add lrc-format

pull/27/head
zhaarey 3 months ago
parent 78ebfc9b74
commit 11d34f3601
  1. 1
      README.md
  2. 1
      config.yaml
  3. 85
      main.go

@ -12,6 +12,7 @@
9. 支持下载歌手 `go run main.go https://music.apple.com/us/artist/taylor-swift/159260351` `--all-album` 自动选择歌手的所有专辑 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运行,解密速度超快,基本秒解 10. 新增[wrapper](https://github.com/zhaarey/wrapper/releases)模式 目前只能linux运行,解密速度超快,基本秒解
11. `limit-max`支持限制长度 默认200 11. `limit-max`支持限制长度 默认200
12. 支持逐词与未同步歌词
本项目仅支持ALAC和Atmos 本项目仅支持ALAC和Atmos
- `alac (audio-alac-stereo)` - `alac (audio-alac-stereo)`

@ -1,6 +1,7 @@
media-user-token: "your-media-user-token" media-user-token: "your-media-user-token"
embed-lrc: true embed-lrc: true
save-lrc-file: false save-lrc-file: false
lrc-format: "lyrics" #lyrics syllable-lyrics
save-artist-cover: false save-artist-cover: false
save-animated-artwork: false # If enabled, requires ffmpeg save-animated-artwork: false # If enabled, requires ffmpeg
emby-animated-artwork: false # If enabled, requires ffmpeg emby-animated-artwork: false # If enabled, requires ffmpeg

@ -44,6 +44,7 @@ var artist_select = false
type Config struct { type Config struct {
MediaUserToken string `yaml:"media-user-token"` MediaUserToken string `yaml:"media-user-token"`
SaveLrcFile bool `yaml:"save-lrc-file"` SaveLrcFile bool `yaml:"save-lrc-file"`
LrcFormat string `yaml:"lrc-format"`
SaveAnimatedArtwork bool `yaml:"save-animated-artwork"` SaveAnimatedArtwork bool `yaml:"save-animated-artwork"`
EmbyAnimatedArtwork bool `yaml:"emby-animated-artwork"` EmbyAnimatedArtwork bool `yaml:"emby-animated-artwork"`
EmbedLrc bool `yaml:"embed-lrc"` 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) { func getSongLyrics(songId string, storefront string, token string, userToken string) (string, error) {
req, err := http.NewRequest("GET", 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 { if err != nil {
return "", err return "", err
} }
@ -1826,13 +1827,95 @@ func main() {
fmt.Printf("======= Completed %d/%d ###### %d errors!! =======\n", oktrackNum, trackTotalnum, trackTotalnum-oktrackNum) 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) { func conventTTMLToLRC(ttml string) (string, error) {
parsedTTML := etree.NewDocument() parsedTTML := etree.NewDocument()
err := parsedTTML.ReadFromString(ttml) err := parsedTTML.ReadFromString(ttml)
if err != nil { if err != nil {
return "", err return "", err
} }
var lrcLines []string 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 _, item := range parsedTTML.FindElement("tt").FindElement("body").ChildElements() {
for _, lyric := range item.ChildElements() { for _, lyric := range item.ChildElements() {
var h, m, s, ms int var h, m, s, ms int

Loading…
Cancel
Save