-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat(lyric): 添加云盘音乐歌词支持 #1022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
feat(lyric): 添加云盘音乐歌词支持 #1022
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,8 +1,15 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { qqMusicMatch } from "@/api/qqmusic"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { cloudSongLyric } from "@/api/cloud"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { songLyric, songLyricTTML } from "@/api/song"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { keywords as defaultKeywords, regexes as defaultRegexes } from "@/assets/data/exclude"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCacheManager } from "@/core/resource/CacheManager"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useMusicStore, useSettingStore, useStatusStore, useStreamingStore } from "@/stores"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| useDataStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| useMusicStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| useSettingStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| useStatusStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| useStreamingStore, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "@/stores"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { LyricPriority, SongLyric } from "@/types/lyric"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { SongType } from "@/types/main"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { isElectron } from "@/utils/env"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -75,7 +82,10 @@ class LyricManager { | |||||||||||||||||||||||||||||||||||||||||||||||||
| * @param type 缓存类型 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns 缓存数据 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| private async getRawLyricCache(id: number, type: "lrc" | "ttml" | "qrc"): Promise<string | null> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| private async getRawLyricCache( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id: number | string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| type: "lrc" | "ttml" | "qrc", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<string | null> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const settingStore = useSettingStore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isElectron || !settingStore.cacheEnabled) return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -99,7 +109,11 @@ class LyricManager { | |||||||||||||||||||||||||||||||||||||||||||||||||
| * @param type 缓存类型 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param data 数据 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| private async saveRawLyricCache(id: number, type: "lrc" | "ttml" | "qrc", data: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| private async saveRawLyricCache( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id: number | string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| type: "lrc" | "ttml" | "qrc", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| data: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const settingStore = useSettingStore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isElectron || !settingStore.cacheEnabled) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -304,8 +318,11 @@ class LyricManager { | |||||||||||||||||||||||||||||||||||||||||||||||||
| if (qqMusicAdopted && result.yrcData.length > 0) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof id !== "number") return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const dataStore = useDataStore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const userId = dataStore.userData.userId; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const lyricCacheKey = song.pc && userId ? `cloud_${userId}_${id}` : id; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let data: any = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await this.getRawLyricCache(id, "lrc"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await this.getRawLyricCache(lyricCacheKey, "lrc"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (cached) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| data = JSON.parse(cached); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -314,33 +331,60 @@ class LyricManager { | |||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!data) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| data = await songLyric(id); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (song.pc && userId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| data = await cloudSongLyric(id, userId); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!data) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| data = await songLyric(id); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data && data.code === 200) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.saveRawLyricCache(id, "lrc", JSON.stringify(data)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.saveRawLyricCache(lyricCacheKey, "lrc", JSON.stringify(data)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
333
to
343
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fallback logic for cloud song lyrics is incorrect. If
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!data || data.code !== 200) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
333
to
344
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| let lrcLines: LyricLine[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let yrcLines: LyricLine[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const getLyricText = (lyric: unknown): string => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof lyric === "string") return lyric; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| lyric && | ||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof lyric === "object" && | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "lyric" in lyric && | ||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof lyric.lyric === "string" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return lyric.lyric; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const lrcContent = getLyricText(data?.lrc); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const tlyricContent = getLyricText(data?.tlyric); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const romalrcContent = getLyricText(data?.romalrc); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const yrcContent = getLyricText(data?.yrc); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const ytlrcContent = getLyricText(data?.ytlrc); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const yromalrcContent = getLyricText(data?.yromalrc); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 普通歌词 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data?.lrc?.lyric) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| lrcLines = parseLrc(data.lrc.lyric) || []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (lrcContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| lrcLines = parseLrc(lrcContent) || []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 普通歌词翻译 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data?.tlyric?.lyric) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| lrcLines = alignLyrics(lrcLines, parseLrc(data.tlyric.lyric), "translatedLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (tlyricContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| lrcLines = alignLyrics(lrcLines, parseLrc(tlyricContent), "translatedLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 普通歌词音译 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data?.romalrc?.lyric) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| lrcLines = alignLyrics(lrcLines, parseLrc(data.romalrc.lyric), "romanLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (romalrcContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| lrcLines = alignLyrics(lrcLines, parseLrc(romalrcContent), "romanLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 逐字歌词 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data?.yrc?.lyric) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| yrcLines = parseYrc(data.yrc.lyric) || []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (yrcContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| yrcLines = parseYrc(yrcContent) || []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 逐字歌词翻译 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data?.ytlrc?.lyric) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| yrcLines = alignLyrics(yrcLines, parseLrc(data.ytlrc.lyric), "translatedLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (ytlrcContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| yrcLines = alignLyrics(yrcLines, parseLrc(ytlrcContent), "translatedLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 逐字歌词音译 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data?.yromalrc?.lyric) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| yrcLines = alignLyrics(yrcLines, parseLrc(data.yromalrc.lyric), "romanLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (yromalrcContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| yrcLines = alignLyrics(yrcLines, parseLrc(yromalrcContent), "romanLyric"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (lrcLines.length) result.lrcData = lrcLines; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // 如果没有 TTML 且没有 QM YRC,则采用 网易云 YRC | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cloudSongLyric 的参数顺序是 (sid, uid),但同文件的 matchCloudSong 是 (uid, sid, asid)。这种不一致很容易在后续调用时传参写反;建议统一为 (uid, sid) 或改为接收一个对象参数(如 { uid, sid })以提升可读性并减少误用风险。