diff --git a/src/music/commands/download.py b/src/music/commands/download.py index 458e69f..5535091 100644 --- a/src/music/commands/download.py +++ b/src/music/commands/download.py @@ -1,12 +1,13 @@ import asyncio +import glob import os import re from pathlib import Path -from typing import ClassVar from pydantic_settings import CliImplicitFlag, CliPositionalArg import structlog import yt_dlp +import yt_dlp.cookies from mutagen.easyid3 import EasyID3 from pydantic import Field, computed_field from shazamio import Shazam @@ -73,22 +74,24 @@ def current_quarter() -> Path: return Path().home() / "Music" / f"{date.quarter}_{date.year}" +def _cookiesfrombrowser() -> tuple | None: + """First available cookies source: firefox dev edition, firefox, then chrome.""" + for root in yt_dlp.cookies._firefox_browser_dirs(): + # dev edition lives in a randomly-prefixed dir, so pass an absolute path + matches = glob.glob(os.path.join(root, "*.dev-edition-default")) + if matches: + return ("firefox", matches[0], None, None) + if any(yt_dlp.cookies._firefox_cookie_dbs(yt_dlp.cookies._firefox_browser_dirs())): + return ("firefox", None, None, None) + return ("chrome", None, None, None) + + class YtDownload(Command): """ download a youtube song from {URL} to current quarter dir. """ url: CliPositionalArg[str] = Field(description="youtube url to download") - ydl_opts: ClassVar = { - "format": "mp3/bestaudio/best", - "postprocessors": [ - { - "key": "FFmpegExtractAudio", - "preferredcodec": "mp3", - } - ], - "remote_components": ["ejs:github"], - } parents: CliImplicitFlag[bool] = Field( default=True, description="create the parent dirs if not exists" ) @@ -99,6 +102,24 @@ class YtDownload(Command): date = DateParse() return Path().home() / "Music" / f"{date.quarter}_{date.year}" + @computed_field() + @property + def ydl_opts(self) -> dict: + opts = { + "format": "mp3/bestaudio/best", + "postprocessors": [ + { + "key": "FFmpegExtractAudio", + "preferredcodec": "mp3", + } + ], + "remote_components": ["ejs:github"], + } + cookies = _cookiesfrombrowser() + if cookies is not None: + opts["cookiesfrombrowser"] = cookies + return opts + def run(self) -> None: os.chdir(Path.home() / "Downloads") with yt_dlp.YoutubeDL(self.ydl_opts) as ydl: