diff --git a/.gitignore b/.gitignore index 066c297..bbeec67 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__/ .ruff_cache/ music/ +cookies/ diff --git a/Makefile b/Makefile index c985eba..1c47226 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: run test build frontend backend run: - @echo 'Not implemented' + HOST=127.0.0.1 PORT=4009 COOKIES_DIR=cookies python3 ./backend/main.py test: @python3 -m unittest discover -vcs ./backend diff --git a/backend/config.py b/backend/config.py new file mode 100644 index 0000000..86e3d40 --- /dev/null +++ b/backend/config.py @@ -0,0 +1,22 @@ +import os +from pathlib import Path + + +class Config: + + def __init__(self) -> None: + + self.host = os.getenv('HOST') or '0.0.0.0' + self.port = int(os.getenv('PORT') or 4009) + self.path_length = int(os.getenv('PATH_LENGTH') or 255) + self.cookies_dir = Path(os.getenv('COOKIES_DIR') or 'cookies') + + +_config: Config | None = None + + +def get() -> Config: + global _config + if _config is None: + _config = Config() + return _config diff --git a/backend/main.py b/backend/main.py index 35b7086..7f6879c 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,6 +3,7 @@ import json import websockets +import config import response import ydl_pool import ydl_wrap @@ -11,10 +12,6 @@ import ydl_wrap type SocketT = websockets.WebSocketServerProtocol -# TODO: config -HOST = '127.0.0.1' -PORT = 5678 - async def handler(socket: SocketT) -> None: @@ -59,7 +56,8 @@ async def handler(socket: SocketT) -> None: async def main() -> None: - async with websockets.serve(handler, HOST, PORT): + cfg = config.get() + async with websockets.serve(handler, cfg.host, cfg.port): await asyncio.Future() diff --git a/backend/ydl_pool.py b/backend/ydl_pool.py index 10bed62..ee6bef7 100644 --- a/backend/ydl_pool.py +++ b/backend/ydl_pool.py @@ -1,6 +1,7 @@ from yt_dlp import YoutubeDL from yt_dlp.postprocessor import FFmpegExtractAudioPP +import config import id3pp @@ -21,7 +22,7 @@ class _CreateYDL: @staticmethod def yandex() -> YoutubeDL: - return YoutubeDL() # TODO: cookies + return YoutubeDL() create_ydl_fn = { @@ -45,13 +46,21 @@ class Downloaders: def get_ydl(self, site: str) -> YoutubeDL: + cfg = config.get() ydl = self.ydls[site] + if ydl is None: ydl = create_ydl_fn[site]() - ydl.params['trim_file_name'] = 255 # TODO: config # NOTE: includes path, not only filename + + ydl.params['trim_file_name'] = cfg.path_length # NOTE: includes path, not only filename # artists.0 instead of artist, because it can contain "feat. ..." ydl.params['outtmpl']['default'] = 'music/%(artists.0)s/%(album)s/%(track)s.%(ext)s' ydl.add_post_processor(id3pp.ID3TagsPP(), when='post_process') + + cookies = cfg.cookies_dir / (site + '.txt') + if cookies.exists(): + ydl.params['cookiefile'] = str(cookies) + return ydl def cleanup(self) -> None: diff --git a/backend/ydl_wrap.py b/backend/ydl_wrap.py index cd37f35..2a89ebf 100644 --- a/backend/ydl_wrap.py +++ b/backend/ydl_wrap.py @@ -16,10 +16,13 @@ async def get_playlist_items(ydl: YoutubeDL, url: str) -> list[str]: def _target_get_playlist_items(ydl: YoutubeDL, url: str) -> list[str]: - info = ydl.extract_info(url, download=False, process=False) + info = ydl.extract_info(url, download=False, process=True) if info is None: raise RuntimeError('ydl.extract_info returned None') - return [entry['title'] for entry in info['entries']] + return [ + entry['track'] if 'track' in entry else entry['title'] + for entry in info['entries'] + ] async def download(