team-1/backend/src/song_fetch.py

97 lines
2.4 KiB
Python
Raw Normal View History

2025-08-01 19:16:20 +02:00
import requests
import urllib.parse
import os.path
import os
import sys
2025-08-01 23:21:21 +02:00
from dataclasses import dataclass
2025-08-01 19:16:20 +02:00
sys.path.append("/yt-dlp")
import yt_dlp
2025-08-01 23:21:21 +02:00
@dataclass
class SongInfo:
artist: str
title: str
img_id: str
tags: list[str]
def _lastfm_search(query: str) -> tuple[str, str]:
2025-08-01 19:16:20 +02:00
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"]
2025-08-01 23:21:21 +02:00
def _lastfm_getinfo(name: str, artist: str) -> tuple[str, list[str]]: # ( image_id, tags )
2025-08-01 19:16:20 +02:00
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 (
2025-08-01 23:21:21 +02:00
# track_info["mbid"],
2025-08-01 19:16:20 +02:00
os.path.splitext(os.path.basename(image_url.path))[0],
2025-08-01 23:21:21 +02:00
[t["name"] for t in track_info["toptags"]["tag"]],
2025-08-01 19:16:20 +02:00
)
2025-08-01 23:21:21 +02:00
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)
2025-08-02 04:09:01 +02:00
def yt_search_song(name: str, artist: str) -> str: # video id
2025-08-01 21:21:24 +02:00
ydl_opts = {
"format": "bestaudio",
"default_search": "ytsearch1",
"outtmpl": "%(title)s.%(ext)s",
"skip_download": True,
}
2025-08-01 19:16:20 +02:00
2025-08-01 21:21:24 +02:00
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(f"{name!r} - {artist!r}", download=False)
2025-08-01 19:16:20 +02:00
2025-08-02 04:09:01 +02:00
return info["entries"][0]["id"]
2025-08-01 19:16:20 +02:00
2025-08-02 04:09:01 +02:00
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]
2025-08-01 19:16:20 +02:00
2025-08-01 21:21:24 +02:00
for fmt in first_entry["formats"]:
if "acodec" in fmt and fmt["acodec"] != "none":
2025-08-02 04:09:01 +02:00
return fmt["url"]
2025-08-01 19:16:20 +02:00
2025-08-01 21:21:24 +02:00
return None