Stage works!

This commit is contained in:
Tim Bentley 2016-06-11 17:28:50 +01:00
parent 6a955a5573
commit 4a30e71a79
6 changed files with 304 additions and 106 deletions

View File

@ -39,13 +39,13 @@ def _route_from_url(url_prefix, url):
return url return url
def register_endpoint(endpoint): def register_endpoint(end_point):
""" """
Register an endpoint with the app Register an endpoint with the app
""" """
print("ep", endpoint) print("ep", end_point)
for url, view_func, method, secure in endpoint.routes: for url, view_func, method, secure in end_point.routes:
route = _route_from_url(endpoint.url_prefix, url) route = _route_from_url(end_point.url_prefix, url)
application.add_route(route, view_func, method, secure) application.add_route(route, view_func, method, secure)
from .endpoint import Endpoint from .endpoint import Endpoint

View File

@ -23,7 +23,10 @@ import logging
from openlp.core.api import OpenWSServer, OpenLPPoll, OpenLPHttpServer from openlp.core.api import OpenWSServer, OpenLPPoll, OpenLPHttpServer
from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties
from openlp.core.api.uiinterfaces import stage_endpoint
# These are here to load the endpoints
from openlp.core.api.coreendpoints import stage_endpoint
from openlp.core.api.controllerendpoints import controller_endpoint
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
import logging
import os
import urllib.request
import urllib.error
from openlp.core.api import Endpoint, register_endpoint
from openlp.core.common import Registry, AppLocation, Settings
from openlp.core.lib import ItemCapabilities, create_thumb
log = logging.getLogger(__name__)
controller_endpoint = Endpoint('api')
@controller_endpoint.route('controller/live/text')
def controller_text(request):
"""
Perform an action on the slide controller.
:param request: the http request - not used
"""
log.debug("controller_text ")
live_controller = Registry().get('live_controller')
current_item = live_controller.service_item
data = []
if current_item:
for index, frame in enumerate(current_item.get_frames()):
item = {}
# Handle text (songs, custom, bibles)
if current_item.is_text():
if frame['verseTag']:
item['tag'] = str(frame['verseTag'])
else:
item['tag'] = str(index + 1)
item['text'] = str(frame['text'])
item['html'] = str(frame['html'])
# Handle images, unless a custom thumbnail is given or if thumbnails is disabled
elif current_item.is_image() and not frame.get('image', '') and Settings().value('remotes/thumbnails'):
item['tag'] = str(index + 1)
thumbnail_path = os.path.join('images', 'thumbnails', frame['title'])
full_thumbnail_path = os.path.join(AppLocation.get_data_path(), thumbnail_path)
# Create thumbnail if it doesn't exists
if not os.path.exists(full_thumbnail_path):
create_thumb(current_item.get_frame_path(index), full_thumbnail_path, False)
item['img'] = urllib.request.pathname2url(os.path.sep + thumbnail_path)
item['text'] = str(frame['title'])
item['html'] = str(frame['title'])
else:
# Handle presentation etc.
item['tag'] = str(index + 1)
if current_item.is_capable(ItemCapabilities.HasDisplayTitle):
item['title'] = str(frame['display_title'])
if current_item.is_capable(ItemCapabilities.HasNotes):
item['slide_notes'] = str(frame['notes'])
if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
Settings().value('remotes/thumbnails'):
# If the file is under our app directory tree send the portion after the match
data_path = AppLocation.get_data_path()
if frame['image'][0:len(data_path)] == data_path:
item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
item['text'] = str(frame['title'])
item['html'] = str(frame['title'])
item['selected'] = (live_controller.selected_row == index)
data.append(item)
json_data = {'results': {'slides': data}}
if current_item:
json_data['results']['item'] = live_controller.service_item.unique_identifier
return json_data
@controller_endpoint.route('service/list')
def service_list(request):
"""
Handles requests for service items in the service manager
"""
return {'results': {'items': get_service_items()}}
def get_service_items():
"""
Read the service item in use and return the data as a json object
"""
live_controller = Registry().get('live_controller')
service_items = []
if live_controller.service_item:
current_unique_identifier = live_controller.service_item.unique_identifier
else:
current_unique_identifier = None
for item in Registry().get('service_manager').service_items:
service_item = item['service_item']
service_items.append({
'id': str(service_item.unique_identifier),
'title': str(service_item.get_display_title()),
'plugin': str(service_item.name),
'notes': str(service_item.notes),
'selected': (service_item.unique_identifier == current_unique_identifier)
})
return service_items
register_endpoint(controller_endpoint)

View File

@ -0,0 +1,166 @@
import logging
import os
from openlp.core.api import Endpoint, register_endpoint
from openlp.core.common import AppLocation, UiStrings, translate
from mako.template import Template
log = logging.getLogger(__name__)
stage_endpoint = Endpoint('')
FILE_TYPES = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.jpg': 'image/jpeg',
'.gif': 'image/gif',
'.ico': 'image/x-icon',
'.png': 'image/png'
}
remote = translate('RemotePlugin.Mobile', 'Remote')
stage = translate('RemotePlugin.Mobile', 'Stage View')
live = translate('RemotePlugin.Mobile', 'Live View')
template_vars = {
'app_title': "{main} {remote}".format(main=UiStrings().OLPV2x, remote=remote),
'stage_title': "{main} {stage}".format(main=UiStrings().OLPV2x, stage=stage),
'live_title': "{main} {live}".format(main=UiStrings().OLPV2x, live=live),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
'search': translate('RemotePlugin.Mobile', 'Search'),
'home': translate('RemotePlugin.Mobile', 'Home'),
'refresh': translate('RemotePlugin.Mobile', 'Refresh'),
'blank': translate('RemotePlugin.Mobile', 'Blank'),
'theme': translate('RemotePlugin.Mobile', 'Theme'),
'desktop': translate('RemotePlugin.Mobile', 'Desktop'),
'show': translate('RemotePlugin.Mobile', 'Show'),
'prev': translate('RemotePlugin.Mobile', 'Prev'),
'next': translate('RemotePlugin.Mobile', 'Next'),
'text': translate('RemotePlugin.Mobile', 'Text'),
'show_alert': translate('RemotePlugin.Mobile', 'Show Alert'),
'go_live': translate('RemotePlugin.Mobile', 'Go Live'),
'add_to_service': translate('RemotePlugin.Mobile', 'Add to Service'),
'add_and_go_to_service': translate('RemotePlugin.Mobile', 'Add & Go to Service'),
'no_results': translate('RemotePlugin.Mobile', 'No Results'),
'options': translate('RemotePlugin.Mobile', 'Options'),
'service': translate('RemotePlugin.Mobile', 'Service'),
'slides': translate('RemotePlugin.Mobile', 'Slides'),
'settings': translate('RemotePlugin.Mobile', 'Settings'),
}
@stage_endpoint.route('$')
@stage_endpoint.route('(stage)$')
@stage_endpoint.route('(main)$')
@stage_endpoint.route('(css)')
@stage_endpoint.route('(js)')
@stage_endpoint.route('(assets)')
def file_access(request):
"""
Get a list of songs`
"""
file_name = request.path
html_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'api', 'html')
log.debug('serve file request {name}'.format(name=file_name))
if file_name.startswith('/'):
file_name = file_name[1:]
if not file_name:
file_name = 'index.html'
if '.' not in file_name:
file_name += '.html'
if file_name.startswith('/'):
file_name = file_name[1:]
path = os.path.normpath(os.path.join(html_dir, file_name))
return _process_file(path)
@stage_endpoint.route('(stage)/(.*)$')
def bespoke_file_access(request):
"""
Allow Stage view to be delivered with custom views.
:param request: base path of the URL. Not used but passed by caller
:return:
"""
file_name = request.path
config_dir = os.path.join(AppLocation.get_data_path(), 'stages')
log.debug('serve file request {name}'.format(name=file_name))
parts = file_name.split('/')
if len(parts) == 1:
file_name = os.path.join(parts[0], 'stage.html')
elif len(parts) == 3:
file_name = os.path.join(parts[1], parts[2])
path = os.path.normpath(os.path.join(config_dir, file_name))
return _process_file(path)
@stage_endpoint.route('main/image$')
def main_image(request):
"""
Return the latest display image as a byte stream.
:param request: base path of the URL. Not used but passed by caller
:return:
"""
# result = {
# 'slide_image': 'data:image/png;base64,' + str(image_to_byte(self.live_controller.slide_image))
# }
# self.do_json_header()
# return json.dumps({'results': result}).encode()
pass
@stage_endpoint.route(r'^/(\w+)/thumbnails([^/]+)?/(.*)$')
def main_image(request):
"""
Get a list of songs
:param request: base path of the URL. Not used but passed by caller
:return:
"""
# songs = db.query(Song).get()
# return {'songs': [dictify(song) for song in songs]}
print("AAA")
def _process_file(path):
"""
Common file processing code
:param path: path to file to be loaded
:return: web resource to be loaded
"""
ext, content_type = get_content_type(path)
file_handle = None
try:
if ext == '.html':
variables = template_vars
content = Template(filename=path, input_encoding='utf-8').render(**variables)
else:
file_handle = open(path, 'rb')
log.debug('Opened {path}'.format(path=path))
content = file_handle.read().decode("utf-8")
except IOError:
log.exception('Failed to open {path}'.format(path=path))
return None
finally:
if file_handle:
file_handle.close()
return content
def get_content_type(file_name):
"""
Examines the extension of the file and determines what the content_type should be, defaults to text/plain
Returns the extension and the content_type
:param file_name: name of file
"""
ext = os.path.splitext(file_name)[1]
content_type = FILE_TYPES.get(ext, 'text/plain')
return ext, content_type
register_endpoint(stage_endpoint)

View File

@ -37,6 +37,7 @@ def _make_response(view_result):
""" """
Create a Response object from response Create a Response object from response
""" """
print(view_result)
if isinstance(view_result, Response): if isinstance(view_result, Response):
return view_result return view_result
elif isinstance(view_result, tuple): elif isinstance(view_result, tuple):
@ -54,8 +55,12 @@ def _make_response(view_result):
return Response(body=json.dumps(view_result), status=200, return Response(body=json.dumps(view_result), status=200,
content_type='application/json', charset='utf8') content_type='application/json', charset='utf8')
elif isinstance(view_result, str): elif isinstance(view_result, str):
return Response(body=view_result, status=200, if 'body {' in view_result:
content_type='text/html', charset='utf8') return Response(body=view_result, status=200,
content_type='text/css', charset='utf8')
else:
return Response(body=view_result, status=200,
content_type='text/html', charset='utf8')
def _handle_exception(error): def _handle_exception(error):
@ -92,14 +97,13 @@ class WSGIApplication(object):
""" """
Find the appropriate URL and run the view function Find the appropriate URL and run the view function
""" """
print(request.path)
print(self.route_map.items())
for route, views in self.route_map.items(): for route, views in self.route_map.items():
if re.match(route, request.path): if re.match(route, request.path):
if request.method.upper() in views: if request.method.upper() in views:
log.debug('Found {method} {url}'.format(method=request.method, url=request.path)) log.debug('Found {method} {url}'.format(method=request.method, url=request.path))
view_func = views[request.method.upper()]['function'] view_func = views[request.method.upper()]['function']
return _make_response(view_func(request)) return _make_response(view_func(request))
log.error('Not Found url {url} '.format(url=request.path))
raise NotFound() raise NotFound()
def wsgi_app(self, environ, start_response): def wsgi_app(self, environ, start_response):

View File

@ -1,97 +0,0 @@
import logging
import os
from openlp.core.api import Endpoint, register_endpoint
log = logging.getLogger(__name__)
stage_endpoint = Endpoint('')
@stage_endpoint.route('$')
@stage_endpoint.route('(stage)$')
@stage_endpoint.route('(main)$')
def file_access(request):
"""
Get a list of songs`
"""
#songs = db.query(Song).get()
#return {'songs': [dictify(song) for song in songs]}
print("AAA")
@stage_endpoint.route('(stage)/(.*)$')
def bespoke_file_access(request):
"""
Allow Stage view to be delivered with custom views.
:param url_path: base path of the URL. Not used but passed by caller
:param file_name: file name with path
:return:
"""
pass
# log.debug('serve file request {name}'.format(name=file_name))
# parts = file_name.split('/')
# if len(parts) == 1:
# file_name = os.path.join(parts[0], 'stage.html')
# elif len(parts) == 3:
# file_name = os.path.join(parts[1], parts[2])
# path = os.path.normpath(os.path.join(self.config_dir, file_name))
# if not path.startswith(self.config_dir):
# return self.do_not_found()
# return _process_file(path)
@stage_endpoint.route('main/image$')
def main_image(request):
"""
Return the latest display image as a byte stream.
"""
# result = {
# 'slide_image': 'data:image/png;base64,' + str(image_to_byte(self.live_controller.slide_image))
# }
# self.do_json_header()
# return json.dumps({'results': result}).encode()
pass
@stage_endpoint.route(r'^/(\w+)/thumbnails([^/]+)?/(.*)$')
def main_image(request):
"""
Get a list of songs
"""
# songs = db.query(Song).get()
# return {'songs': [dictify(song) for song in songs]}
print("AAA")
def _process_file(self, path):
"""
Common file processing code
:param path: path to file to be loaded
:return: web resource to be loaded
"""
# content = None
# ext, content_type = self.get_content_type(path)
# file_handle = None
# try:
# if ext == '.html':
# variables = self.template_vars
# content = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables)
# else:
# file_handle = open(path, 'rb')
# log.debug('Opened {path}'.format(path=path))
# content = file_handle.read()
# except IOError:
# log.exception('Failed to open {path}'.format(path=path))
# return self.do_not_found()
# finally:
# if file_handle:
# file_handle.close()
# self.send_response(200)
# self.send_header('Content-type', content_type)
# self.end_headers()
# return content
pass
register_endpoint(stage_endpoint)