diff --git a/backend/src/app.py b/backend/src/app.py index 2066572..a484a46 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -8,8 +8,8 @@ from dataclasses import asdict from .state import State from .connect import get_connection from .room import Room -from .song import Song, init_db, get_song_by_title_artist, add_song_in_db -from .song_fetch import lastfm_query_search, download_song_mp3 +from .song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid +from .song_fetch import lastfm_query_search, yt_get_audio_url, yt_search_song from .qrcode_gen import generate_qr from typing import Any @@ -171,8 +171,7 @@ def add_song(): if (song := get_song_by_title_artist(info.title, info.artist)) is None: ## song not found, downolad from YT - if (res := download_song_mp3(info.title, info.artist)) is None: - return error("Cannot get info from YT") + yt_video_id = yt_search_song(info.title, info.artist) ## add in DB song = Song( @@ -181,7 +180,7 @@ def add_song(): artist=info.artist, tags=info.tags, image_id=info.img_id, - youtube_id=res[0], + youtube_id=yt_video_id, ) add_song_in_db(song) @@ -241,5 +240,19 @@ def room_qrcode(): return Response(stream, content_type="image/jpeg") +@app.get("/api/song/audio") +def get_audio_url(): + if (song_uuid := request.args.get("song")) is None: + return error("Missing song id") + + if (song := get_song_by_uuid(song_uuid)) is None: + return error("Song not found") + + if (url := yt_get_audio_url(song.youtube_id)) is None: + return error("Cannot get audio url") + + return {"success": True, "url": url} + + if __name__ == "__main__": socketio.run(app, debug=True) diff --git a/backend/src/song_fetch.py b/backend/src/song_fetch.py index 561e18d..ec15485 100644 --- a/backend/src/song_fetch.py +++ b/backend/src/song_fetch.py @@ -59,7 +59,7 @@ def lastfm_query_search(query: str) -> SongInfo: return SongInfo(artist=artist, title=name, img_id=img_id, tags=tags) -def download_song_mp3(name: str, artist: str) -> tuple[str, str] | None: # ( id, audio ) +def yt_search_song(name: str, artist: str) -> str: # video id ydl_opts = { "format": "bestaudio", "default_search": "ytsearch1", @@ -70,12 +70,27 @@ def download_song_mp3(name: str, artist: str) -> tuple[str, str] | None: # ( id with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(f"{name!r} - {artist!r}", download=False) - first_entry = info["entries"][0] + return info["entries"][0]["id"] - video_id = first_entry["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 video_id, fmt["url"] + return fmt["url"] return None