add sync playback

This commit is contained in:
j 2017-05-15 19:03:50 +02:00
parent 2307f5829e
commit 1c0ea9c620
1 changed files with 159 additions and 0 deletions

159
playout/playsync.py Executable file
View File

@ -0,0 +1,159 @@
#!/usr/bin/python3
import argparse
import datetime
import os
import random
import socket
import string
import sys
import time
from glob import glob
from queue import Queue
from socketserver import UDPServer, ThreadingMixIn, BaseRequestHandler
from threading import Thread
import ox
import mpv
import logging
logger = logging.getLogger('cdosea')
DEFAULT_PORT=2680
DEBUG=False
def update_playlist(playlist, prefix='video/'):
playlist = 'play.m3u'
today = datetime.date.today()
seconds_since_midnight = time.time() - time.mktime(today.timetuple())
files = []
videos = {}
for letter in string.ascii_uppercase:
videos[letter] = glob('%s%s*.mp4' % (prefix, letter.lower()))
random.shuffle(videos[letter])
for i in range(10):
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']
files.append(f)
except:
pass
with open(playlist, 'w') as f:
f.write('\n'.join(files))
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
pass
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'
else:
response = b'WAITING'
socket.sendto(response, self.client_address)
self.server.player.queue.put('')
class Player(Thread):
first = True
running = True
playing = False
current = ''
def __init__(self, peer, player, playlist):
self.peer = peer
self.playlist = playlist
self.player = player
self.queue = Queue()
Thread.__init__(self)
self.daemon = True
self.start()
def run(self):
logger.debug("update playlist")
update_playlist(self.playlist)
logger.debug("load playlist")
self.player.loadlist(self.playlist)
self.player.pause = True
while self.running:
logger.debug("play")
self.play()
logger.debug("ping")
self.ping()
logger.debug("wait")
self.queue.get()
def play(self):
self.playing = True
self.player.pause = False
self.player.wait_for_playback()
self.player.pause = True
self.playing = False
def ping(self):
data = 'NEXT'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
logger.debug("ping: %s %s", self.peer, data)
sock.sendto(bytes(data + "\n", "utf-8"), self.peer)
received = str(sock.recv(1024), "utf-8")
if received == 'WAITING' and not self.queue.qsize():
if self.first:
self.queue.put('')
self.first = False
logger.debug("Sent: %s", data)
logger.debug("Received: %s", received)
def my_log(loglevel, component, message):
logger.debug('[{}] {}: {}'.format(loglevel, component, message))
def main():
parser = argparse.ArgumentParser(description='play 2 screens in sync')
parser.add_argument('--peer', help='ip[:port] of peer', required=True)
parser.add_argument('--port', type=int, help='local port', default=DEFAULT_PORT)
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)
args = parser.parse_args()
if ':' in args.peer:
peer = args.peer.split(':')
peer = (peer[0], int(peer[1]))
else:
peer = (args.peer, DEFAULT_PORT)
DEBUG = args.debug
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)
player = mpv.MPV(log_handler=my_log, input_default_bindings=True, input_vo_keyboard=True)
player.fullscreen = not args.window
player.loop = 'inf'
server = ThreadingUDPServer(('0.0.0.0', args.port), Handler)
server.player = Player(peer, player, args.playlist)
logger.debug("listen on %s...", args.port)
try:
server.serve_forever()
except KeyboardInterrupt:
pass
del player
if __name__ == "__main__":
main()