From f2b27241c749a9bb8269d549a063c15f7720d59c Mon Sep 17 00:00:00 2001 From: zhaarey <157944548+zhaarey@users.noreply.github.com> Date: Mon, 13 Jan 2025 00:47:49 +0800 Subject: [PATCH] add use go-mp4tag --- go.mod | 5 +- go.sum | 2 + main.go | 150 ++++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 102 insertions(+), 55 deletions(-) diff --git a/go.mod b/go.mod index 0ebe02a..f6c161b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module main -go 1.17 +go 1.21.6 + +toolchain go1.22.2 require ( github.com/Eyevinn/mp4ff v0.46.0 @@ -11,6 +13,7 @@ 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/rivo/uniseg v0.4.7 // indirect golang.org/x/sys v0.22.0 // indirect diff --git a/go.sum b/go.sum index 9695a86..b48d54b 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/Eyevinn/mp4ff v0.46.0 h1:A8oJA4A3C9fDbX38jEw/26utjNdvmRmrO37tVI5pDk0= 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/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws= github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU= diff --git a/main.go b/main.go index 856584b..7074d59 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ import ( "strconv" "strings" + "github.com/Sorrow446/go-mp4tag" "github.com/spf13/pflag" "gopkg.in/yaml.v2" @@ -28,24 +29,22 @@ import ( "main/utils/runv2" "main/utils/structs" - ) var ( forbiddenNames = regexp.MustCompile(`[/\\<>:"|?*]`) - dl_atmos bool - dl_aac bool - dl_select bool - artist_select bool - alac_max *int - atmos_max *int - Config structs.ConfigSet - counter structs.Counter - okDict = make(map[string][]int) + dl_atmos bool + dl_aac bool + dl_select bool + artist_select bool + alac_max *int + atmos_max *int + aac_type *string + Config structs.ConfigSet + counter structs.Counter + okDict = make(map[string][]int) ) - - func loadConfig() error { // 读取config.yaml文件内容 data, err := ioutil.ReadFile("config.yaml") @@ -86,7 +85,6 @@ func fileExists(path string) (bool, error) { return false, err } - func checkUrl(url string) (string, string) { pat := regexp.MustCompile(`^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w{2})(?:\/album|\/album\/.+))\/(?:id)?(\d[^\D]+)(?:$|\?)`) 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) if err != nil { fmt.Println("Failed to get lyrics") - } else if Config.LrcFormat == "ttml"{ + } else if Config.LrcFormat == "ttml" { if Config.SaveLrcFile { lrc = ttml err := writeLyrics(sanAlbumFolder, lrcFilename, lrc) @@ -777,41 +775,9 @@ func rip(albumId string, token string, storefront string, userToken string) erro continue } - - //add tags - index := trackNum - 1 tags := []string{ "tool=", 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 strings.Contains(albumId, "pl.") && Config.DlAlbumcoverForPlaylist { @@ -838,6 +804,8 @@ func rip(albumId string, token string, storefront string, userToken string) erro continue } } + err = writeMP4Tags(trackPath, meta, trackNum, trackTotal) + counter.Success++ okDict[albumId] = append(okDict[albumId], trackNum) } @@ -845,6 +813,82 @@ func rip(albumId string, token string, storefront string, userToken string) erro 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() { err := loadConfig() if err != nil { @@ -865,8 +909,9 @@ func main() { pflag.BoolVar(&dl_aac, "aac", false, "Enable adm-aac download mode") pflag.BoolVar(&dl_select, "select", false, "Enable selective download") 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") - atmos_max = pflag.Int("atmos-max", -1, "Specify the max quality for download atmos") + alac_max = pflag.Int("alac-max", Config.AlacMax, "Specify the max quality for download alac") + 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 pflag.Usage = func() { @@ -874,16 +919,13 @@ func main() { fmt.Println("Options:") pflag.PrintDefaults() } + Config.AlacMax = *alac_max + Config.AtmosMax = *atmos_max + Config.AacType = *aac_type // Parse the flag arguments pflag.Parse() - if *alac_max != -1 { - Config.AlacMax = *alac_max - } - if *atmos_max != -1 { - Config.AtmosMax = *atmos_max - } args := pflag.Args() if len(args) == 0 { fmt.Println("No URLs provided. Please provide at least one URL.")