← Back to team overview

openlp-core team mailing list archive

[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.