openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #20684
[Merge] lp:~trb143/openlp/cherrypy into lp:openlp
Tim Bentley has proposed merging lp:~trb143/openlp/cherrypy into lp:openlp.
Requested reviews:
Andreas Preikschat (googol)
Related bugs:
Bug #826724 in OpenLP: "Make the Web Remote password protected"
https://bugs.launchpad.net/openlp/+bug/826724
Bug #826731 in OpenLP: "Add optional SSL to web remote"
https://bugs.launchpad.net/openlp/+bug/826731
For more details, see:
https://code.launchpad.net/~trb143/openlp/cherrypy/+merge/167113
Add a /live option to the remote interface to all images of the live to be displayed.
This is a no secure option like stage.
--
https://code.launchpad.net/~trb143/openlp/cherrypy/+merge/167113
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2013-04-23 21:46:07 +0000
+++ openlp/core/ui/slidecontroller.py 2013-06-03 18:05:33 +0000
@@ -121,6 +121,8 @@
self.update_slide_limits()
self.panel = QtGui.QWidget(parent.controlSplitter)
self.slideList = {}
+ self.slide_count = 0
+ self.slide_image = None
# Layout for holding panel
self.panel_layout = QtGui.QVBoxLayout(self.panel)
self.panel_layout.setSpacing(0)
@@ -1050,27 +1052,28 @@
def updatePreview(self):
"""
- This updates the preview frame, for example after changing a slide or
- using *Blank to Theme*.
+ This updates the preview frame, for example after changing a slide or using *Blank to Theme*.
"""
log.debug(u'updatePreview %s ' % self.screens.current[u'primary'])
if not self.screens.current[u'primary'] and self.service_item and \
self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
- # Grab now, but try again in a couple of seconds if slide change
- # is slow
- QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
- QtCore.QTimer.singleShot(2.5, self.grabMainDisplay)
+ # Grab now, but try again in a couple of seconds if slide change is slow
+ QtCore.QTimer.singleShot(0.5, self.grab_maindisplay)
+ QtCore.QTimer.singleShot(2.5, self.grab_maindisplay)
else:
- self.slidePreview.setPixmap(self.display.preview())
+ self.slide_image = self.display.preview()
+ self.slidePreview.setPixmap(self.slide_image)
+ self.slide_count += 1
- def grabMainDisplay(self):
+ def grab_maindisplay(self):
"""
Creates an image of the current screen and updates the preview frame.
"""
- winid = QtGui.QApplication.desktop().winId()
+ win_id = QtGui.QApplication.desktop().winId()
rect = self.screens.current[u'size']
- winimg = QtGui.QPixmap.grabWindow(winid, rect.x(), rect.y(), rect.width(), rect.height())
- self.slidePreview.setPixmap(winimg)
+ win_image = QtGui.QPixmap.grabWindow(win_id, rect.x(), rect.y(), rect.width(), rect.height())
+ self.slidePreview.setPixmap(win_image)
+ self.slide_image = win_image
def on_slide_selected_next_action(self, checked):
"""
=== added file 'openlp/plugins/remotes/html/live.css'
--- openlp/plugins/remotes/html/live.css 1970-01-01 00:00:00 +0000
+++ openlp/plugins/remotes/html/live.css 2013-06-03 18:05:33 +0000
@@ -0,0 +1,39 @@
+/******************************************************************************
+* OpenLP - Open Source Lyrics Projection *
+* --------------------------------------------------------------------------- *
+* Copyright (c) 2008-2013 Raoul Snyman *
+* Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan *
+* Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, *
+* Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. *
+* Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, *
+* Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
+* Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, *
+* Frode Woldsund, Martin Zibricky *
+* --------------------------------------------------------------------------- *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation; version 2 of the License. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program; if not, write to the Free Software Foundation, Inc., 59 *
+* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+******************************************************************************/
+body {
+ background-color: black;
+ font-family: sans-serif;
+ overflow: hidden;
+}
+
+.size {
+ position: absolute;
+ top: 0px;
+ vertical-align: middle;
+ height: 100%;
+ background-size: cover;
+ background-repeat: no-repeat;
+}
\ No newline at end of file
=== added file 'openlp/plugins/remotes/html/live.html'
--- openlp/plugins/remotes/html/live.html 1970-01-01 00:00:00 +0000
+++ openlp/plugins/remotes/html/live.html 2013-06-03 18:05:33 +0000
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<!--
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+-->
+<head>
+ <meta charset="utf-8" />
+ <title>${live_title}</title>
+ <link rel="stylesheet" href="/files/live.css" />
+ <link rel="shortcut icon" type="image/x-icon" href="/files/images/favicon.ico">
+ <script type="text/javascript" src="/files/jquery.js"></script>
+ <script type="text/javascript" src="/files/live.js"></script>
+</head>
+<body>
+<img id="image" class="size"/>
+</body>
+</html>
\ No newline at end of file
=== added file 'openlp/plugins/remotes/html/live.js'
--- openlp/plugins/remotes/html/live.js 1970-01-01 00:00:00 +0000
+++ openlp/plugins/remotes/html/live.js 2013-06-03 18:05:33 +0000
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * OpenLP - Open Source Lyrics Projection *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2013 Raoul Snyman *
+ * Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan *
+ * Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, *
+ * Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. *
+ * Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, *
+ * Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
+ * Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, *
+ * Frode Woldsund, Martin Zibricky *
+ * --------------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published by the Free *
+ * Software Foundation; version 2 of the License. *
+ * *
+ * This program is distributed in the hope that it will be useful, but WITHOUT *
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+ * more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., 59 *
+ * Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+ ******************************************************************************/
+window.OpenLP = {
+ loadSlide: function (event) {
+ $.getJSON(
+ "/live/image",
+ function (data, status) {
+ var img = document.getElementById('image');
+ img.src = data.results.slide_image;
+ img.style.display = 'block';
+ }
+ );
+ },
+ pollServer: function () {
+ $.getJSON(
+ "/live/poll",
+ function (data, status) {
+ if (OpenLP.slideCount != data.results.slide_count) {
+ OpenLP.slideCount = data.results.slide_count;
+ OpenLP.loadSlide();
+ }
+ }
+ );
+ }
+}
+$.ajaxSetup({ cache: false });
+setInterval("OpenLP.pollServer();", 500);
+OpenLP.pollServer();
+
=== modified file 'openlp/plugins/remotes/lib/httpserver.py'
--- openlp/plugins/remotes/lib/httpserver.py 2013-04-23 20:31:19 +0000
+++ openlp/plugins/remotes/lib/httpserver.py 2013-06-03 18:05:33 +0000
@@ -124,7 +124,7 @@
from mako.template import Template
from PyQt4 import QtCore
-from openlp.core.lib import Registry, Settings, PluginStatus, StringContent
+from openlp.core.lib import Registry, Settings, PluginStatus, StringContent, image_to_byte
from openlp.core.utils import AppLocation, translate
from cherrypy._cpcompat import sha, ntob
@@ -136,6 +136,7 @@
"""
Create an encrypted password for the given password.
"""
+ log.debug("make_sha_hash")
return sha(ntob(password)).hexdigest()
@@ -143,6 +144,7 @@
"""
Fetch the password for a provided user.
"""
+ log.debug("Fetch Password")
if username != Settings().value(u'remotes/user id'):
return None
return make_sha_hash(Settings().value(u'remotes/password'))
@@ -175,9 +177,11 @@
self.root = self.Public()
self.root.files = self.Files()
self.root.stage = self.Stage()
+ self.root.live = self.Live()
self.root.router = self.router
self.root.files.router = self.router
self.root.stage.router = self.router
+ self.root.live.router = self.router
cherrypy.tree.mount(self.root, '/', config=self.define_config())
# Turn off the flood of access messages cause by poll
cherrypy.log.access_log.propagate = False
@@ -213,6 +217,9 @@
u'tools.basic_auth.on': False},
u'/stage': {u'tools.staticdir.on': True,
u'tools.staticdir.dir': self.router.html_dir,
+ u'tools.basic_auth.on': False},
+ u'/live': {u'tools.staticdir.on': True,
+ u'tools.staticdir.dir': self.router.html_dir,
u'tools.basic_auth.on': False}}
return directory_config
@@ -239,7 +246,16 @@
class Stage(object):
"""
- Stageview is read only so security is not relevant and would reduce it's usability
+ Stage view is read only so security is not relevant and would reduce it's usability
+ """
+ @cherrypy.expose
+ def default(self, *args, **kwargs):
+ url = urlparse.urlparse(cherrypy.url())
+ return self.router.process_http_request(url.path, *args)
+
+ class Live(object):
+ """
+ Live view is read only so security is not relevant and would reduce it's usability
"""
@cherrypy.expose
def default(self, *args, **kwargs):
@@ -265,9 +281,12 @@
self.routes = [
(u'^/$', self.serve_file),
(u'^/(stage)$', self.serve_file),
+ (u'^/(live)$', self.serve_file),
(r'^/files/(.*)$', self.serve_file),
(r'^/api/poll$', self.poll),
(r'^/stage/poll$', self.poll),
+ (r'^/live/poll$', self.live_poll),
+ (r'^/live/image$', self.live_image),
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
(r'^/stage/controller/(live|preview)/(.*)$', self.controller),
(r'^/api/service/(.*)$', self.service),
@@ -305,6 +324,7 @@
if response:
return response
else:
+ log.debug('Path not found %s', url_path)
return self._http_not_found()
def _get_service_items(self):
@@ -334,6 +354,7 @@
self.template_vars = {
'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Remote'),
'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Stage View'),
+ 'live_title': translate('RemotePlugin.Mobile', 'OpenLP 2.1 Live View'),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
@@ -359,18 +380,19 @@
def serve_file(self, filename=None):
"""
- Send a file to the socket. For now, just a subset of file types
- and must be top level inside the html folder.
+ Send a file to the socket. For now, just a subset of file types and must be top level inside the html folder.
If subfolders requested return 404, easier for security for the present.
- Ultimately for i18n, this could first look for xx/file.html before
- falling back to file.html... where xx is the language, e.g. 'en'
+ Ultimately for i18n, this could first look for xx/file.html before falling back to file.html.
+ where xx is the language, e.g. 'en'
"""
log.debug(u'serve file request %s' % filename)
if not filename:
filename = u'index.html'
elif filename == u'stage':
filename = u'stage.html'
+ elif filename == u'live':
+ filename = u'live.html'
path = os.path.normpath(os.path.join(self.html_dir, filename))
if not path.startswith(self.html_dir):
return self._http_not_found()
@@ -425,6 +447,26 @@
cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': result})
+ def live_poll(self):
+ """
+ Poll OpenLP to determine the current slide count.
+ """
+ result = {
+ u'slide_count': self.live_controller.slide_count
+ }
+ cherrypy.response.headers['Content-Type'] = u'application/json'
+ return json.dumps({u'results': result})
+
+ def live_image(self):
+ """
+ Return the latest display image as a byte stream.
+ """
+ result = {
+ u'slide_image': u'data:image/png;base64,' + str(image_to_byte(self.live_controller.slide_image))
+ }
+ cherrypy.response.headers['Content-Type'] = u'application/json'
+ return json.dumps({u'results': result})
+
def display(self, action):
"""
Hide or show the display screen.