Added is_valid check to sources. Filebased entries are valid, iff they appear in index.

This commit is contained in:
Christoph Stahl 2025-02-15 01:32:13 +01:00
parent 9232f3870f
commit c381133252
3 changed files with 80 additions and 27 deletions

View file

@ -32,6 +32,8 @@ import socketio
from aiohttp import web from aiohttp import web
from profanity_check import predict from profanity_check import predict
from syng.sources.source import EntryNotValid
from .result import Result from .result import Result
from . import jsonencoder from . import jsonencoder
@ -314,10 +316,10 @@ class Server:
:rtype: Optional[str] :rtype: Optional[str]
""" """
source_obj = state.client.sources[data["source"]] source_obj = state.client.sources[data["source"]]
try:
entry = await source_obj.get_entry( entry = await source_obj.get_entry(
data["performer"], data["ident"], artist=data["artist"], title=data["title"] data["performer"], data["ident"], artist=data["artist"], title=data["title"]
) )
if entry is None: if entry is None:
await self.sio.emit( await self.sio.emit(
"msg", "msg",
@ -325,6 +327,14 @@ class Server:
room=sid, room=sid,
) )
return None return None
except EntryNotValid as e:
await self.sio.emit(
"msg",
{"msg": f"Unable to add to the waiting room: {data['ident']}. {e}"},
room=sid,
)
return None
if "uid" not in data or ( if "uid" not in data or (
(data["uid"] is not None and len(list(state.queue.find_by_uid(data["uid"]))) == 0) (data["uid"] is not None and len(list(state.queue.find_by_uid(data["uid"]))) == 0)
@ -511,13 +521,13 @@ class Server:
source_obj = state.client.sources[data["source"]] source_obj = state.client.sources[data["source"]]
try:
entry = await source_obj.get_entry( entry = await source_obj.get_entry(
data["performer"], data["performer"],
data["ident"], data["ident"],
artist=data.get("artist", None), artist=data.get("artist", None),
title=data.get("title", None), title=data.get("title", None),
) )
if entry is None: if entry is None:
await self.sio.emit( await self.sio.emit(
"msg", "msg",
@ -525,6 +535,13 @@ class Server:
room=sid, room=sid,
) )
return None return None
except EntryNotValid as e:
await self.sio.emit(
"msg",
{"msg": f"Unable to append {data['ident']}. {e}"},
room=sid,
)
return None
entry.uid = data["uid"] if "uid" in data else None entry.uid = data["uid"] if "uid" in data else None
@ -564,6 +581,7 @@ class Server:
source_obj = state.client.sources[data["source"]] source_obj = state.client.sources[data["source"]]
try:
entry = await source_obj.get_entry( entry = await source_obj.get_entry(
data["performer"], data["ident"], artist=data["artist"], title=data["title"] data["performer"], data["ident"], artist=data["artist"], title=data["title"]
) )
@ -575,6 +593,13 @@ class Server:
room=sid, room=sid,
) )
return None return None
except EntryNotValid as e:
await self.sio.emit(
"msg",
{"msg": f"Unable to append {data['ident']}. {e}"},
room=sid,
)
return None
entry.uid = data["uid"] if "uid" in data else None entry.uid = data["uid"] if "uid" in data else None
@ -605,6 +630,14 @@ class Server:
lambda item: item.update(**data["meta"], incomplete_data=False), lambda item: item.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: for entry in state.waiting_room:
if entry.uuid == data["uuid"] or str(entry.uuid) == data["uuid"]: if entry.uuid == data["uuid"] or str(entry.uuid) == data["uuid"]:
entry.update(**data["meta"], incomplete_data=False) entry.update(**data["meta"], incomplete_data=False)

View file

@ -4,6 +4,8 @@ import asyncio
import os import os
from typing import TYPE_CHECKING, Any, Optional from typing import TYPE_CHECKING, Any, Optional
from syng.entry import Entry
try: try:
from pymediainfo import MediaInfo 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.extensions: list[str] = config["extensions"] if "extensions" in config else ["mp3+cdg"]
self.extra_mpv_options = {"scale": "oversample"} 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: def has_correct_extension(self, path: Optional[str]) -> bool:
""" """
Check if a `path` has a correct extension. Check if a `path` has a correct extension.

View file

@ -29,6 +29,9 @@ from ..config import BoolOption, ConfigOption
# logger: logging.Logger = logging.getLogger(__name__) # logger: logging.Logger = logging.getLogger(__name__)
class EntryNotValid(Exception):
"""Raised when an entry is not valid for a source."""
@dataclass @dataclass
class DLFilesEntry: class DLFilesEntry:
@ -127,6 +130,19 @@ class Source(ABC):
self.build_index = config.get("build_index", False) self.build_index = config.get("build_index", False)
self.apply_config(config) 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( async def get_entry(
self, self,
performer: str, performer: str,
@ -153,9 +169,8 @@ class Source(ABC):
:returns: New entry for the identifier, or None, if the ident is :returns: New entry for the identifier, or None, if the ident is
invalid. invalid.
:rtype: Optional[Entry] :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) res: Result = Result.from_filename(ident, self.source_name)
entry = Entry( entry = Entry(
@ -168,8 +183,8 @@ class Source(ABC):
performer=performer, performer=performer,
incomplete_data=True, incomplete_data=True,
) )
if not await self.is_valid(entry): if not self.is_valid(entry):
return None raise EntryNotValid(f"Entry {entry} is not valid for source {self.source_name}")
return entry return entry
async def search(self, query: str) -> list[Result]: async def search(self, query: str) -> list[Result]: