feat: get precise music title via bilibili API#68
Conversation
WalkthroughThe changes implement a feature to fetch precise music metadata from Bilibili videos using their BGM recognition API, then use this metadata for more accurate lyric searching. New API and query endpoints are added, the lyric service is enhanced with bilibili-specific orchestration, and a UI button enables cache clearing. Changes
Sequence DiagramsequenceDiagram
participant UI as Test Page
participant Service as LyricService
participant API as BilibiliAPI
participant FS as File System
rect rgb(230, 245, 255)
Note over UI,FS: Bilibili BGM-based Lyric Search Flow
UI->>Service: smartFetchLyrics(bilibiliTrack)
alt track has bvid & cid
Service->>API: getWebPlayerInfo(bvid, cid)
API-->>Service: BilibiliWebPlayerInfo
Service->>Service: getPreciseMusicNameOnBilibiliVideo(bgm_info)
Service->>Service: getBestMatchedLyrics(track, preciseName)
Service->>FS: Fetch lyrics with precise keyword
FS-->>Service: Lyrics data
Service->>FS: Write results to cache
else fallback
Service->>Service: getBestMatchedLyrics(track)
end
Service-->>UI: Lyrics result
end
rect rgb(255, 240, 245)
Note over UI,FS: Clear Cache Flow
UI->>Service: clearAllLyrics()
Service->>FS: Remove all cache entries
FS-->>Service: Success/Failure
Service-->>UI: Result with toast
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (8)
CHANGELOG.md (1)
8-14: Polish: Keep-a-Changelog casing and acronym
- Prefer "Unreleased" (canonical casing).
- Uppercase the acronym “BGM”.
Apply:
-## [UNRELEASED] +## [Unreleased] @@ -- 基于 B 站视频 bgm 识别结果精准搜索歌词 +- 基于 B 站视频 BGM 识别结果精准搜索歌词src/types/apis/bilibili.ts (1)
346-352: Type safety: allow null and document shape
- bgm_info can be absent or null; reflect that in the type.
- Please verify whether the client unwraps
dataso thatbgm_infois indeed top-level here.Apply:
-interface BilibiliWebPlayerInfo { - bgm_info?: { +interface BilibiliWebPlayerInfo { + bgm_info?: ({ music_id: number music_title: string jump_url: string - } + } | null) }To confirm the response shape, please check the endpoint’s latest payload (fields and nesting) as Bilibili responses often differ between app/web variants.
Also applies to: 375-376
src/app/test/test.tsx (1)
116-142: Typo: rename clearAllLyrcis → clearAllLyrics for consistencyKeeps naming aligned with lyricService.clearAllLyrics() and avoids confusion.
- const clearAllLyrcis = () => { + const clearAllLyrics = () => { @@ - onPress: clearAction, + onPress: clearAction, @@ - onPress={clearAllLyrcis} + onPress={clearAllLyrics}Also applies to: 188-195
src/lib/api/bilibili/api.ts (1)
752-769: New API looks good; consider cancellation support and verify payload
- Implementation aligns with existing WBI calls. LGTM.
- Optional: accept an AbortSignal to enable query cancellation, similar to getSearchSuggestions.
- Please verify that
/x/player/wbi/v2returns the exact shape modeled byBilibiliWebPlayerInfo(esp.bgm_infonesting).src/hooks/queries/bilibili/video.ts (1)
58-73: Return just what callers need via selectIf consumers only care about the song metadata, select it here to minimize rerenders and downstream null checks.
return useQuery({ queryKey: videoDataQueryKeys.getWebPlayerInfo(bvid, cid), queryFn: () => returnOrThrowAsync(bilibiliApi.getWebPlayerInfo(bvid!, cid!)), enabled, staleTime: 5 * 60 * 1000, + select: (data) => data.bgm_info ?? null, })src/lib/services/lyricService.ts (3)
96-111: Bilibili-first branch looks sound; minor simplificationYou can drop fromSafePromise here since getPreciseMusicNameOnBilibiliVideo never throws and always resolves to string | undefined.
- return ResultAsync.fromSafePromise( - this.getPreciseMusicNameOnBilibiliVideo(track.bilibiliMetadata), - ) + return ResultAsync.fromPromise( + this.getPreciseMusicNameOnBilibiliVideo(track.bilibiliMetadata), + (e) => e as Error, + )
212-233: Reuse cleanKeyword for normalization and guard against missing titleSimpler and more robust than a single-pattern regex.
- .andThen((res) => { - if (!res.bgm_info) return errAsync(new Error('没有获取到歌曲信息')) - const filteredResult = /《(.+?)》/.exec(res.bgm_info.music_title) - logger.debug('从 bilibili 获取到的该视频中识别到的歌曲名', { - music_title: res.bgm_info.music_title, - }) - if (filteredResult?.[1]) { - return okAsync(filteredResult[1]) - } - return okAsync(res.bgm_info.music_title) - }) + .andThen((res) => { + const title = res.bgm_info?.music_title + if (!title) return errAsync(new Error('没有获取到歌曲信息')) + logger.debug('从 bilibili 获取到的该视频中识别到的歌曲名', { music_title: title }) + return okAsync(this.cleanKeyword(title)) + })
235-258: clearAllLyrics: behavior is fine; optional telemetryConsider emitting a metric (count of files removed) to aid support.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
CHANGELOG.md(1 hunks)src/app/test/test.tsx(3 hunks)src/hooks/queries/bilibili/video.ts(2 hunks)src/lib/api/bilibili/api.ts(2 hunks)src/lib/services/lyricService.ts(4 hunks)src/types/apis/bilibili.ts(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/app/test/test.tsx (1)
src/components/modals/AlertModal.tsx (1)
alert(72-85)
src/hooks/queries/bilibili/video.ts (2)
src/utils/neverthrow-utils.ts (1)
returnOrThrowAsync(8-21)src/lib/api/bilibili/api.ts (1)
bilibiliApi(772-772)
src/lib/api/bilibili/api.ts (3)
src/types/apis/bilibili.ts (1)
BilibiliWebPlayerInfo(375-375)src/lib/api/bilibili/wbi.ts (1)
getWbiEncodedParams(123-128)src/lib/api/bilibili/client.ts (1)
bilibiliApiClient(145-145)
src/lib/services/lyricService.ts (2)
src/types/core/media.ts (2)
Track(63-63)BilibiliTrack(38-54)src/lib/api/bilibili/api.ts (1)
bilibiliApi(772-772)
🔇 Additional comments (1)
src/lib/services/lyricService.ts (1)
41-53: Optional parameter is backward-compatible; random selection is a known pre-existing issueBoth callers work correctly:
- Line 104: Passes
musicNamefrom bilibili metadata extraction- Line 112: Omits second argument, using default behavior
Random selection at lines 56-57 (with FIXME comment) is pre-existing, not introduced in this change. Flag for follow-up refactor to truly implement "best matched" semantics rather than random selection.
Closes #67
Summary by CodeRabbit