diff --git a/syng/client.py b/syng/client.py index 112499f..b723d79 100644 --- a/syng/client.py +++ b/syng/client.py @@ -1,13 +1,17 @@ import asyncio import socketio from traceback import print_exc +from json import load -from .sources import YoutubeSource +from .sources import Source, configure_sources from .entry import Entry + sio = socketio.AsyncClient() -sources = {"youtube": YoutubeSource()} +with open("./syng-client.json") as f: + source_config = load(f) +sources = configure_sources(source_config, client=True) currentLock = asyncio.Semaphore(0) state = { @@ -78,10 +82,11 @@ async def handle_connect(): await sio.emit("register-client", {"secret": "test"}) -@sio.on("register-client") +@sio.on("client-registered") async def handle_register(data): if data["success"]: print("Registered") + await sio.emit("config", {"sources": source_config}) asyncio.create_task(playerTask()) asyncio.create_task(bufferTask()) else: diff --git a/syng/server.py b/syng/server.py index afe1b45..e8053e5 100644 --- a/syng/server.py +++ b/syng/server.py @@ -9,7 +9,7 @@ from aiohttp import web import socketio from .entry import Entry -from .sources import YoutubeSource +from .sources import configure_sources # socketio = SocketIO(app, cors_allowed_origins='*') # sio = socketio.AsyncServer() @@ -17,12 +17,10 @@ from .sources import YoutubeSource sio = socketio.AsyncServer(cors_allowed_origins="*", logger=True, engineio_logger=True) app = web.Application() sio.attach(app) -sources = {"youtube": YoutubeSource()} -admins = set() admin_secrets = ["admin"] client_secrets = ["test"] -clients = set() +sources = {} class Queue(deque): @@ -57,6 +55,7 @@ async def handle_state(sid, data: dict[str, Any]): @sio.on("append") async def handle_append(sid, data: dict[str, Any]): + print(f"append: {data}") source_obj = sources[data["source"]] entry = await Entry.from_source(data["performer"], data["id"], source_obj) @@ -66,39 +65,63 @@ async def handle_append(sid, data: dict[str, Any]): @sio.on("get-next") async def handle_next(sid, data: dict[str, Any]): - if sid in clients: - print(f"get-next request from client {sid}") - current = await queue.popleft() - print(f"Sending {current} to client {sid}") - print(f"new state: {queue.to_dict()}") - await sio.emit("next", current.to_dict(), room=sid) + async with sio.session(sid) as session: + if "client" in session and session["client"]: + print(f"get-next request from client {sid}") + current = await queue.popleft() + print(f"Sending {current} to client {sid}") + print(f"new state: {queue.to_dict()}") + await sio.emit("next", current.to_dict(), room=sid) @sio.on("register-client") async def handle_register_client(sid, data: dict[str, Any]): if data["secret"] in client_secrets: print(f"Registerd new client {sid}") - clients.add(sid) - await sio.emit("register-client", {"success": True}, room=sid) + await sio.save_session(sid, {"client": True}) + sio.enter_room(sid, "clients") + await sio.emit("client-registered", {"success": True}, room=sid) else: - await sio.emit("register-client", {"success": False}, room=sid) + await sio.emit("client-registered", {"success": False}, room=sid) + + +@sio.on("config") +async def handle_config(sid, data): + async with sio.session(sid) as session: + if "client" in session and session["client"]: + sources.update(configure_sources(data["sources"], client=False)) + print(f"Updated Config: {sources}") @sio.on("register-admin") async def handle_register_admin(sid, data: dict[str, str]): if data["secret"] in admin_secrets: print(f"Registerd new admin {sid}") - admins.add(sid) + await sio.save_session(sid, {"admin": True}) await sio.emit("register-admin", {"success": True}, room=sid) else: await sio.emit("register-admin", {"success": False}, room=sid) +@sio.on("get-config") +async def handle_config(sid, data): + async with sio.session(sid) as session: + if "admin" in session and session["admin"]: + await sio.emit("config", list(sources.keys())) + + @sio.on("skip") async def handle_skip(sid, data={}): - if sid in admins: - for client in clients: - await sio.emit("skip", room=client) + async with sio.session(sid) as session: + if "admin" in session and session["admin"]: + await sio.emit("skip", room="client") + + +@sio.on("disconnect") +async def handle_disconnect(sid, data={}): + async with sio.session(sid) as session: + if "client" in session and session["client"]: + sio.leave_room(sid, "clients") @sio.on("search") diff --git a/syng/sources/__init__.py b/syng/sources/__init__.py index 3fec541..4ffaa6e 100644 --- a/syng/sources/__init__.py +++ b/syng/sources/__init__.py @@ -1,2 +1,16 @@ +from .source import Source, available_sources from .youtube import YoutubeSource -from .source import Source +from .s3 import S3Source + + +def configure_sources(configs: dict, client) -> dict[str, Source]: + print(available_sources) + configured_sources = {} + for source, config in configs.items(): + if source in available_sources: + configured_sources[source] = available_sources[source](config) + if client: + configured_sources[source].init_client() + else: + configured_sources[source].init_server() + return configured_sources diff --git a/syng/sources/source.py b/syng/sources/source.py index ec505c3..95f0c37 100644 --- a/syng/sources/source.py +++ b/syng/sources/source.py @@ -29,3 +29,12 @@ class Source: async def skip_current(self) -> None: pass + + def init_server(self) -> None: + pass + + def init_client(self) -> None: + pass + + +available_sources = {} diff --git a/syng/sources/youtube.py b/syng/sources/youtube.py index d178a37..a6b176f 100644 --- a/syng/sources/youtube.py +++ b/syng/sources/youtube.py @@ -5,28 +5,29 @@ from functools import partial from pytube import YouTube, Search, Channel, innertube from mpv import MPV -from .source import Source, async_in_thread +from .source import Source, async_in_thread, available_sources from ..entry import Entry from ..result import Result class YoutubeSource(Source): - def __init__(self): + def __init__(self, config): super().__init__() self.innertube_client = innertube.InnerTube(client="WEB") - self.channels = ["/c/CCKaraoke"] + self.channels = config["channels"] if "channels" in config else [] @async_in_thread def play(self, ident: str) -> None: - self.player = MPV( + player = MPV( input_default_bindings=True, input_vo_keyboard=True, osc=True, ytdl=True, script_opts="ytdl_hook-ytdl_path=yt-dlp", ) - self.player.play(ident) - self.player.wait_for_playback() + player.play(ident) + player.wait_for_playback() + del player async def skip_current(self) -> None: loop = asyncio.get_event_loop() @@ -112,3 +113,6 @@ class YoutubeSource(Source): except KeyError: pass return list_of_videos + + +available_sources["youtube"] = YoutubeSource