add use go-mp4tag

This commit is contained in:
zhaarey
2025-01-13 00:47:49 +08:00
parent d2971585d0
commit f2b27241c7
3 changed files with 102 additions and 55 deletions

5
go.mod
View File

@ -1,6 +1,8 @@
module main module main
go 1.17 go 1.21.6
toolchain go1.22.2
require ( require (
github.com/Eyevinn/mp4ff v0.46.0 github.com/Eyevinn/mp4ff v0.46.0
@ -11,6 +13,7 @@ require (
) )
require ( require (
github.com/Sorrow446/go-mp4tag v0.0.0-20240130220823-68ce31d53e37 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
golang.org/x/sys v0.22.0 // indirect golang.org/x/sys v0.22.0 // indirect

2
go.sum
View File

@ -1,5 +1,7 @@
github.com/Eyevinn/mp4ff v0.46.0 h1:A8oJA4A3C9fDbX38jEw/26utjNdvmRmrO37tVI5pDk0= github.com/Eyevinn/mp4ff v0.46.0 h1:A8oJA4A3C9fDbX38jEw/26utjNdvmRmrO37tVI5pDk0=
github.com/Eyevinn/mp4ff v0.46.0/go.mod h1:hJNUUqOBryLAzUW9wpCJyw2HaI+TCd2rUPhafoS5lgg= github.com/Eyevinn/mp4ff v0.46.0/go.mod h1:hJNUUqOBryLAzUW9wpCJyw2HaI+TCd2rUPhafoS5lgg=
github.com/Sorrow446/go-mp4tag v0.0.0-20240130220823-68ce31d53e37 h1:6X6U2D53ITfDGiyGN+sOVm/iFveFHrFRS7icGJ+u88M=
github.com/Sorrow446/go-mp4tag v0.0.0-20240130220823-68ce31d53e37/go.mod h1:l5rVvaRUrCot83416D6xggKCeFZQAXcv02tnJslG26s=
github.com/abema/go-mp4 v1.3.0 h1:vr0PX0jk3E4GO1c28fNRsyZdkLwz38R+XRVncIH1XDk= github.com/abema/go-mp4 v1.3.0 h1:vr0PX0jk3E4GO1c28fNRsyZdkLwz38R+XRVncIH1XDk=
github.com/abema/go-mp4 v1.3.0/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws= github.com/abema/go-mp4 v1.3.0/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws=
github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU= github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU=

150
main.go
View File

@ -19,6 +19,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/Sorrow446/go-mp4tag"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@ -28,24 +29,22 @@ import (
"main/utils/runv2" "main/utils/runv2"
"main/utils/structs" "main/utils/structs"
) )
var ( var (
forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`) forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`)
dl_atmos bool dl_atmos bool
dl_aac bool dl_aac bool
dl_select bool dl_select bool
artist_select bool artist_select bool
alac_max *int alac_max *int
atmos_max *int atmos_max *int
Config structs.ConfigSet aac_type *string
counter structs.Counter Config structs.ConfigSet
okDict = make(map[string][]int) counter structs.Counter
okDict = make(map[string][]int)
) )
func loadConfig() error { func loadConfig() error {
// 读取config.yaml文件内容 // 读取config.yaml文件内容
data, err := ioutil.ReadFile("config.yaml") data, err := ioutil.ReadFile("config.yaml")
@ -86,7 +85,6 @@ func fileExists(path string) (bool, error) {
return false, err return false, err
} }
func checkUrl(url string) (string, string) { func checkUrl(url string) (string, string) {
pat := regexp.MustCompile(`^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w{2})(?:\/album|\/album\/.+))\/(?:id)?(\d[^\D]+)(?:$|\?)`) pat := regexp.MustCompile(`^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w{2})(?:\/album|\/album\/.+))\/(?:id)?(\d[^\D]+)(?:$|\?)`)
matches := pat.FindAllStringSubmatch(url, -1) matches := pat.FindAllStringSubmatch(url, -1)
@ -726,7 +724,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
ttml, err := getSongLyrics(track.ID, storefront, token, userToken) ttml, err := getSongLyrics(track.ID, storefront, token, userToken)
if err != nil { if err != nil {
fmt.Println("Failed to get lyrics") fmt.Println("Failed to get lyrics")
} else if Config.LrcFormat == "ttml"{ } else if Config.LrcFormat == "ttml" {
if Config.SaveLrcFile { if Config.SaveLrcFile {
lrc = ttml lrc = ttml
err := writeLyrics(sanAlbumFolder, lrcFilename, lrc) err := writeLyrics(sanAlbumFolder, lrcFilename, lrc)
@ -777,41 +775,9 @@ func rip(albumId string, token string, storefront string, userToken string) erro
continue continue
} }
//add tags
index := trackNum - 1
tags := []string{ tags := []string{
"tool=", "tool=",
fmt.Sprintf("lyrics=%s", lrc), fmt.Sprintf("lyrics=%s", lrc),
fmt.Sprintf("title=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Name),
fmt.Sprintf("artist=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName),
fmt.Sprintf("genre=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.GenreNames[0]),
fmt.Sprintf("created=%s", meta.Data[0].Attributes.ReleaseDate),
fmt.Sprintf("album_artist=%s", meta.Data[0].Attributes.ArtistName),
fmt.Sprintf("composer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName),
fmt.Sprintf("writer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName),
fmt.Sprintf("performer=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName),
fmt.Sprintf("copyright=%s", meta.Data[0].Attributes.Copyright),
fmt.Sprintf("ISRC=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc),
fmt.Sprintf("UPC=%s", meta.Data[0].Attributes.Upc),
}
if strings.Contains(albumId, "pl.") && !Config.UseSongInfoForPlaylist {
tags = append(tags, "disk=1/1")
tags = append(tags, fmt.Sprintf("track=%d", trackNum))
tags = append(tags, fmt.Sprintf("tracknum=%d/%d", trackNum, trackTotal))
tags = append(tags, fmt.Sprintf("album=%s", meta.Data[0].Attributes.Name))
} else {
tags = append(tags, fmt.Sprintf("disk=%d/%d", meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber, meta.Data[0].Relationships.Tracks.Data[trackTotal-1].Attributes.DiscNumber))
tags = append(tags, fmt.Sprintf("track=%d", meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
tags = append(tags, fmt.Sprintf("tracknum=%d/%d", meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber, trackTotal))
tags = append(tags, fmt.Sprintf("album=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName))
}
if track.Attributes.ContentRating == "explicit" {
tags = append(tags, "rating=1")
} else if track.Attributes.ContentRating == "clean" {
tags = append(tags, "rating=2")
} else {
tags = append(tags, "rating=0")
} }
if Config.EmbedCover { if Config.EmbedCover {
if strings.Contains(albumId, "pl.") && Config.DlAlbumcoverForPlaylist { if strings.Contains(albumId, "pl.") && Config.DlAlbumcoverForPlaylist {
@ -838,6 +804,8 @@ func rip(albumId string, token string, storefront string, userToken string) erro
continue continue
} }
} }
err = writeMP4Tags(trackPath, meta, trackNum, trackTotal)
counter.Success++ counter.Success++
okDict[albumId] = append(okDict[albumId], trackNum) okDict[albumId] = append(okDict[albumId], trackNum)
} }
@ -845,6 +813,82 @@ func rip(albumId string, token string, storefront string, userToken string) erro
return err return err
} }
func writeMP4Tags(trackPath string, meta *structs.AutoGenerated, trackNum, trackTotal int) error {
index := trackNum - 1
artistID, err := strconv.ParseUint(meta.Data[0].Relationships.Tracks.Data[index].Relationships.Artists.Data[0].ID, 10, 32)
if err != nil {
return err
}
albumID, err := strconv.ParseUint(meta.Data[0].ID, 10, 32)
if err != nil {
return err
}
releaseYear, err := strconv.ParseUint(meta.Data[0].Attributes.ReleaseDate[:4], 10, 32)
if err != nil {
return err
}
t := &mp4tag.MP4Tags{
Title: meta.Data[0].Relationships.Tracks.Data[index].Attributes.Name,
TitleSort: meta.Data[0].Relationships.Tracks.Data[index].Attributes.Name,
AlbumArtist: meta.Data[0].Attributes.ArtistName,
AlbumArtistSort: meta.Data[0].Attributes.ArtistName,
Artist: meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName,
ArtistSort: meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName,
Custom: map[string]string{
"PERFORMER": meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName,
"RELEASETIME": meta.Data[0].Relationships.Tracks.Data[index].Attributes.ReleaseDate,
"ISRC": meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc,
"LABEL": meta.Data[0].Attributes.RecordLabel,
"UPC": meta.Data[0].Attributes.Upc,
},
ItunesAlbumID: int32(albumID),
Composer: meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName,
ComposerSort: meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName,
Date: meta.Data[0].Attributes.ReleaseDate,
CustomGenre: meta.Data[0].Relationships.Tracks.Data[index].Attributes.GenreNames[0],
Copyright: meta.Data[0].Attributes.Copyright,
Publisher: meta.Data[0].Attributes.RecordLabel,
ItunesArtistID: int32(artistID),
Year: int32(releaseYear),
}
if strings.Contains(meta.Data[0].ID, "pl.") && !Config.UseSongInfoForPlaylist {
t.DiscNumber = 1
t.DiscTotal = 1
t.TrackNumber = int16(trackNum)
t.TrackTotal = int16(trackTotal)
t.Album = meta.Data[0].Attributes.Name
t.AlbumSort = meta.Data[0].Attributes.Name
} else {
t.DiscNumber = int16(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber)
t.DiscTotal = int16(meta.Data[0].Relationships.Tracks.Data[trackTotal-1].Attributes.DiscNumber)
t.TrackNumber = int16(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber)
t.TrackTotal = int16(trackTotal)
t.Album = meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName
t.AlbumSort = meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName
}
if meta.Data[0].Relationships.Tracks.Data[index].Attributes.ContentRating == "explicit" {
t.ItunesAdvisory = mp4tag.ItunesAdvisoryExplicit
} else if meta.Data[0].Relationships.Tracks.Data[index].Attributes.ContentRating == "clean" {
t.ItunesAdvisory = mp4tag.ItunesAdvisoryClean
} else {
t.ItunesAdvisory = mp4tag.ItunesAdvisoryNone
}
mp4, err := mp4tag.Open(trackPath)
if err != nil {
panic(err)
}
defer mp4.Close()
err = mp4.Write(t, []string{})
if err != nil {
panic(err)
}
return err
}
func main() { func main() {
err := loadConfig() err := loadConfig()
if err != nil { if err != nil {
@ -865,8 +909,9 @@ func main() {
pflag.BoolVar(&dl_aac, "aac", false, "Enable adm-aac download mode") pflag.BoolVar(&dl_aac, "aac", false, "Enable adm-aac download mode")
pflag.BoolVar(&dl_select, "select", false, "Enable selective download") pflag.BoolVar(&dl_select, "select", false, "Enable selective download")
pflag.BoolVar(&artist_select, "all-album", false, "Download all artist albums") pflag.BoolVar(&artist_select, "all-album", false, "Download all artist albums")
alac_max = pflag.Int("alac-max", -1, "Specify the max quality for download alac") alac_max = pflag.Int("alac-max", Config.AlacMax, "Specify the max quality for download alac")
atmos_max = pflag.Int("atmos-max", -1, "Specify the max quality for download atmos") atmos_max = pflag.Int("atmos-max", Config.AtmosMax, "Specify the max quality for download atmos")
aac_type = pflag.String("aac-type", Config.AacType, "Select AAC type, aac aac-binaural aac-downmix")
// Custom usage message for help // Custom usage message for help
pflag.Usage = func() { pflag.Usage = func() {
@ -874,16 +919,13 @@ func main() {
fmt.Println("Options:") fmt.Println("Options:")
pflag.PrintDefaults() pflag.PrintDefaults()
} }
Config.AlacMax = *alac_max
Config.AtmosMax = *atmos_max
Config.AacType = *aac_type
// Parse the flag arguments // Parse the flag arguments
pflag.Parse() pflag.Parse()
if *alac_max != -1 {
Config.AlacMax = *alac_max
}
if *atmos_max != -1 {
Config.AtmosMax = *atmos_max
}
args := pflag.Args() args := pflag.Args()
if len(args) == 0 { if len(args) == 0 {
fmt.Println("No URLs provided. Please provide at least one URL.") fmt.Println("No URLs provided. Please provide at least one URL.")