2017-08-29 17:27:06 +00:00
|
|
|
#!/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
|
|
|
|
|
2023-10-12 10:38:34 +00:00
|
|
|
from .utils import update_playlist, get_player, trigger_lights, get_path
|
|
|
|
from . import config
|
2017-08-29 17:27:06 +00:00
|
|
|
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger('cdosea')
|
|
|
|
|
|
|
|
DEFAULT_PORT = 2680
|
|
|
|
DEBUG = False
|
|
|
|
|
|
|
|
|
|
|
|
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]
|
2023-10-12 11:44:26 +00:00
|
|
|
logger.debug("respond to %s: %s", self.client_address[0], response)
|
2017-08-29 17:27:06 +00:00
|
|
|
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
|
|
|
|
|
2023-10-12 10:38:34 +00:00
|
|
|
def __init__(self, peer, player, playlist, prefix):
|
2017-08-29 17:27:06 +00:00
|
|
|
self.peer = peer
|
|
|
|
self.playlist = playlist
|
2017-08-30 14:07:50 +00:00
|
|
|
self.prefix = prefix
|
2017-08-29 17:27:06 +00:00
|
|
|
self.player = player
|
|
|
|
self.queue = Queue()
|
|
|
|
Thread.__init__(self)
|
|
|
|
self.daemon = True
|
|
|
|
self.start()
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
logger.debug("update playlist")
|
2017-08-30 14:07:50 +00:00
|
|
|
self.position, self.playlist_items = update_playlist(self.playlist, self.prefix, position=self.get_position())
|
2017-08-29 17:27:06 +00:00
|
|
|
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
|
2023-10-12 10:38:34 +00:00
|
|
|
if config.lights and self.player.path:
|
|
|
|
trigger_lights(get_path(self.player.path))
|
2017-08-29 17:27:06 +00:00
|
|
|
self.player.wait_for_playback()
|
|
|
|
self.player.pause = True
|
|
|
|
self.playing = False
|
|
|
|
|
|
|
|
def ping(self):
|
|
|
|
data = 'NEXT'
|
2023-10-12 11:29:02 +00:00
|
|
|
if ':' in self.peer[0]:
|
2023-10-12 11:24:32 +00:00
|
|
|
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
|
|
|
else:
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
2017-08-29 17:27:06 +00:00
|
|
|
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:
|
2023-10-12 11:29:02 +00:00
|
|
|
if ':' in self.peer[0]:
|
2023-10-12 11:24:32 +00:00
|
|
|
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
|
|
|
else:
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
|
|
|
2017-08-29 17:27:06 +00:00
|
|
|
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 main():
|
2017-08-30 14:07:50 +00:00
|
|
|
playlist = os.path.expanduser('~/Videos/cdosea.m3u')
|
|
|
|
prefix = os.path.expanduser('~/Videos/CDOSEA')
|
|
|
|
|
2017-08-29 17:27:06 +00:00
|
|
|
parser = argparse.ArgumentParser(description='play 2 screens in sync')
|
2023-10-12 11:27:26 +00:00
|
|
|
parser.add_argument('--peer', help='ip of peer', required=True)
|
|
|
|
parser.add_argument('--peer-port', help='port of peer', default=DEFAULT_PORT)
|
2017-08-29 17:27:06 +00:00
|
|
|
parser.add_argument('--port', type=int, help='local port', default=DEFAULT_PORT)
|
2017-08-30 14:07:50 +00:00
|
|
|
parser.add_argument('--playlist', help='play.m3u', default=playlist)
|
|
|
|
parser.add_argument('--prefix', help='video location', default=prefix)
|
2017-08-29 17:27:06 +00:00
|
|
|
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()
|
|
|
|
|
2023-10-12 11:27:26 +00:00
|
|
|
peer = (args.peer, args.peer_port)
|
2017-08-29 17:27:06 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2017-08-30 14:07:50 +00:00
|
|
|
player = get_player(fullscreen=not args.window)
|
2023-10-12 11:57:18 +00:00
|
|
|
|
|
|
|
if ':' in args.peer:
|
|
|
|
listen = '::'
|
|
|
|
ThreadingUDPServer.address_family = socket.AF_INET6
|
|
|
|
else:
|
|
|
|
listen = '0.0.0.0'
|
2023-10-12 11:50:05 +00:00
|
|
|
server = ThreadingUDPServer((listen, args.port), Handler)
|
2023-10-12 10:54:33 +00:00
|
|
|
server.allow_reuse_address = True
|
2023-10-12 10:38:34 +00:00
|
|
|
server.player = Player(peer, player, args.playlist, args.prefix)
|
2017-08-29 17:27:06 +00:00
|
|
|
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()
|