removed __cache__-thingy, that was only around to hold data from search results to forming the entries...
This commit is contained in:
parent
cd3e6d6d7c
commit
fdf72ac4f7
11 changed files with 674 additions and 690 deletions
|
@ -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:
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]:
|
||||
|
|
|
@ -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,19 +44,16 @@ 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:
|
||||
self.length = 300
|
||||
self._title = None
|
||||
self._author = None
|
||||
self.watch_url = url
|
||||
return
|
||||
if self._infos is None:
|
||||
raise RuntimeError(f'Extraction not possible for "{url}"')
|
||||
try:
|
||||
self._infos = YoutubeDL({"quiet": True}).extract_info(url, download=False)
|
||||
except DownloadError:
|
||||
self.length = 300
|
||||
self._title = None
|
||||
self._author = None
|
||||
self.watch_url = url
|
||||
return
|
||||
if self._infos is None:
|
||||
raise RuntimeError(f'Extraction not possible for "{url}"')
|
||||
self.length = self._infos["duration"]
|
||||
self._title = self._infos["title"]
|
||||
self._author = self._infos["channel"]
|
||||
|
@ -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,33 +283,16 @@ 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,
|
||||
source="youtube",
|
||||
album="YouTube",
|
||||
duration=length,
|
||||
title=yt_song._title,
|
||||
artist=yt_song._author,
|
||||
performer=performer,
|
||||
)
|
||||
|
||||
return await asyncio.to_thread(_get_entry, performer, ident)
|
||||
return Entry(
|
||||
ident=ident,
|
||||
source="youtube",
|
||||
duration=180,
|
||||
album="YouTube",
|
||||
title=title,
|
||||
artist=artist,
|
||||
performer=performer,
|
||||
incomplete_data=True,
|
||||
)
|
||||
|
||||
async def search(self, query: str) -> list[Result]:
|
||||
"""
|
||||
|
@ -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 {
|
||||
|
|
598
syng/static/assets/index.38362a39.js
Normal file
598
syng/static/assets/index.38362a39.js
Normal file
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
1
syng/static/assets/index.e5e245ad.css
Normal file
1
syng/static/assets/index.e5e245ad.css
Normal file
File diff suppressed because one or more lines are too long
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue