feat(music-server): expose topn tracks endpoint

This commit is contained in:
2026-07-17 11:42:28 +08:00
parent 069af30dba
commit 4eea6ef8c9
4 changed files with 183 additions and 3 deletions
@@ -26,6 +26,19 @@ class PlayerHistoryRouteTests(unittest.TestCase):
playlist_id integer primary key,
added_at text not null
);
create table song_heat_summary (
song_id integer primary key,
play_count_total integer not null default 0,
play_count_30d integer not null default 0,
last_played_at text
);
insert into song_heat_summary (
song_id, play_count_total, play_count_30d, last_played_at
) values
(42, 8, 5, '2026-07-16T10:00:00+00:00'),
(7, 12, 9, '2026-07-16T11:00:00+00:00');
"""
)
conn.commit()
@@ -66,6 +79,44 @@ class PlayerHistoryRouteTests(unittest.TestCase):
1,
),
)
conn.executescript(
"""
create table catalog_tracks (
song_id integer primary key,
platform text not null,
remote_track_id text not null,
name text not null,
singers text,
album text,
cover_url text,
duration_ms integer not null
);
create table catalog_track_files (
id integer primary key autoincrement,
song_id integer not null,
quality_label text,
backend_type text not null,
backend_name text,
locator text not null,
public_url text,
status text not null,
is_primary integer not null default 0
);
insert into catalog_tracks (
song_id, platform, remote_track_id, name, singers, album, cover_url, duration_ms
) values
(42, 'kuwo', '42', '热门歌曲二', '歌手乙', '专辑乙', 'https://img/42.jpg', 242000),
(7, 'qq', '7', '热门歌曲一', '歌手甲', '专辑甲', 'https://img/7.jpg', 198000);
insert into catalog_track_files (
song_id, quality_label, backend_type, backend_name, locator, public_url, status, is_primary
) values
(42, 'lossless', 'local_fs', 'default-local', 'kuwo/42.flac', null, 'active', 1),
(7, 'high', 'local_fs', 'default-local', 'qq/7.mp3', null, 'active', 1);
"""
)
conn.commit()
conn.close()
@@ -140,6 +191,37 @@ class PlayerHistoryRouteTests(unittest.TestCase):
self.assertEqual(400, invalid_track_id.status_code)
self.assertEqual(400, invalid_progress.status_code)
def test_topn_returns_playable_tracks_in_heat_order(self):
with tempfile.TemporaryDirectory() as tmpdir:
player_db_path = Path(tmpdir) / "player.db"
catalog_db_path = Path(tmpdir) / "catalog_read.db"
self._prepare_player_db(player_db_path)
self._prepare_catalog_db(catalog_db_path)
with patch.dict(
"os.environ",
{
"PLAYER_DB_PATH": str(player_db_path),
"CATALOG_DB_PATH": str(catalog_db_path),
},
clear=False,
):
response = TestClient(create_app()).get(
"/player/v1/topn?limit=2",
headers=auth_headers(player_db_path),
)
self.assertEqual(200, response.status_code)
payload = response.json()
self.assertEqual(30, payload["periodDays"])
self.assertEqual(
["catalogsync:song:7", "catalogsync:song:42"],
[item["id"] for item in payload["musicList"]],
)
self.assertEqual([1, 2], [item["rank"] for item in payload["musicList"]])
self.assertEqual([9, 5], [item["playCount30d"] for item in payload["musicList"]])
self.assertEqual("歌手甲", payload["musicList"][0]["artist"])
if __name__ == "__main__":
unittest.main()