import sqlite3 import tempfile import unittest from pathlib import Path from unittest.mock import patch from fastapi.testclient import TestClient from music_server.app import create_app from music_server.services.cache_service import CacheService from tests.support import auth_headers class MfMediaRouteTests(unittest.TestCase): def _prepare_catalog_db( self, db_path: Path, *, backend_type: str = "object_storage", backend_name: str = "main-s3", locator: str = "music/netease/test.flac", public_url: str | None = "https://cdn.example/test.flac", file_size_bytes: int = 42345678, ) -> None: conn = sqlite3.connect(db_path) conn.execute( """ create table catalog_track_files ( song_id integer not null, quality_label text not null, ext text not null, file_size_bytes integer not null, backend_type text not null, backend_name text not null, locator text not null, public_url text, status text not null, is_primary integer not null ) """ ) conn.execute( """ insert into catalog_track_files ( song_id, quality_label, ext, file_size_bytes, backend_type, backend_name, locator, public_url, status, is_primary ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( 3476, "super", "flac", file_size_bytes, backend_type, backend_name, locator, public_url, "active", 1, ), ) conn.commit() conn.close() def _prepare_active_cache( self, *, player_db_path: Path, catalog_db_path: Path, song_id: int = 3476, cache_url: str = "https://cache.example/test.flac", status: str = "active", ) -> None: service = CacheService( player_db_path=str(player_db_path), catalog_db_path=str(catalog_db_path), secret_encryption_key="test-secret", ) target = service.create_cache_target( name="edge-cache", kind="s3", order_index=1, capacity_songs=10, public_base_url="https://cache.example", path_prefix="songs", enabled=True, secrets={"bucket": "music", "region": "test"}, ) service.upsert_cache_object( song_id=song_id, target_id=target["id"], quality_label="super", source_locator="cache/test.flac", remote_key="songs/test.flac", public_url=cache_url, status=status, last_rank=1, uploaded_at="2026-04-23T00:00:00+00:00", last_verified_at="2026-04-23T00:00:00+00:00", evictable=False, ) def test_media_stream_extension_route_registers_before_generic_route(self): app = create_app() stream_paths = [ route.path for route in app.routes if getattr(route, "path", "").startswith("/mf/v1/media/stream/") ] self.assertEqual( [ "/mf/v1/media/stream/{token}.{ext}", "/mf/v1/media/stream/{token}", ], stream_paths, ) def test_media_resolve_returns_selected_source_and_signed_stream_url(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" self._prepare_catalog_db(db_path) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", }, clear=False, ): client = TestClient(create_app()) response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, response.status_code) payload = response.json() self.assertEqual("object_storage", payload["selected_source"]["kind"]) self.assertEqual("main-s3", payload["selected_source"]["backend"]) self.assertEqual("super", payload["selected_source"]["quality"]) self.assertEqual("flac", payload["selected_source"]["ext"]) self.assertEqual(42345678, payload["selected_source"]["size_bytes"]) self.assertIn("/mf/v1/media/stream/", payload["stream"]["url"]) self.assertTrue(payload["stream"]["url"].endswith(".flac")) def test_media_stream_redirects_to_public_url(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" self._prepare_catalog_db(db_path) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) stream_url = resolve_response.json()["stream"]["url"] stream_response = client.get( stream_url, follow_redirects=False, ) self.assertEqual(307, stream_response.status_code) self.assertEqual( "https://cdn.example/test.flac", stream_response.headers.get("location"), ) def test_media_resolve_prefers_active_cache_object(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" self._prepare_catalog_db(db_path) self._prepare_active_cache(player_db_path=player_db_path, catalog_db_path=db_path) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "MUSIC_SERVER_SECRET_ENCRYPTION_KEY": "test-secret", }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) self.assertEqual("cache", resolve_response.json()["selected_source"]["kind"]) with patch("music_server.routes.mf_media._is_cache_url_reachable", return_value=True): stream_response = client.get( resolve_response.json()["stream"]["url"], follow_redirects=False, ) self.assertEqual(307, stream_response.status_code) self.assertEqual( "https://cache.example/test.flac", stream_response.headers.get("location"), ) def test_media_resolve_falls_back_when_cache_object_is_not_active(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" self._prepare_catalog_db(db_path) self._prepare_active_cache( player_db_path=player_db_path, catalog_db_path=db_path, status="failed", ) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "MUSIC_SERVER_SECRET_ENCRYPTION_KEY": "test-secret", }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) self.assertEqual("object_storage", resolve_response.json()["selected_source"]["kind"]) stream_response = client.get( resolve_response.json()["stream"]["url"], follow_redirects=False, ) self.assertEqual(307, stream_response.status_code) self.assertEqual( "https://cdn.example/test.flac", stream_response.headers.get("location"), ) def test_media_resolve_and_stream_ignore_cache_when_cache_relay_disabled(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" self._prepare_catalog_db(db_path) self._prepare_active_cache(player_db_path=player_db_path, catalog_db_path=db_path) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "MUSIC_SERVER_SECRET_ENCRYPTION_KEY": "test-secret", "MUSIC_SERVER_CACHE_RELAY_ENABLED": "0", }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) self.assertEqual("object_storage", resolve_response.json()["selected_source"]["kind"]) with patch("music_server.routes.mf_media._is_cache_url_reachable", return_value=True): stream_response = client.get( resolve_response.json()["stream"]["url"], follow_redirects=False, ) heat_service = CacheService( player_db_path=str(player_db_path), catalog_db_path=str(db_path), secret_encryption_key="test-secret", ) summary = heat_service.get_heat_summary(song_id=3476) self.assertEqual(307, stream_response.status_code) self.assertEqual( "https://cdn.example/test.flac", stream_response.headers.get("location"), ) self.assertEqual(0, summary["play_count_total"]) self.assertEqual(0, summary["play_count_30d"]) def test_media_stream_falls_back_when_cached_public_url_is_unreachable(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" self._prepare_catalog_db(db_path) self._prepare_active_cache(player_db_path=player_db_path, catalog_db_path=db_path) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "MUSIC_SERVER_SECRET_ENCRYPTION_KEY": "test-secret", }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) with patch("music_server.routes.mf_media._is_cache_url_reachable", return_value=False): stream_response = client.get( resolve_response.json()["stream"]["url"], follow_redirects=False, ) self.assertEqual(307, stream_response.status_code) self.assertEqual( "https://cdn.example/test.flac", stream_response.headers.get("location"), ) def test_media_stream_falls_back_when_cached_public_url_is_unreachable(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" self._prepare_catalog_db(db_path) self._prepare_active_cache(player_db_path=player_db_path, catalog_db_path=db_path) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "MUSIC_SERVER_SECRET_ENCRYPTION_KEY": "test-secret", }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) with patch("music_server.routes.mf_media._is_cache_url_reachable", return_value=False): stream_response = client.get( resolve_response.json()["stream"]["url"], follow_redirects=False, ) self.assertEqual(307, stream_response.status_code) self.assertEqual( "https://cdn.example/test.flac", stream_response.headers.get("location"), ) def test_media_stream_serves_local_file_when_public_url_missing(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" library_root = Path(tmpdir) / "library" local_file = library_root / "music" / "netease" / "test.flac" local_file.parent.mkdir(parents=True, exist_ok=True) local_file.write_bytes(b"flac-bytes") self._prepare_catalog_db( db_path, backend_type="local_fs", backend_name="default-local", locator="music/netease/test.flac", public_url=None, file_size_bytes=10, ) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "LOCAL_LIBRARY_ROOT": str(library_root), }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) stream_url = resolve_response.json()["stream"]["url"] stream_response = client.get(stream_url) self.assertEqual(200, stream_response.status_code) self.assertEqual(b"flac-bytes", stream_response.content) self.assertEqual("bytes", stream_response.headers.get("accept-ranges")) self.assertEqual("10", stream_response.headers.get("content-length")) self.assertEqual("audio/flac", stream_response.headers.get("content-type")) def test_media_stream_local_single_range_returns_206_and_partial_content(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" library_root = Path(tmpdir) / "library" local_file = library_root / "music" / "netease" / "test.flac" local_file.parent.mkdir(parents=True, exist_ok=True) local_file.write_bytes(b"0123456789") self._prepare_catalog_db( db_path, backend_type="local_fs", backend_name="default-local", locator="music/netease/test.flac", public_url=None, file_size_bytes=10, ) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "LOCAL_LIBRARY_ROOT": str(library_root), }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) stream_url = resolve_response.json()["stream"]["url"] stream_response = client.get(stream_url, headers={"Range": "bytes=2-5"}) self.assertEqual(206, stream_response.status_code) self.assertEqual(b"2345", stream_response.content) self.assertEqual("bytes", stream_response.headers.get("accept-ranges")) self.assertEqual("bytes 2-5/10", stream_response.headers.get("content-range")) self.assertEqual("4", stream_response.headers.get("content-length")) self.assertEqual("audio/flac", stream_response.headers.get("content-type")) def test_media_stream_local_invalid_range_returns_416(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" library_root = Path(tmpdir) / "library" local_file = library_root / "music" / "netease" / "test.flac" local_file.parent.mkdir(parents=True, exist_ok=True) local_file.write_bytes(b"0123456789") self._prepare_catalog_db( db_path, backend_type="local_fs", backend_name="default-local", locator="music/netease/test.flac", public_url=None, file_size_bytes=10, ) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "LOCAL_LIBRARY_ROOT": str(library_root), }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) stream_url = resolve_response.json()["stream"]["url"] stream_response = client.get(stream_url, headers={"Range": "bytes=99-100"}) self.assertEqual(416, stream_response.status_code) self.assertEqual("bytes", stream_response.headers.get("accept-ranges")) self.assertEqual("bytes */10", stream_response.headers.get("content-range")) def test_media_stream_counts_heat_once_for_repeated_stream_requests(self): with tempfile.TemporaryDirectory() as tmpdir: db_path = Path(tmpdir) / "catalog_read.db" player_db_path = Path(tmpdir) / "player.db" library_root = Path(tmpdir) / "library" local_file = library_root / "music" / "netease" / "test.flac" local_file.parent.mkdir(parents=True, exist_ok=True) local_file.write_bytes(b"0123456789") self._prepare_catalog_db( db_path, backend_type="local_fs", backend_name="default-local", locator="music/netease/test.flac", public_url=None, file_size_bytes=10, ) with patch.dict( "os.environ", { "CATALOG_DB_PATH": str(db_path), "PLAYER_DB_PATH": str(player_db_path), "PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token", "LOCAL_LIBRARY_ROOT": str(library_root), "MUSIC_SERVER_SECRET_ENCRYPTION_KEY": "test-secret", }, clear=False, ): client = TestClient(create_app()) resolve_response = client.post( "/mf/v1/media/resolve", headers=auth_headers(player_db_path), json={"song_id": "catalogsync:song:3476", "quality": "super"}, ) self.assertEqual(200, resolve_response.status_code) stream_url = resolve_response.json()["stream"]["url"] full_response = client.get(stream_url) range_response = client.get(stream_url, headers={"Range": "bytes=2-5"}) heat_service = CacheService( player_db_path=str(player_db_path), catalog_db_path=str(db_path), secret_encryption_key="test-secret", ) summary = heat_service.get_heat_summary(song_id=3476) self.assertEqual(200, full_response.status_code) self.assertEqual(206, range_response.status_code) self.assertEqual(1, summary["play_count_total"]) self.assertEqual(1, summary["play_count_30d"]) if __name__ == "__main__": unittest.main()