import mimetypes
#mimetypes.init()
import logging
import datetime
import os
import json
from twisted.web.server import Site
from twisted.web.resource import Resource, IResource
from twisted.web.static import File
#File.contentTypes = mimetypes.types_map
File.contentTypes.update(
{
'.apng': 'image/png',
})
from twisted.internet import reactor
from twisted.internet.protocol import ClientCreator
from twisted.web.client import getPage
from . import clock
from . import playlist
[docs]class SchedulesPage(Resource):
def __init__(self, schedule):
self.schedule = schedule
[docs] def render_GET(self, request):
if not request.args.get("date"):
date = clock.now().date()
else:
y, m, d = request.args["date"][0].split('-')
date = datetime.date(year=int(y), month=int(m), day=int(d))
l = self.schedule.get_programs_by_date(date, as_dict=True)
d = {"date": "%i-%i-%i" % (date.year, date.month, date.day), "schedule": l}
s = json.dumps(d)
return s
[docs]class StillsListPage(Resource):
def __init__(self, path):
self.path = path
[docs] def render_GET(self, request):
l = os.listdir(self.path)
l = [{"filename":fn} for fn in l]
s = json.dumps(l)
return s.encode("utf-8")
# TODO: There's no security. Use proper websocket-rpc instead of this silly protocol
from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol
[docs]class PlayoutWebsocketProtocol(WebSocketServerProtocol):
def __init__(self, service, playout=None, schedule=None):
super().__init__()
self.service = service
self.playout = playout
self.schedule = schedule
self.random_provider = playout.random_provider
[docs] def onMessage(self, frame, binary):
cmd = frame[:frame.find(b":")]
arg = frame[frame.find(b":")+2:]
logging.info("Command from web: %s" % (repr(frame)))
if cmd == "display-still":
self.playout.show_still("stills/"+arg)
elif cmd == "cancel-still":
self.playout.cancel_still()
elif cmd == "play-mediaid":
argl = arg.split(' ')
media_id = int(argl[0])
offset = float(argl[1])
duration = float(argl[2])
p = playlist.Program()
p.set_program(media_id, program_start=clock.now(), playback_offset=offset, playback_duration=duration, title="%i direct play media" % media_id)
# TODO: Move to service ?
self.playout.cue_program(p)
elif cmd == "resume-playback":
# TODO: Rename to resume schedule?
self.playout.resume_playback()
self.playout.start_schedule()
elif cmd == "resume-current-program":
self.playout.resume_current_program()
elif cmd == "clear-next-program":
self.playout.set_next_program(None)
self.playout.stop_schedule()
elif cmd == "set-next-program-from-schedule":
self.playout.start_schedule()
elif cmd == "reload-schedule":
self.schedule.update_from_pg_cache(days=14)
self.random_provider.reload()
self.service.on_set_schedule(None)
self.playout.start_schedule()
[docs] def onOpen(self):
if not self.service:
return
self.service.add_observer(self) # Will get a lot of info from here
self.sendMessage(("time: %s" % (clock.now().ctime(),)).encode('utf-8'))
[docs] def onClose(self, wasClean, code, reason):
self.service.remove_observer(self)
[docs] def on_playback_started(self, program):
if not program:
program = self.schedule.new_program()
program.set_program(-1, program_start=clock.now(), title="*** Dead Air ***", playback_duration=float("inf"))
self.sendMessage(b"next: %s" % program.json())
logging.warning("playing '*** Dead Air ***' sent to webbrowser")
else:
self.sendMessage(b"playing: %s" % program.json())
[docs] def on_set_schedule(self, schedule):
self.sendMessage(b"schedule-updated: %s" % clock.now().ctime())
[docs] def on_set_next_program(self, program):
if not program:
# TODO: Set next-start, if possible, to duration-progress
program = self.schedule.new_program()
program.set_program(-1, program_start=clock.now(), title="*** Dead Air ***", playback_duration=float("inf"))
self.sendMessage(b"next: %s" % program.json())
logging.warning("next-program '*** Dead Air ***' sent to webbrowser")
else:
self.sendMessage(b"next: %s" % program.json())
[docs] def on_still(self, name):
self.sendMessage(b"still: %s" % name)
from telelib.commonweb import simple_guard_resource
[docs]def start_web(localEPG=None, playout_service=None, playout=None, port=8888, schedule=None):
root = File('web')
if schedule:
root.putChild("schedules", SchedulesPage(schedule))
root.putChild("player_snapshots", File('cache/snapshots'))
root.putChild("stills", StillsListPage("stills"))
wrapper = simple_guard_resource(root)
site = Site(wrapper)
reactor.listenTCP(port, site)
factory = WebSocketServerFactory()
factory.protocol = lambda: PlayoutWebsocketProtocol (playout_service, playout, schedule)
reactor.listenTCP(8889, factory)
"""
import playout_autobahn
from autobahn import AutobahnServerFactory, AutobahnServerProtocol
factory = AutobahnServerFactory()
factory.protocol = lambda: playout_autobahn.AutobahnServerProtocol (playout_service, playout, schedule)
reactor.listenTCP(8899, factory)
"""
if __name__=="__main__":
#localEPG = epgget.LocalEPG()
#localEPG.load_cache()
schedule = playlist.Schedule()
schedule.update_from_pg_cache(days=14)
start_web(schedule=schedule)
reactor.run()