diff --git a/syng/server.py b/syng/server.py index 1c2d483..7f6789f 100644 --- a/syng/server.py +++ b/syng/server.py @@ -32,6 +32,8 @@ import socketio from aiohttp import web from profanity_check import predict +from syng.sources.source import EntryNotValid + from .result import Result from . import jsonencoder @@ -314,18 +316,26 @@ class Server: :rtype: Optional[str] """ source_obj = state.client.sources[data["source"]] - entry = await source_obj.get_entry( - data["performer"], data["ident"], artist=data["artist"], title=data["title"] - ) - - if entry is None: + try: + entry = await source_obj.get_entry( + data["performer"], data["ident"], artist=data["artist"], title=data["title"] + ) + if entry is None: + await self.sio.emit( + "msg", + {"msg": f"Unable to add to the waiting room: {data['ident']}. Maybe try again?"}, + room=sid, + ) + return None + except EntryNotValid as e: await self.sio.emit( "msg", - {"msg": f"Unable to add to the waiting room: {data['ident']}. Maybe try again?"}, + {"msg": f"Unable to add to the waiting room: {data['ident']}. {e}"}, room=sid, ) return None + if "uid" not in data or ( (data["uid"] is not None and len(list(state.queue.find_by_uid(data["uid"]))) == 0) or (data["uid"] is None and state.queue.find_by_name(data["performer"]) is None) @@ -511,17 +521,24 @@ class Server: source_obj = state.client.sources[data["source"]] - entry = await source_obj.get_entry( - data["performer"], - data["ident"], - artist=data.get("artist", None), - title=data.get("title", None), - ) - - if entry is None: + try: + entry = await source_obj.get_entry( + data["performer"], + data["ident"], + artist=data.get("artist", None), + title=data.get("title", None), + ) + if entry is None: + await self.sio.emit( + "msg", + {"msg": f"Unable to append {data['ident']}. Maybe try again?"}, + room=sid, + ) + return None + except EntryNotValid as e: await self.sio.emit( "msg", - {"msg": f"Unable to append {data['ident']}. Maybe try again?"}, + {"msg": f"Unable to append {data['ident']}. {e}"}, room=sid, ) return None @@ -564,14 +581,22 @@ class Server: source_obj = state.client.sources[data["source"]] - entry = await source_obj.get_entry( - data["performer"], data["ident"], artist=data["artist"], title=data["title"] - ) + try: + entry = await source_obj.get_entry( + data["performer"], data["ident"], artist=data["artist"], title=data["title"] + ) - if entry is None: + if entry is None: + await self.sio.emit( + "msg", + {"msg": f"Unable to append {data['ident']}. Maybe try again?"}, + room=sid, + ) + return None + except EntryNotValid as e: await self.sio.emit( "msg", - {"msg": f"Unable to append {data['ident']}. Maybe try again?"}, + {"msg": f"Unable to append {data['ident']}. {e}"}, room=sid, ) return None @@ -605,9 +630,17 @@ class Server: lambda item: item.update(**data["meta"], incomplete_data=False), ) - for entry in state.waiting_room: - if entry.uuid == data["uuid"] or str(entry.uuid) == data["uuid"]: - entry.update(**data["meta"], incomplete_data=False) + entry = state.queue.find_by_uuid(data["uuid"]) + if entry is not None: + source = entry.source + source_obj = state.client.sources[source] + if not source_obj.is_valid(entry): + await self.log_to_playback(state, f"Entry {entry.ident} is not valid.", level="error") + await state.queue.remove(entry) + else: + for entry in state.waiting_room: + if entry.uuid == data["uuid"] or str(entry.uuid) == data["uuid"]: + entry.update(**data["meta"], incomplete_data=False) await self.broadcast_state(state) diff --git a/syng/sources/filebased.py b/syng/sources/filebased.py index ca031bf..e6272ab 100644 --- a/syng/sources/filebased.py +++ b/syng/sources/filebased.py @@ -4,6 +4,8 @@ import asyncio import os from typing import TYPE_CHECKING, Any, Optional +from syng.entry import Entry + try: from pymediainfo import MediaInfo @@ -39,6 +41,9 @@ class FileBasedSource(Source): self.extensions: list[str] = config["extensions"] if "extensions" in config else ["mp3+cdg"] self.extra_mpv_options = {"scale": "oversample"} + def is_valid(self, entry: Entry) -> bool: + return entry.ident in self._index and entry.source == self.source_name + def has_correct_extension(self, path: Optional[str]) -> bool: """ Check if a `path` has a correct extension. diff --git a/syng/sources/source.py b/syng/sources/source.py index e209682..4f3a790 100644 --- a/syng/sources/source.py +++ b/syng/sources/source.py @@ -29,6 +29,9 @@ from ..config import BoolOption, ConfigOption # logger: logging.Logger = logging.getLogger(__name__) +class EntryNotValid(Exception): + """Raised when an entry is not valid for a source.""" + @dataclass class DLFilesEntry: @@ -127,6 +130,19 @@ class Source(ABC): self.build_index = config.get("build_index", False) self.apply_config(config) + def is_valid(self, entry: Entry) -> bool: + """ + Check if the entry is valid. + + Each source can implement this method to check if the entry is valid. + + :param entry: The entry to check + :type entry: Entry + :returns: True if the entry is valid, False otherwise. + :rtype: bool + """ + return True + async def get_entry( self, performer: str, @@ -153,9 +169,8 @@ class Source(ABC): :returns: New entry for the identifier, or None, if the ident is invalid. :rtype: Optional[Entry] + :raises EntryNotValid: If the entry is not valid for the source. """ - if ident not in self._index: - return None res: Result = Result.from_filename(ident, self.source_name) entry = Entry( @@ -168,8 +183,8 @@ class Source(ABC): performer=performer, incomplete_data=True, ) - if not await self.is_valid(entry): - return None + if not self.is_valid(entry): + raise EntryNotValid(f"Entry {entry} is not valid for source {self.source_name}") return entry async def search(self, query: str) -> list[Result]: