From 11d34f36016b08501f3ec2717acc7e9a1798d392 Mon Sep 17 00:00:00 2001 From: zhaarey <157944548+zhaarey@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:57:47 +0800 Subject: [PATCH] add lrc-format --- README.md | 1 + config.yaml | 1 + main.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 069872a..5e220e4 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ 9. 支持下载歌手 `go run main.go https://music.apple.com/us/artist/taylor-swift/159260351` `--all-album` 自动选择歌手的所有专辑 10. 新增[wrapper](https://github.com/zhaarey/wrapper/releases)模式 目前只能linux运行,解密速度超快,基本秒解 11. `limit-max`支持限制长度 默认200 +12. 支持逐词与未同步歌词 本项目仅支持ALAC和Atmos - `alac (audio-alac-stereo)` diff --git a/config.yaml b/config.yaml index cf796d2..d2fce03 100644 --- a/config.yaml +++ b/config.yaml @@ -1,6 +1,7 @@ media-user-token: "your-media-user-token" embed-lrc: true save-lrc-file: false +lrc-format: "lyrics" #lyrics syllable-lyrics save-artist-cover: false save-animated-artwork: false # If enabled, requires ffmpeg emby-animated-artwork: false # If enabled, requires ffmpeg diff --git a/main.go b/main.go index 92a3efa..12bd09e 100644 --- a/main.go +++ b/main.go @@ -44,6 +44,7 @@ var artist_select = false type Config struct { MediaUserToken string `yaml:"media-user-token"` SaveLrcFile bool `yaml:"save-lrc-file"` + LrcFormat string `yaml:"lrc-format"` SaveAnimatedArtwork bool `yaml:"save-animated-artwork"` EmbyAnimatedArtwork bool `yaml:"emby-animated-artwork"` EmbedLrc bool `yaml:"embed-lrc"` @@ -1258,7 +1259,7 @@ func getMeta(albumId string, token string, storefront string) (*AutoGenerated, e func getSongLyrics(songId string, storefront string, token string, userToken string) (string, error) { req, err := http.NewRequest("GET", - fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/songs/%s/lyrics", storefront, songId), nil) + fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/songs/%s/%s", storefront, songId, config.LrcFormat), nil) if err != nil { return "", err } @@ -1826,13 +1827,95 @@ func main() { fmt.Printf("======= Completed %d/%d ###### %d errors!! =======\n", oktrackNum, trackTotalnum, trackTotalnum-oktrackNum) } +func conventSyllableTTMLToLRC(ttml string) (string, error) { + parsedTTML := etree.NewDocument() + err := parsedTTML.ReadFromString(ttml) + if err != nil { + return "", err + } + var lrcLines []string + parseTime := func(timeValue string) (string, error) { + var h, m, s, ms int + if strings.Contains(timeValue, ":") { + _, err = fmt.Sscanf(timeValue, "%d:%d:%d.%d", &h, &m, &s, &ms) + if err != nil { + _, err = fmt.Sscanf(timeValue, "%d:%d.%d", &m, &s, &ms) + h = 0 + } + } else { + _, err = fmt.Sscanf(timeValue, "%d.%d", &s, &ms) + h, m = 0, 0 + } + if err != nil { + return "", err + } + m += h * 60 + ms = ms / 10 + return fmt.Sprintf("[%02d:%02d.%02d]", m, s, ms), nil + } + for _, div := range parsedTTML.FindElement("tt").FindElement("body").FindElements("div") { + for _, item := range div.ChildElements() { + var lrcSyllables []string + for _, lyric := range item.ChildElements() { + if lyric.SelectAttr("begin") == nil { + continue + } + beginTime, err := parseTime(lyric.SelectAttr("begin").Value) + if err != nil { + return "", err + } + var text string + if lyric.SelectAttr("text") == nil { + var textTmp []string + for _, span := range lyric.Child { + if _, ok := span.(*etree.CharData); ok { + textTmp = append(textTmp, span.(*etree.CharData).Data) + } else { + textTmp = append(textTmp, span.(*etree.Element).Text()) + } + } + text = strings.Join(textTmp, "") + } else { + text = lyric.SelectAttr("text").Value + } + lrcSyllables = append(lrcSyllables, fmt.Sprintf("%s%s", beginTime, text)) + } + endTime, err := parseTime(item.SelectAttr("end").Value) + if err != nil { + return "", err + } + lrcLines = append(lrcLines, strings.Join(lrcSyllables, "")+endTime) + } + } + return strings.Join(lrcLines, "\n"), nil +} + func conventTTMLToLRC(ttml string) (string, error) { parsedTTML := etree.NewDocument() err := parsedTTML.ReadFromString(ttml) if err != nil { return "", err } + var lrcLines []string + timingAttr := parsedTTML.FindElement("tt").SelectAttr("itunes:timing") + if timingAttr != nil { + if timingAttr.Value == "Word" { + lrc, err := conventSyllableTTMLToLRC(ttml) + return lrc, err + } + if timingAttr.Value == "None" { + for _, p := range parsedTTML.FindElements("//p") { + line := p.Text() + line = strings.TrimSpace(line) + if line != "" { + lrcLines = append(lrcLines, line) + } + } + return strings.Join(lrcLines, "\n"), nil + } + } + for _, item := range parsedTTML.FindElement("tt").FindElement("body").ChildElements() { for _, lyric := range item.ChildElements() { var h, m, s, ms int