import requests import urllib.parse import os.path import os import sys from dataclasses import dataclass sys.path.append("/yt-dlp") import yt_dlp @dataclass class SongInfo: artist: str title: str img_id: str tags: list[str] def _lastfm_search(query: str) -> tuple[str, str]: response = requests.get( url="https://ws.audioscrobbler.com/2.0/?method=track.search&format=json", params={"limit": 5, "track": query, "api_key": os.environ["LASTFM_API_KEY"]}, ) assert response.status_code == 200 track_info = response.json()["results"]["trackmatches"]["track"][0] return track_info["name"], track_info["artist"] def _lastfm_getinfo(name: str, artist: str) -> tuple[str, list[str]]: # ( image_id, tags ) response = requests.get( url="https://ws.audioscrobbler.com/2.0/?method=track.getInfo&format=json", params={ "track": name, "artist": artist, "api_key": os.environ["LASTFM_API_KEY"], }, ) track_info = response.json()["track"] image_url = urllib.parse.urlparse(track_info["album"]["image"][0]["#text"]) return ( # track_info["mbid"], os.path.splitext(os.path.basename(image_url.path))[0], [t["name"] for t in track_info["toptags"]["tag"]], ) def lastfm_query_search(query: str) -> SongInfo: name, artist = _lastfm_search(query) img_id, tags = _lastfm_getinfo(name, artist) return SongInfo(artist=artist, title=name, img_id=img_id, tags=tags) def yt_search_song(name: str, artist: str) -> str: # video id ydl_opts = { "format": "bestaudio", "default_search": "ytsearch1", "outtmpl": "%(title)s.%(ext)s", "skip_download": True, } with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(f"{name!r} - {artist!r}", download=False) return info["entries"][0]["id"] def yt_get_audio_url(video_id) -> str | None: # audio url ydl_opts = { "format": "bestaudio", "default_search": "ytsearch1", "outtmpl": "%(title)s.%(ext)s", "skip_download": True, } with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(video_id, download=False) if "entries" not in info: return info["url"] first_entry = info["entries"][0] for fmt in first_entry["formats"]: if "acodec" in fmt and fmt["acodec"] != "none": return fmt["url"] return None