- Remove committed .coverage and test-results/ (196K screenshots); gitignore them - Fix hardcoded /home/userpath + venv/bin/python in test_endpoints.py (relative backend dir + sys.executable) - Fix concatenated 'import json' in settings.py; bare excepts -> Exception; SQLAlchemy-safe is_active.is_(True); __all__ on models/schemas barrels - ruff clean (93 fixes), MIT LICENSE, PLAN.md -> docs/, README Tests section - 300 tests pass, 93.7% coverage
91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
from fastapi import APIRouter, Depends
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Optional
|
|
from ..db.database import get_db
|
|
from ..models.song import Song
|
|
from ..schemas.releases import NewReleaseResponse
|
|
from ..services.musicbrainz import search_artist, get_artist_releases
|
|
|
|
router = APIRouter(prefix="/api/releases", tags=["releases"])
|
|
|
|
|
|
@router.get("", response_model=List[NewReleaseResponse])
|
|
def check_releases(artist: Optional[str] = None, db: Session = Depends(get_db)):
|
|
if artist:
|
|
artist_data = search_artist(artist)
|
|
if not artist_data:
|
|
return []
|
|
|
|
releases = get_artist_releases(artist_data["id"])
|
|
return [NewReleaseResponse(
|
|
artist_name=artist_data["name"],
|
|
albums=[{"id": r["id"], "title": r["title"], "cover_art": r.get("cover_art"), "release_date": r["release_date"], "tracks": r["tracks"]} for r in releases],
|
|
)]
|
|
|
|
# Check all unique artists in library
|
|
artists = db.query(Song.artist).distinct().all()
|
|
results = []
|
|
|
|
for (artist_name,) in artists[:10]:
|
|
artist_data = search_artist(artist_name)
|
|
if artist_data:
|
|
releases = get_artist_releases(artist_data["id"], limit=3)
|
|
if releases:
|
|
results.append(NewReleaseResponse(
|
|
artist_name=artist_data["name"],
|
|
albums=[{"id": r["id"], "title": r["title"], "cover_art": r.get("cover_art"), "release_date": r["release_date"], "tracks": r["tracks"]} for r in releases],
|
|
))
|
|
|
|
return results
|
|
|
|
|
|
@router.get("/{artist}")
|
|
def check_artist_releases(artist: str, db: Session = Depends(get_db)):
|
|
artist_data = search_artist(artist)
|
|
if not artist_data:
|
|
return []
|
|
|
|
releases = get_artist_releases(artist_data["id"])
|
|
return NewReleaseResponse(
|
|
artist_name=artist_data["name"],
|
|
albums=[{"id": r["id"], "title": r["title"], "cover_art": r.get("cover_art"), "release_date": r["release_date"], "tracks": r["tracks"]} for r in releases],
|
|
)
|
|
|
|
|
|
@router.post("/add")
|
|
def add_release_to_playlist(artist: str, album_id: str, playlist_id: str, db: Session = Depends(get_db)):
|
|
from ..models.playlist import Playlist, PlaylistSong
|
|
|
|
playlist = db.query(Playlist).filter(Playlist.id == playlist_id).first()
|
|
if not playlist:
|
|
return {"error": "Playlist not found"}
|
|
|
|
artist_data = search_artist(artist)
|
|
if not artist_data:
|
|
return {"error": "Artist not found"}
|
|
|
|
releases = get_artist_releases(artist_data["id"])
|
|
album = next((r for r in releases if r["id"] == album_id), None)
|
|
if not album:
|
|
return {"error": "Album not found"}
|
|
|
|
added = 0
|
|
for track in album["tracks"]:
|
|
existing = db.query(Song).filter(Song.title == track["title"], Song.artist == artist).first()
|
|
if not existing:
|
|
import uuid
|
|
song = Song(
|
|
id=str(uuid.uuid4()),
|
|
title=track["title"],
|
|
artist=artist,
|
|
duration_sec=track["duration"],
|
|
)
|
|
db.add(song)
|
|
existing = song
|
|
added += 1
|
|
|
|
ps = PlaylistSong(playlist_id=playlist_id, song_id=existing.id, position=added)
|
|
db.add(ps)
|
|
|
|
db.commit()
|
|
return {"added": added, "playlist_id": playlist_id} |