Files
teamspeak-music-bot/web/src/views/Artist.layout.test.ts
T
zzstar101 b6ad536bb7 feat(web): artist search, artist pages, and full-catalogue playback
Adds artist support for the NetEase and QQ providers plus the matching UI.

Backend:
- SearchResult gains `artists`; new optional MusicProvider methods
  getArtistDetail / getArtistSongs / getArtistAlbums / getArtistAllSongs.
- NetEase: /cloudsearch type=100 for artist search, /artists, /artist/songs,
  /artist/album and /artist/desc for the artist page.
- QQ: singer search rides along in the existing musicu.fcg batch
  (search_type=1); singer detail via music.web_singer_info_svr. QQ exposes no
  working singer-song paging endpoint, so the full catalogue is built from the
  hot 50 plus every album of the singer (album search filtered by singerMID,
  songs fetched per album, de-duplicated, cached for 10 minutes). A failed
  album sweep is never cached and degrades to the hot list.
- API: GET /api/music/artist/:id and POST /api/player/:botId/play-artist
  (player.control capability, guest flag playCollection); /search/all now
  aggregates artists too.

Frontend:
- Search history in localStorage (max 10, per platform, never shared between
  users), shown as a dropdown under the search box and as 最近搜索 chips.
- Artist row in the search results; new /artist/:id page (portrait, aliases,
  stats, description, top songs, album shelf) with 播放 / 随机播放, which queue
  the singer's whole catalogue.
- playArtist store action.

Tests cover the provider mappers, the new routes, the play-artist collector
(paging, de-duplication, 500-track cap), permission gating and the new views.
2026-10-02 01:36:03 +08:00

43 lines
1.4 KiB
TypeScript

import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
import { describe, expect, it } from "vitest";
const currentDir = dirname(fileURLToPath(import.meta.url));
const source = () => readFileSync(join(currentDir, "Artist.vue"), "utf8");
describe("Artist page layout", () => {
it("has no 全部歌曲 browser section (play buttons queue the catalogue instead)", () => {
const src = source();
expect(src).not.toContain("全部歌曲</h2>");
expect(src).not.toContain("加载更多");
expect(src).not.toContain("加载全部歌曲");
expect(src).not.toContain("ALL_SONGS_PAGE");
expect(src).not.toContain("loadMoreSongs");
expect(src).not.toContain("allSongs");
});
it("keeps the hot songs and album sections", () => {
const src = source();
expect(src).toContain("热门歌曲");
expect(src).toContain("专辑");
expect(src).toContain("显示全部");
});
it("plays through playArtist without an all flag (the server always loads everything)", () => {
const src = source();
expect(src).toContain("store.playArtist(artistId(), platform.value)");
expect(src).not.toContain("playArtist(artistId(), platform.value, true)");
});
it("refetches when navigating between artists", () => {
const src = source();
expect(src).toContain("watch(");
expect(src).toContain("route.params.id");
});
});