From 3f20dbd968d98cadf771cdb28ed53ead8a0bb3b2 Mon Sep 17 00:00:00 2001 From: j Date: Sat, 20 May 2017 18:30:31 +0200 Subject: [PATCH] playsync --- playout/playsync.py | 105 +++++++++++++++++++++++++++++++++----------- playout/update.py | 18 +++++++- 2 files changed, 95 insertions(+), 28 deletions(-) diff --git a/playout/playsync.py b/playout/playsync.py index 12448ed..9a2fc29 100755 --- a/playout/playsync.py +++ b/playout/playsync.py @@ -5,6 +5,7 @@ import os import random import socket import string +import subprocess import sys import time from glob import glob @@ -18,15 +19,12 @@ import mpv import logging logger = logging.getLogger('cdosea') -DEFAULT_PORT=2680 -DEBUG=False +DEFAULT_PORT = 2680 +DEBUG = False -def update_playlist(playlist, prefix='video/'): +def update_playlist(playlist, prefix='video/', position=None): playlist = 'play.m3u' - today = datetime.date.today() - seconds_since_midnight = time.time() - time.mktime(today.timetuple()) - files = [] videos = {} for letter in string.ascii_uppercase: @@ -37,45 +35,76 @@ def update_playlist(playlist, prefix='video/'): for letter in string.ascii_uppercase: files.append(videos[letter][i]) - position = 0 - while position < seconds_since_midnight: - f = files.pop(0) - try: - position += ox.avinfo(f)['duration'] + if position is None: + today = datetime.date.today() + seconds_since_midnight = time.time() - time.mktime(today.timetuple()) + offset = 0 + position = 0 + + while offset < seconds_since_midnight: + f = files.pop(0) + try: + offset += ox.avinfo(f)['duration'] + files.append(f) + except: + pass + position += 1 + else: + pos = position + while pos: + f = files.pop(0) files.append(f) - except: - pass + pos -= 1 with open(playlist, 'w') as f: f.write('\n'.join(files)) + f.write('\n') + return position, len(files) + +def trigger_lights(path): + #number = int(path.split('/')[-1].split('.')[0][1:]) + #cmd = ['/opt/LanBox-JSONRPC/fade.py', str(number)] + cmd = ['./lights.py', path] + subprocess.Popen(cmd) class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass + def q_binding(self, *args): + self.player.running = False + self.shutdown() + class Handler(BaseRequestHandler): def handle(self): data = self.request[0].strip() - socket = self.request[1] - logger.debug("%s wrote: %s", self.client_address[0], data) - if self.server.player.playing: - response = b'PLAYING' + logger.debug("%s said: %s", self.client_address[0], data) + queue = False + if data == b'POS': + response = ('%d' % self.server.player.position).encode() else: - response = b'WAITING' + if self.server.player.playing: + response = b'PLAYING' + else: + response = b'WAITING' + queue = True + socket = self.request[1] socket.sendto(response, self.client_address) - self.server.player.queue.put('') - + if queue: + self.server.player.queue.put('') class Player(Thread): first = True running = True playing = False current = '' + playlist_items = 260 - def __init__(self, peer, player, playlist): + def __init__(self, peer, player, playlist, lights=False): self.peer = peer self.playlist = playlist self.player = player + self.lights = lights self.queue = Queue() Thread.__init__(self) self.daemon = True @@ -83,13 +112,14 @@ class Player(Thread): def run(self): logger.debug("update playlist") - update_playlist(self.playlist) + self.position, self.playlist_items = update_playlist(self.playlist, position=self.get_position()) logger.debug("load playlist") self.player.loadlist(self.playlist) self.player.pause = True while self.running: logger.debug("play") self.play() + self.position = (self.position + 1) % self.playlist_items logger.debug("ping") self.ping() logger.debug("wait") @@ -98,6 +128,8 @@ class Player(Thread): def play(self): self.playing = True self.player.pause = False + if self.lights: + trigger_lights(self.player.path.decode()) self.player.wait_for_playback() self.player.pause = True self.playing = False @@ -115,6 +147,19 @@ class Player(Thread): logger.debug("Sent: %s", data) logger.debug("Received: %s", received) + def get_position(self): + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.settimeout(1) + data = 'POS' + sock.sendto(bytes(data + "\n", "utf-8"), self.peer) + received = str(sock.recv(1024), "utf-8") + pos = int(received) + except socket.timeout: + logger.debug('no response', exc_info=1) + pos = None + return pos + def my_log(loglevel, component, message): logger.debug('[{}] {}: {}'.format(loglevel, component, message)) @@ -126,6 +171,7 @@ def main(): parser.add_argument('--playlist', help='play.m3u', default='play.m3u') parser.add_argument('--window', action='store_true', help='run in window', default=False) parser.add_argument('--debug', action='store_true', help='debug', default=False) + parser.add_argument('--lights', action='store_true', help='lights', default=False) args = parser.parse_args() if ':' in args.peer: @@ -138,14 +184,21 @@ def main(): if DEBUG: log_format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s' logging.basicConfig(level=logging.DEBUG, format=log_format) - base = os.path.dirname(os.path.abspath(__file__)) - os.chdir(base) + base = os.path.dirname(os.path.abspath(__file__)) + os.chdir(base) + if args.lights: + time.sleep(5) - player = mpv.MPV(log_handler=my_log, input_default_bindings=True, input_vo_keyboard=True) + player = mpv.MPV( + log_handler=my_log, input_default_bindings=True, + input_vo_keyboard=True, sub_text_font_size=28 + ) player.fullscreen = not args.window player.loop = 'inf' + server = ThreadingUDPServer(('0.0.0.0', args.port), Handler) - server.player = Player(peer, player, args.playlist) + server.player = Player(peer, player, args.playlist, args.lights) + player.register_key_binding('q', server.q_binding) logger.debug("listen on %s...", args.port) try: diff --git a/playout/update.py b/playout/update.py index 499ac62..7e8635e 100755 --- a/playout/update.py +++ b/playout/update.py @@ -11,11 +11,20 @@ import ox socket.setdefaulttimeout(10) -base = 'https://cdosea.0x2620.org/static/render' +base = 'https://cdosea.0x2620.org/static/render/' lock = '/tmp/update.lock' folder = os.path.abspath(os.path.dirname(__file__)) os.chdir(folder) +def get_subtitle(url, name): + try: + r = requests.get(url, stream=True) + with open('%s.tmp' % name, 'wb') as fd: + shutil.copyfileobj(r.raw, fd) + shutil.move('%s.tmp' % name, name) + except: + pass + if os.path.exists(lock): sys.exit(0) with open(lock, 'w') as f: @@ -24,7 +33,7 @@ with open(lock, 'w') as f: for i in range(10): for letter in string.ascii_lowercase: name = '%s%02d.1080p.mp4' % (letter, i) - url = '%s/%s' % (base, name) + url = '%s%s' % (base, name) name = 'video/' + name folder = os.path.dirname(name) if not os.path.exists(folder): @@ -36,6 +45,7 @@ for i in range(10): else: get = True if get: + print(url) try: r = requests.get(url, stream=True) with open('%s.tmp' % name, 'wb') as fd: @@ -45,6 +55,10 @@ for i in range(10): mtime = time.mktime(datetime.datetime.strptime(r.headers.get("Last-Modified"), "%a, %d %b %Y %X GMT").timetuple()) os.utime(name, (mtime, mtime)) ox.avinfo(name)['duration'] + get_subtitle(url.replace('.mp4', '.srt'), name.replace('.mp4', '.srt')) + except KeyboardInterrupt: + os.unlink(lock) + sys.exit(-1) except: print(url, 'failed') os.unlink(lock)