removed __cache__-thingy, that was only around to hold data from search results to forming the entries...

This commit is contained in:
Christoph Stahl 2024-10-14 18:22:31 +02:00
parent cd3e6d6d7c
commit fdf72ac4f7
11 changed files with 674 additions and 690 deletions

View file

@ -61,6 +61,7 @@ class Entry:
uuid: UUID = field(default_factory=uuid4)
uid: Optional[str] = None
started_at: Optional[float] = None
incomplete_data: bool = False
def update(self, **kwargs: Any) -> None:
"""

View file

@ -26,8 +26,8 @@ class Result:
ident: str
source: str
title: str
artist: str
album: str
artist: Optional[str]
album: Optional[str]
duration: Optional[str] = None
@classmethod
@ -58,9 +58,7 @@ class Result:
album = splitfile[2].strip()
return cls(ident=ident, source=source, title=title, artist=artist, album=album)
except IndexError:
return cls(
ident=filename, source=source, title=basename, artist="Unknown", album="Unknown"
)
return cls(ident=filename, source=source, title=basename, artist=None, album=None)
@classmethod
def from_dict(cls, values: dict[str, str]) -> Result:
@ -97,20 +95,22 @@ class Result:
- ident (str)
- source (str)
- title (str)
- artist (str)
- album (str)
- album (str, if available)
- artist (str, if available)
- duration (str, if available)
:return: The dictionary with the values
:rtype: dict[str, str]
"""
output = {
output: dict[str, str] = {
"ident": self.ident,
"source": self.source,
"title": self.title,
"artist": self.artist,
"album": self.album,
}
if self.album is not None:
output["album"] = self.album
if self.artist is not None:
output["artist"] = self.artist
if self.duration is not None:
output["duration"] = self.duration
return output

View file

@ -23,7 +23,7 @@ from json.decoder import JSONDecodeError
from argparse import Namespace
from dataclasses import dataclass
from dataclasses import field
from typing import Any, Callable, overload
from typing import Any, Callable
from typing import AsyncGenerator
from typing import Optional
@ -32,7 +32,6 @@ from aiohttp import web
from profanity_check import predict
from .result import Result
from .sources.youtube import YouTube
from . import jsonencoder
from .log import logger
@ -298,7 +297,9 @@ class Server:
:rtype: None
"""
source_obj = state.client.sources[data["source"]]
entry = await source_obj.get_entry(data["performer"], data["ident"])
entry = await source_obj.get_entry(
data["performer"], data["ident"], artist=data["artist"], title=data["title"]
)
if entry is None:
await self.sio.emit(
@ -476,6 +477,8 @@ class Server:
"source": data["source"],
"performer": data["performer"],
"ident": data["ident"],
"artist": data["artist"],
"title": data["title"],
},
"old_entry": {
"artist": old_entry.artist,
@ -489,7 +492,9 @@ class Server:
source_obj = state.client.sources[data["source"]]
entry = await source_obj.get_entry(data["performer"], data["ident"])
entry = await source_obj.get_entry(
data["performer"], data["ident"], artist=data["artist"], title=data["title"]
)
if entry is None:
await self.sio.emit(
@ -531,7 +536,9 @@ class Server:
source_obj = state.client.sources[data["source"]]
entry = await source_obj.get_entry(data["performer"], data["ident"])
entry = await source_obj.get_entry(
data["performer"], data["ident"], artist=data["artist"], title=data["title"]
)
if entry is None:
await self.sio.emit(
@ -564,14 +571,15 @@ class Server:
:type data: dict[str, Any]
:rtype: None
"""
print(data)
state.queue.update(
data["uuid"],
lambda item: item.update(**data["meta"]),
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"])
entry.update(**data["meta"], incomplete_data=False)
await self.broadcast_state(state)
@ -1111,21 +1119,6 @@ class Server:
web_sid = data["sid"]
results = [Result.from_dict(result) for result in data["results"]]
# TODO: we convert the results to YouTube objects. This
# adds them to the cache to prevent YouTube from blocking us.
__unused_yt_list = [
YouTube.from_result(
{
"duration": result.duration,
"title": result.title,
"channel": result.artist,
"url": result.ident,
}
)
for result in results
if "youtube" == result.source
]
await self.send_search_results(web_sid, results)
async def send_search_results(self, sid: str, results: list[Result]) -> None:

View file

@ -157,7 +157,14 @@ class Source(ABC):
)
return await mpv_process
async def get_entry(self, performer: str, ident: str) -> Optional[Entry]:
async def get_entry(
self,
performer: str,
ident: str,
/,
artist: Optional[str] = None,
title: Optional[str] = None,
) -> Optional[Entry]:
"""
Create an :py:class:`syng.entry.Entry` from a given identifier.
@ -185,10 +192,11 @@ class Source(ABC):
ident=ident,
source=self.source_name,
duration=180,
album=res.album,
title=res.title,
artist=res.artist,
album=res.album if res.album else "Unknown",
title=res.title if res.title else title if title else "Unknown",
artist=res.artist if res.artist else artist if artist else "Unknown",
performer=performer,
incomplete_data=True,
)
async def search(self, query: str) -> list[Result]:

View file

@ -30,10 +30,6 @@ class YouTube:
A minimal compatibility layer for the YouTube object of pytube, implemented via yt-dlp
"""
__cache__: dict[str, Any] = (
{}
) # TODO: this may grow fast... but atm it fixed youtubes anti bot measures
def __init__(self, url: Optional[str] = None):
"""
Construct a YouTube object from a url.
@ -48,9 +44,6 @@ class YouTube:
self._author: Optional[str]
if url is not None:
if url in YouTube.__cache__:
self._infos = YouTube.__cache__[url]
else:
try:
self._infos = YoutubeDL({"quiet": True}).extract_info(url, download=False)
except DownloadError:
@ -107,12 +100,12 @@ class YouTube:
:type search_result: dict[str, Any]
"""
url = search_result["url"]
cls.__cache__[url] = {
"duration": int(search_result["duration"]),
"title": search_result["title"],
"channel": search_result["channel"],
"url": url,
}
# cls.__cache__[url] = {
# "duration": int(search_result["duration"]),
# "title": search_result["title"],
# "channel": search_result["channel"],
# "url": url,
# }
return cls(url)
@ -268,7 +261,14 @@ class YoutubeSource(Source):
else:
await super().play(entry, mpv_options)
async def get_entry(self, performer: str, ident: str) -> Optional[Entry]:
async def get_entry(
self,
performer: str,
ident: str,
/,
artist: Optional[str] = None,
title: Optional[str] = None,
) -> Optional[Entry]:
"""
Create an :py:class:`syng.entry.Entry` for the identifier.
@ -283,34 +283,17 @@ class YoutubeSource(Source):
:rtype: Optional[Entry]
"""
def _get_entry(performer: str, url: str) -> Optional[Entry]:
"""
Create the entry in a thread.
:param performer: The person singing.
:type performer: str
:param url: A url to a YouTube video.
:type url: str
:return: An entry with the data.
:rtype: Optional[Entry]
"""
yt_song = YouTube(url)
try:
length = yt_song.length
except TypeError:
length = 180
return Entry(
ident=url,
ident=ident,
source="youtube",
duration=180,
album="YouTube",
duration=length,
title=yt_song._title,
artist=yt_song._author,
title=title,
artist=artist,
performer=performer,
incomplete_data=True,
)
return await asyncio.to_thread(_get_entry, performer, ident)
async def search(self, query: str) -> list[Result]:
"""
Search YouTube and the configured channels for the query.
@ -392,7 +375,7 @@ class YoutubeSource(Source):
Video metadata should be read on the client to avoid banning
the server.
"""
if entry.title is None or entry.artist is None:
if entry.incomplete_data:
print(f"Looking up {entry.ident}")
youtube_video: YouTube = await asyncio.to_thread(YouTube, entry.ident)
return {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -5,8 +5,8 @@
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Syng Rocks!</title>
<script type="module" crossorigin src="/assets/index.953ecce8.js"></script>
<link rel="stylesheet" href="/assets/index.ceeebb4f.css">
<script type="module" crossorigin src="/assets/index.38362a39.js"></script>
<link rel="stylesheet" href="/assets/index.e5e245ad.css">
</head>
<body>
<div id="app"></div>