feat: add lyrics source tracking, Paxsenix partner, and dedicated lyrics provider settings page

- Add getLyricsLRCWithSource to return lyrics with source metadata
- Display lyrics source in track metadata screen
- Improve LRC parsing to preserve background vocal tags
- Add dedicated LyricsProviderPriorityPage for provider configuration
- Add Paxsenix as lyrics proxy partner for Apple Music/QQ Music
- Handle inline timestamps and speaker prefixes in LRC display
This commit is contained in:
zarzet
2026-02-14 02:15:36 +07:00
parent 30973a8e78
commit f4934dcb28
12 changed files with 803 additions and 200 deletions
+58
View File
@@ -1008,6 +1008,64 @@ func GetLyricsLRC(spotifyID, trackName, artistName string, filePath string, dura
return lrcContent, nil
}
func GetLyricsLRCWithSource(spotifyID, trackName, artistName string, filePath string, durationMs int64) (string, error) {
if filePath != "" {
lyrics, err := ExtractLyrics(filePath)
if err == nil && lyrics != "" {
result := map[string]interface{}{
"lyrics": lyrics,
"source": "Embedded",
"sync_type": "EMBEDDED",
"instrumental": false,
}
jsonBytes, err := json.Marshal(result)
if err != nil {
return "", err
}
return string(jsonBytes), nil
}
result := map[string]interface{}{
"lyrics": "",
"source": "",
"sync_type": "",
"instrumental": false,
}
jsonBytes, err := json.Marshal(result)
if err != nil {
return "", err
}
return string(jsonBytes), nil
}
client := NewLyricsClient()
durationSec := float64(durationMs) / 1000.0
lyricsData, err := client.FetchLyricsAllSources(spotifyID, trackName, artistName, durationSec)
if err != nil {
return "", err
}
lrcContent := ""
if lyricsData.Instrumental {
lrcContent = "[instrumental:true]"
} else {
lrcContent = convertToLRCWithMetadata(lyricsData, trackName, artistName)
}
result := map[string]interface{}{
"lyrics": lrcContent,
"source": lyricsData.Source,
"sync_type": lyricsData.SyncType,
"instrumental": lyricsData.Instrumental,
}
jsonBytes, err := json.Marshal(result)
if err != nil {
return "", err
}
return string(jsonBytes), nil
}
func EmbedLyricsToFile(filePath, lyrics string) (string, error) {
err := EmbedLyrics(filePath, lyrics)
if err != nil {
+7
View File
@@ -608,6 +608,13 @@ func parseSyncedLyrics(syncedLyrics string) []LyricsLine {
continue
}
// Preserve Apple/QQ background vocal tags by attaching them to
// the previous timed line. This keeps [bg:...] in final exported LRC.
if strings.HasPrefix(line, "[bg:") && len(lines) > 0 {
lines[len(lines)-1].Words = strings.TrimSpace(lines[len(lines)-1].Words + "\n" + line)
continue
}
matches := lrcPattern.FindStringSubmatch(line)
if len(matches) == 5 {
startMs := lrcTimestampToMs(matches[1], matches[2], matches[3])
+1 -1
View File
@@ -289,7 +289,7 @@ func formatPaxContent(lyricsType string, content []paxLyrics, multiPersonWordByW
timestamp := msToLRCTimestamp(int64(line.Timestamp))
if lyricsType == "Syllable" {
if strings.EqualFold(lyricsType, "Syllable") {
sb.WriteString(timestamp)
if multiPersonWordByWord {
if line.OppositeTurn {