Add YouTube Music playlist import support
- Add ytmusicapi dependency for fetching public YouTube Music playlists - Create youtube_music service with playlist fetching and track search - Add /api/youtube-music/import and /api/youtube-music/search endpoints - Add importYouTubePlaylist and searchYouTubeMusic API client functions - Update Playlists page with YouTube Music import button and URL input modal
This commit is contained in:
87
backend/app/services/youtube_music.py
Normal file
87
backend/app/services/youtube_music.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import re
|
||||
|
||||
from ytmusicapi import YTMusic
|
||||
|
||||
ytmusic = YTMusic()
|
||||
|
||||
|
||||
def extract_playlist_id(url: str) -> str:
|
||||
"""Extract playlist ID from a YouTube Music playlist URL."""
|
||||
match = re.search(r"[?&]list=([A-Za-z0-9_-]+)", url)
|
||||
if not match:
|
||||
raise ValueError("Invalid YouTube Music playlist URL")
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def get_playlist_tracks(playlist_url: str) -> tuple[str, str | None, list[dict]]:
|
||||
"""Fetch playlist info and tracks from a public YouTube Music playlist.
|
||||
|
||||
Returns (playlist_name, playlist_image_url, tracks).
|
||||
Each track dict has: title, artist, album, youtube_id, image_url.
|
||||
"""
|
||||
playlist_id = extract_playlist_id(playlist_url)
|
||||
playlist = ytmusic.get_playlist(playlist_id, limit=None)
|
||||
|
||||
name = playlist.get("title", playlist_id)
|
||||
image_url = None
|
||||
thumbnails = playlist.get("thumbnails")
|
||||
if thumbnails:
|
||||
image_url = thumbnails[-1].get("url")
|
||||
|
||||
tracks = []
|
||||
for item in playlist.get("tracks", []):
|
||||
artists = item.get("artists") or []
|
||||
artist_name = ", ".join(a.get("name", "") for a in artists if a.get("name"))
|
||||
|
||||
album_name = None
|
||||
album = item.get("album")
|
||||
if album:
|
||||
album_name = album.get("name")
|
||||
|
||||
thumb_url = None
|
||||
thumbs = item.get("thumbnails")
|
||||
if thumbs:
|
||||
thumb_url = thumbs[-1].get("url")
|
||||
|
||||
tracks.append({
|
||||
"title": item.get("title", "Unknown"),
|
||||
"artist": artist_name or "Unknown",
|
||||
"album": album_name,
|
||||
"youtube_id": item.get("videoId"),
|
||||
"image_url": thumb_url,
|
||||
})
|
||||
|
||||
return name, image_url, tracks
|
||||
|
||||
|
||||
def search_track(query: str) -> list[dict]:
|
||||
"""Search YouTube Music for tracks matching the query.
|
||||
|
||||
Returns a list of result dicts with: title, artist, album, youtube_id, image_url.
|
||||
"""
|
||||
results = ytmusic.search(query, filter="songs", limit=10)
|
||||
|
||||
tracks = []
|
||||
for item in results:
|
||||
artists = item.get("artists") or []
|
||||
artist_name = ", ".join(a.get("name", "") for a in artists if a.get("name"))
|
||||
|
||||
album_name = None
|
||||
album = item.get("album")
|
||||
if album:
|
||||
album_name = album.get("name")
|
||||
|
||||
thumb_url = None
|
||||
thumbs = item.get("thumbnails")
|
||||
if thumbs:
|
||||
thumb_url = thumbs[-1].get("url")
|
||||
|
||||
tracks.append({
|
||||
"title": item.get("title", "Unknown"),
|
||||
"artist": artist_name or "Unknown",
|
||||
"album": album_name,
|
||||
"youtube_id": item.get("videoId"),
|
||||
"image_url": thumb_url,
|
||||
})
|
||||
|
||||
return tracks
|
||||
Reference in New Issue
Block a user