add lrc-format
This commit is contained in:
parent
78ebfc9b74
commit
11d34f3601
@ -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
|
||||||
|
87
main.go
87
main.go
@ -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 conventTTMLToLRC(ttml string) (string, error) {
|
func conventSyllableTTMLToLRC(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
|
||||||
|
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 _, 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…
x
Reference in New Issue
Block a user