add sync/lights

This commit is contained in:
j 2017-08-29 19:27:06 +02:00
parent e68500be28
commit 4c3a6a8c2d
3 changed files with 243 additions and 2 deletions

View file

@ -2,7 +2,6 @@
if [ "x$1" == "xupdate" ]; then
shift
exec python3 -m cdoseaplay.update $@
else
shift
gsettings set org.gnome.desktop.screensaver ubuntu-lock-on-suspend false
@ -14,5 +13,9 @@ else
gsettings set org.gnome.desktop.background primary-color '#888888'
gsettings set org.gnome.desktop.background secondary-color '#888888'
gsettings set org.gnome.desktop.background picture-options 'none'
if [ "x$1" == "xsync" ]; then
exec python3 -m cdoseaplay.sync $@
else
exec python3 -m cdoseaplay.play $@
fi
fi

26
cdoseaplay/lights.py Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/python3
import subprocess
import sys
import os
import time
import ox
from pi import random
path = sys.argv[1]
n = int(os.path.getctime(path) - 1495280000)
duration = ox.avinfo(path)['duration']
seq = random(n * 1000)
pos = 0
lights = []
while pos < duration - 15:
sleep = seq() + 15
light = seq() + 1
if pos + sleep > duration:
break
time.sleep(sleep)
cmd = ['/opt/LanBox-JSONRPC/fade.py', str(light)]
subprocess.Popen(cmd)
pos += sleep

212
cdoseaplay/sync.py Executable file
View file

@ -0,0 +1,212 @@
#!/usr/bin/python3
import argparse
import datetime
import os
import random
import socket
import string
import subprocess
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/', position=None):
playlist = os.path.expanduser('~/Videos/cdosea.m3u')
prefix = os.path.expanduser('~/Videos/CDOSEA')
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])
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)
pos -= 1
with open(playlist, 'w') as f:
f.write('\n'.join(files))
f.write('\n')
return position, len(files)
def trigger_lights(path):
cmd = ['python3', '-m', 'cdoseaplay.lights', 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()
logger.debug("%s said: %s", self.client_address[0], data)
queue = False
if data == b'POS':
response = ('%d' % self.server.player.position).encode()
else:
if self.server.player.playing:
response = b'PLAYING'
else:
response = b'WAITING'
queue = True
socket = self.request[1]
socket.sendto(response, self.client_address)
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, lights=False):
self.peer = peer
self.playlist = playlist
self.player = player
self.lights = lights
self.queue = Queue()
Thread.__init__(self)
self.daemon = True
self.start()
def run(self):
logger.debug("update 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")
self.queue.get()
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
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 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))
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)
parser.add_argument('--lights', action='store_true', help='lights', 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)
if args.lights:
time.sleep(5)
# 42 max
player = mpv.MPV(
log_handler=my_log, input_default_bindings=True,
input_vo_keyboard=True, sub_text_font_size=28, sub_text_font='Menlo'
)
player.fullscreen = not args.window
player.loop = 'inf'
server = ThreadingUDPServer(('0.0.0.0', args.port), Handler)
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:
server.serve_forever()
except KeyboardInterrupt:
pass
del player
if __name__ == "__main__":
main()