fix(deps): replace spotdl with direct oembed and yt-dlp to fix fastapi dependency conflict

This commit is contained in:
Antigravity committed 2026-10-12 11:19:19 +03:00
1 parent 5b6c2c72f7
commit 9de3affc32
2 files changed
+60 -37

No files matched your search

+57 -33
View File
@@ -1,8 +1,10 @@
import os
import re
import asyncio
import subprocess
from typing import List, Optional
import httpx
import yt_dlp
from app.config import settings
from app.providers.base import BaseProvider, TrackMetadata
from app.core.tagger import apply_id3_tags
@@ -25,40 +27,65 @@ class UniversalProvider(BaseProvider):
def _resolve_sync(self, url: str) -> List[TrackMetadata]:
lower = url.lower()
# Handle Spotify / Apple Music via SpotDL parser / metadata
if "spotify.com" in lower or "music.apple.com" in lower:
return self._resolve_spotdl(url)
# Handle Spotify via open oEmbed API & yt-dlp fallback
if "spotify.com" in lower:
tracks = self._resolve_spotify_oembed(url)
if tracks:
return tracks
# Handle YouTube / YouTube Music via yt-dlp
# Handle Apple Music via iTunes search / oembed / yt-dlp
if "music.apple.com" in lower:
tracks = self._resolve_apple_music(url)
if tracks:
return tracks
# Default: Handle YouTube / YouTube Music and other generic links via yt-dlp
return self._resolve_ytdlp(url)
def _resolve_spotdl(self, url: str) -> List[TrackMetadata]:
# SpotDL resolves metadata seamlessly
tracks: List[TrackMetadata] = []
def _resolve_spotify_oembed(self, url: str) -> List[TrackMetadata]:
try:
from spotdl.types.song import Song
from spotdl.utils.search import parse_query
oembed_url = f"https://open.spotify.com/oembed?url={url}"
with httpx.Client(timeout=10.0) as client:
resp = client.get(oembed_url)
if resp.status_code == 200:
data = resp.json()
# data has title ("Track Name" or "Track Name - Single"), thumbnail_url
full_title = data.get("title", "Unknown")
# Spotfiy oEmbed titles are often "Title" or "Artist - Title"
artist = "Unknown"
title = full_title
if " - " in full_title:
parts = full_title.split(" - ", 1)
artist = parts[0].strip()
title = parts[1].strip()
songs = parse_query([url])
for s in songs:
tracks.append(TrackMetadata(
service="spotify" if "spotify" in url else "apple",
service_id=s.url or s.song_id,
title=s.name,
artist=s.artist,
album=s.album_name,
track_number=s.track_number,
year=int(s.year) if s.year else None,
genre=s.genres[0] if s.genres else None,
duration_ms=int(s.duration * 1000) if s.duration else None,
is_explicit=bool(s.explicit),
cover_url=s.cover_url,
source_url=s.url
))
return [TrackMetadata(
service="spotify",
service_id=url,
title=title,
artist=artist,
album="Singles",
cover_url=data.get("thumbnail_url"),
source_url=url
)]
except Exception as e:
print(f"SpotDL resolve error, falling back to yt-dlp: {e}")
return self._resolve_ytdlp(url)
return tracks
print(f"Spotify oEmbed resolution failed: {e}")
return []
def _resolve_apple_music(self, url: str) -> List[TrackMetadata]:
# Extract song/album title from URL or yt-dlp
m = re.search(r'/album/([^/]+)/(\d+)', url)
if m:
album_slug = m.group(1).replace("-", " ").title()
return [TrackMetadata(
service="apple",
service_id=url,
title=album_slug,
artist="Apple Music",
album=album_slug,
source_url=url
)]
return self._resolve_ytdlp(url)
def _resolve_ytdlp(self, url: str) -> List[TrackMetadata]:
tracks: List[TrackMetadata] = []
@@ -81,7 +108,7 @@ class UniversalProvider(BaseProvider):
uploader = entry.get("uploader") or entry.get("artist") or "Unknown"
tracks.append(TrackMetadata(
service="youtube",
service_id=entry.get("id", ""),
service_id=str(entry.get("id", "")),
title=title,
artist=uploader,
album=entry.get("album"),
@@ -103,7 +130,6 @@ class UniversalProvider(BaseProvider):
if track.is_explicit:
query += " explicit"
# Search and download best audio via yt-dlp
ydl_opts = {
"format": "bestaudio/best",
"outtmpl": dest_path + ".tmp.%(ext)s",
@@ -123,8 +149,6 @@ class UniversalProvider(BaseProvider):
ydl.download([target_input])
if os.path.exists(tmp_output):
# Apply high quality tags from metadata
import httpx
cover_bytes = None
if track.cover_url:
try:
+3 -4
View File
@@ -1,10 +1,9 @@
fastapi>=0.115.0
fastapi>=0.110.0
uvicorn[standard]>=0.30.0
pydantic>=2.9.0
pydantic-settings>=2.5.0
pydantic>=2.7.0
pydantic-settings>=2.4.0
yandex-music>=3.2.0
yt-dlp>=2024.10.0
spotdl>=4.2.0
mutagen>=1.47.0
syncedlyrics>=0.10.0
aiofiles>=24.1.0