From 0979ae0e2362c7eaebabe9fcc9225e453cc150dc Mon Sep 17 00:00:00 2001 From: zhaarey <157944548+zhaarey@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:47:17 +0800 Subject: [PATCH] add dl-albumcover-for-playlist --- config.yaml | 4 + main.go | 54 +++++++++--- main_atmos.go | 39 +++++++-- main_select.go | 230 +++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 259 insertions(+), 68 deletions(-) diff --git a/config.yaml b/config.yaml index eb1e0f4..aa9e20e 100644 --- a/config.yaml +++ b/config.yaml @@ -26,3 +26,7 @@ artist-folder-format: "{ArtistName}" explicit-choice : "[E]" clean-choice : "[C]" apple-master-choice : "[M]" +#if set true,for playlst,will use songinfo for meta #albumname track disk +use-songinfo-for-playlist: false +#if set true,will download album cover for playlist +dl-albumcover-for-playlist: false diff --git a/main.go b/main.go index f21470f..e38b5a2 100644 --- a/main.go +++ b/main.go @@ -56,6 +56,8 @@ type Config struct { Check string `yaml:"check"` GetM3u8FromDevice bool `yaml:"get-m3u8-from-device"` AlacMax int `yaml:"alac-max"` + UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"` + DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"` } var config Config @@ -688,13 +690,18 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t if err != nil { return err } - - err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName) + AlbumName:=meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName + if strings.Contains(meta.Data[0].ID, "pl."){ + if !config.UseSongInfoForPlaylist { + AlbumName=meta.Data[0].Attributes.Name + } + } + err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, AlbumName) if err != nil { return err } - err = addMeta(mp4.BoxType{'s', 'o', 'a', 'l'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName) + err = addMeta(mp4.BoxType{'s', 'o', 'a', 'l'}, AlbumName) if err != nil { return err } @@ -759,12 +766,12 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t if len(meta.Data) > 0 { album := meta.Data[0] - err = addMeta(mp4.BoxType{'a', 'A', 'R', 'T'}, album.Attributes.ArtistName) + err = addMeta(mp4.BoxType{'a', 'A', 'R', 'T'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) if err != nil { return err } - err = addMeta(mp4.BoxType{'s', 'o', 'a', 'a'}, album.Attributes.ArtistName) + err = addMeta(mp4.BoxType{'s', 'o', 'a', 'a'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) if err != nil { return err } @@ -822,17 +829,24 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t return err } } - trkn := make([]byte, 8) + disk := make([]byte, 8) binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber)) binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal)) + binary.BigEndian.PutUint32(disk, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber)) + binary.BigEndian.PutUint16(disk[4:], uint16(meta.Data[0].Relationships.Tracks.Data[trackTotal - 1].Attributes.DiscNumber)) + if strings.Contains(meta.Data[0].ID, "pl."){ + if !config.UseSongInfoForPlaylist { + binary.BigEndian.PutUint32(trkn, uint32(trackNum)) + binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal)) + binary.BigEndian.PutUint32(disk, uint32(1)) + binary.BigEndian.PutUint16(disk[4:], uint16(1)) + } + } err = addMeta(mp4.BoxType{'t', 'r', 'k', 'n'}, trkn) if err != nil { return err } - disk := make([]byte, 8) - binary.BigEndian.PutUint32(disk, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber)) - binary.BigEndian.PutUint16(disk[4:], uint16(meta.Data[0].Relationships.Tracks.Data[trackTotal - 1].Attributes.DiscNumber)) err = addMeta(mp4.BoxType{'d', 'i', 's', 'k'}, disk) if err != nil { return err @@ -1101,8 +1115,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str } } -func writeCover(sanAlbumFolder, url string) error { - covPath := filepath.Join(sanAlbumFolder, "cover." + config.CoverFormat) +func writeCover(sanAlbumFolder,name string, url string) error { + covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat) exists, err := fileExists(covPath) if err != nil { fmt.Println("Failed to check if cover exists.") @@ -1248,7 +1262,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_")) os.MkdirAll(sanAlbumFolder, os.ModePerm) fmt.Println(albumFolder) - err = writeCover(sanAlbumFolder, meta.Data[0].Attributes.Artwork.URL) + err = writeCover(sanAlbumFolder,"cover", meta.Data[0].Attributes.Artwork.URL) if err != nil { fmt.Println("Failed to write cover.") } @@ -1374,7 +1388,15 @@ func rip(albumId string, token string, storefront string, userToken string) erro fmt.Sprintf("lyrics=%s", lrc), } if config.EmbedCover { - tags = append(tags, fmt.Sprintf("cover=%s/cover.%s", sanAlbumFolder, config.CoverFormat)) + if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist { + err = writeCover(sanAlbumFolder,track.ID, track.Attributes.Artwork.URL) + if err != nil { + fmt.Println("Failed to write cover.") + } + tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)) + }else{ + tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,"cover", config.CoverFormat)) + } } tagsString := strings.Join(tags, ":") cmd := exec.Command("MP4Box", "-itags", tagsString, trackPath) @@ -1382,6 +1404,12 @@ func rip(albumId string, token string, storefront string, userToken string) erro fmt.Printf("Embed failed: %v\n", err) continue } + if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist { + if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)); err != nil { + fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder,track.ID, config.CoverFormat) + continue + } + } oktrackNum += 1 } return err diff --git a/main_atmos.go b/main_atmos.go index 795d1e4..e7fb2f6 100644 --- a/main_atmos.go +++ b/main_atmos.go @@ -52,6 +52,8 @@ type Config struct { CleanChoice string `yaml:"clean-choice"` AppleMasterChoice string `yaml:"apple-master-choice"` AtmosMax int `yaml:"atmos-max"` + UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"` + DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"` } var config Config @@ -1061,8 +1063,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str } } -func writeCover(sanAlbumFolder, url string) error { - covPath := filepath.Join(sanAlbumFolder, "cover." + config.CoverFormat) +func writeCover(sanAlbumFolder,name string, url string) error { + covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat) exists, err := fileExists(covPath) if err != nil { fmt.Println("Failed to check if cover exists.") @@ -1191,7 +1193,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_")) os.MkdirAll(sanAlbumFolder, os.ModePerm) fmt.Println(albumFolder) - err = writeCover(sanAlbumFolder, meta.Data[0].Attributes.Artwork.URL) + err = writeCover(sanAlbumFolder,"cover", meta.Data[0].Attributes.Artwork.URL) if err != nil { fmt.Println("Failed to write cover.") } @@ -1310,7 +1312,6 @@ func rip(albumId string, token string, storefront string, userToken string) erro tags := []string{ "tool=", fmt.Sprintf("lyrics=%s", lrc), - fmt.Sprintf("album=%s", meta.Data[0].Attributes.Name), 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]), @@ -1322,12 +1323,28 @@ func rip(albumId string, token string, storefront string, userToken string) erro 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), - fmt.Sprintf("track=%s", trackNum), - fmt.Sprintf("tracknum=%d/%d", trackNum, trackTotal), - fmt.Sprintf("disk=%d/%d", meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber, meta.Data[0].Relationships.Tracks.Data[trackTotal - 1].Attributes.DiscNumber), } if config.EmbedCover { - tags = append(tags, fmt.Sprintf("cover=%s/cover.%s", sanAlbumFolder, config.CoverFormat)) + if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist { + err = writeCover(sanAlbumFolder,track.ID, track.Attributes.Artwork.URL) + if err != nil { + fmt.Println("Failed to write cover.") + } + tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)) + }else{ + tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,"cover", config.CoverFormat)) + } + } + if strings.Contains(albumId, "pl.") && !config.UseSongInfoForPlaylist { + tags = append(tags, "disk=1/1") + tags = append(tags, fmt.Sprintf("track=%s", 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=%s", 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)) } tagsString := strings.Join(tags, ":") cmd := exec.Command("MP4Box", "-add", trackPath, "-name", fmt.Sprintf("1=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Name), "-itags", tagsString, "-brand", "mp42", "-ab", "dby1", m4atrackPath) @@ -1341,6 +1358,12 @@ func rip(albumId string, token string, storefront string, userToken string) erro fmt.Printf("Error deleting file: %v\n", err) continue } + if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist { + if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)); err != nil { + fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder,track.ID, config.CoverFormat) + continue + } + } fmt.Printf("Successfully processed and deleted %s\n", filepath.Base(trackPath)) oktrackNum += 1 diff --git a/main_select.go b/main_select.go index 53776e1..2ddad87 100644 --- a/main_select.go +++ b/main_select.go @@ -53,6 +53,8 @@ type Config struct { CleanChoice string `yaml:"clean-choice"` AppleMasterChoice string `yaml:"apple-master-choice"` AlacMax int `yaml:"alac-max"` + UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"` + DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"` } var config Config @@ -679,7 +681,22 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t return err } - err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, meta.Data[0].Attributes.Name) + err = addMeta(mp4.BoxType{'s', 'o', 'n', 'm'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.Name) + if err != nil { + return err + } + AlbumName:=meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName + if strings.Contains(meta.Data[0].ID, "pl."){ + if !config.UseSongInfoForPlaylist { + AlbumName=meta.Data[0].Attributes.Name + } + } + err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, AlbumName) + if err != nil { + return err + } + + err = addMeta(mp4.BoxType{'s', 'o', 'a', 'l'}, AlbumName) if err != nil { return err } @@ -689,25 +706,45 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t return err } + err = addMeta(mp4.BoxType{'s', 'o', 'a', 'r'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) + if err != nil { + return err + } + + err = addMeta(mp4.BoxType{'\251', 'p', 'r', 'f'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) + if err != nil { + return err + } + + err = addExtendedMeta("PERFORMER", meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) + if err != nil { + return err + } + err = addMeta(mp4.BoxType{'\251', 'w', 'r', 't'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName) if err != nil { return err } - err = addMeta(mp4.BoxType{'\251', 'd', 'a', 'y'}, strings.Split(meta.Data[0].Attributes.ReleaseDate, "-")[0]) + err = addMeta(mp4.BoxType{'s', 'o', 'c', 'o'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName) if err != nil { return err } - // cnID, err := strconv.ParseUint(meta.Data[0].Relationships.Tracks.Data[index].ID, 10, 32) - // if err != nil { - // return err - // } + err = addMeta(mp4.BoxType{'\251', 'd', 'a', 'y'}, meta.Data[0].Attributes.ReleaseDate) + if err != nil { + return err + } + + cnID, err := strconv.ParseUint(meta.Data[0].Relationships.Tracks.Data[index].ID, 10, 32) + if err != nil { + return err + } - // err = addMeta(mp4.BoxType{'c', 'n', 'I', 'D'}, uint32(cnID)) - // if err != nil { - // return err - // } + err = addMeta(mp4.BoxType{'c', 'n', 'I', 'D'}, uint32(cnID)) + if err != nil { + return err + } err = addExtendedMeta("ISRC", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc) if err != nil { @@ -724,7 +761,12 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t if len(meta.Data) > 0 { album := meta.Data[0] - err = addMeta(mp4.BoxType{'a', 'A', 'R', 'T'}, album.Attributes.ArtistName) + err = addMeta(mp4.BoxType{'a', 'A', 'R', 'T'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) + if err != nil { + return err + } + + err = addMeta(mp4.BoxType{'s', 'o', 'a', 'a'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ArtistName) if err != nil { return err } @@ -743,6 +785,11 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t return err } + err = addMeta(mp4.BoxType{'\251', 'p', 'u', 'b'}, album.Attributes.RecordLabel) + if err != nil { + return err + } + err = addExtendedMeta("LABEL", album.Attributes.RecordLabel) if err != nil { return err @@ -752,44 +799,53 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t if err != nil { return err } - - // plID, err := strconv.ParseUint(album.ID, 10, 32) - // if err != nil { - // return err - // } - - // err = addMeta(mp4.BoxType{'p', 'l', 'I', 'D'}, uint32(plID)) - // if err != nil { - // return err - // } + + if !strings.Contains(meta.Data[0].ID, "pl."){ + plID, err := strconv.ParseUint(meta.Data[0].ID, 10, 32) + if err != nil { + return err + } + + err = addMeta(mp4.BoxType{'p', 'l', 'I', 'D'}, uint32(plID)) + if err != nil { + return err + } + } } - // if len(meta.Data[0].Relationships.Artists.Data) > 0 { - // atID, err := strconv.ParseUint(meta.Data[0].Relationships.Artists.Data[index].ID, 10, 32) - // if err != nil { - // return err - // } - - // err = addMeta(mp4.BoxType{'a', 't', 'I', 'D'}, uint32(atID)) - // if err != nil { - // return err - // } - // } + if len(meta.Data[0].Relationships.Tracks.Data[index].Relationships.Artists.Data[0].ID) > 0 { + atID, err := strconv.ParseUint(meta.Data[0].Relationships.Tracks.Data[index].Relationships.Artists.Data[0].ID, 10, 32) + if err != nil { + return err + } + err = addMeta(mp4.BoxType{'a', 't', 'I', 'D'}, uint32(atID)) + if err != nil { + return err + } + } trkn := make([]byte, 8) - binary.BigEndian.PutUint32(trkn, uint32(trackNum)) + disk := make([]byte, 8) + binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber)) binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal)) + binary.BigEndian.PutUint32(disk, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.DiscNumber)) + binary.BigEndian.PutUint16(disk[4:], uint16(meta.Data[0].Relationships.Tracks.Data[trackTotal - 1].Attributes.DiscNumber)) + if strings.Contains(meta.Data[0].ID, "pl."){ + if !config.UseSongInfoForPlaylist { + binary.BigEndian.PutUint32(trkn, uint32(trackNum)) + binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal)) + binary.BigEndian.PutUint32(disk, uint32(1)) + binary.BigEndian.PutUint16(disk[4:], uint16(1)) + } + } err = addMeta(mp4.BoxType{'t', 'r', 'k', 'n'}, trkn) if err != nil { return err } - - // disk := make([]byte, 8) - // binary.BigEndian.PutUint32(disk, uint32(meta.Attributes.DiscNumber)) - // err = addMeta(mp4.BoxType{'d', 'i', 's', 'k'}, disk) - // if err != nil { - // return err - // } + err = addMeta(mp4.BoxType{'d', 'i', 's', 'k'}, disk) + if err != nil { + return err + } ctx.UnderIlst = false @@ -1054,8 +1110,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str } } -func writeCover(sanAlbumFolder, url string) error { - covPath := filepath.Join(sanAlbumFolder, "cover." + config.CoverFormat) +func writeCover(sanAlbumFolder,name string, url string) error { + covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat) exists, err := fileExists(covPath) if err != nil { fmt.Println("Failed to check if cover exists.") @@ -1162,13 +1218,27 @@ func rip(albumId string, token string, storefront string, userToken string) erro } } Tag_string := strings.Join(stringsToJoin, " ") + manifest1, err := getInfoFromAdam(meta.Data[0].Relationships.Tracks.Data[0].ID, token, storefront) + if err != nil { + fmt.Println("Failed to get manifest.\n", err) + } + if manifest1.Attributes.ExtendedAssetUrls.EnhancedHls == "" { + fmt.Println("Unavailable in ALAC.") + } + var Quality string + if strings.Contains(config.AlbumFolderFormat, "Quality"){ + Quality,err = extractMediaQuality(manifest1.Attributes.ExtendedAssetUrls.EnhancedHls) + if err != nil { + fmt.Println("Failed to extract quality from manifest.\n", err) + } + } var albumFolder string if strings.Contains(albumId, "pl.") { albumFolder = strings.NewReplacer( "{ArtistName}", "Apple Music", "{PlaylistName}", meta.Data[0].Attributes.Name, "{PlaylistId}", albumId, - "{Quality}","", + "{Quality}",Quality, "{Codec}", "ALAC", "{Tag}",Tag_string, ).Replace(config.PlaylistFolderFormat) @@ -1181,7 +1251,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro "{UPC}", meta.Data[0].Attributes.Upc, "{Copyright}", meta.Data[0].Attributes.Copyright, "{AlbumId}", albumId, - "{Quality}", "", + "{Quality}", Quality, "{Codec}", "ALAC", "{Tag}",Tag_string, ).Replace(config.AlbumFolderFormat) @@ -1193,7 +1263,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_")) os.MkdirAll(sanAlbumFolder, os.ModePerm) fmt.Println(albumFolder) - err = writeCover(sanAlbumFolder, meta.Data[0].Attributes.Artwork.URL) + err = writeCover(sanAlbumFolder,"cover", meta.Data[0].Attributes.Artwork.URL) if err != nil { fmt.Println("Failed to write cover.") } @@ -1255,6 +1325,14 @@ func rip(albumId string, token string, storefront string, userToken string) erro fmt.Println("Unavailable in ALAC.") continue } + var Quality string + if strings.Contains(config.SongFileFormat, "Quality"){ + Quality,err = extractMediaQuality(manifest.Attributes.ExtendedAssetUrls.EnhancedHls) + if err != nil { + fmt.Println("Failed to extract quality from manifest.\n", err) + continue + } + } stringsToJoin := []string{} if track.Attributes.IsAppleDigitalMaster{ if config.AppleMasterChoice != ""{ @@ -1278,7 +1356,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro "{SongName}", track.Attributes.Name, "{DiscNumber}", string(track.Attributes.DiscNumber), "{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber), - "{Quality}","", + "{Quality}",Quality, "{Codec}", "ALAC", "{Tag}",Tag_string, ).Replace(config.SongFileFormat) @@ -1378,7 +1456,15 @@ func rip(albumId string, token string, storefront string, userToken string) erro fmt.Sprintf("lyrics=%s", lrc), } if config.EmbedCover { - tags = append(tags, fmt.Sprintf("cover=%s/cover.%s", sanAlbumFolder, config.CoverFormat)) + if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist { + err = writeCover(sanAlbumFolder,track.ID, track.Attributes.Artwork.URL) + if err != nil { + fmt.Println("Failed to write cover.") + } + tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)) + }else{ + tags = append(tags, fmt.Sprintf("cover=%s/%s.%s", sanAlbumFolder,"cover", config.CoverFormat)) + } } tagsString := strings.Join(tags, ":") cmd := exec.Command("MP4Box", "-itags", tagsString, trackPath) @@ -1386,6 +1472,12 @@ func rip(albumId string, token string, storefront string, userToken string) erro fmt.Printf("Embed failed: %v\n", err) continue } + if strings.Contains(albumId, "pl.") && config.DlAlbumcoverForPlaylist { + if err := os.Remove(fmt.Sprintf("%s/%s.%s", sanAlbumFolder,track.ID, config.CoverFormat)); err != nil { + fmt.Printf("Error deleting file: %s/%s.%s\n", sanAlbumFolder,track.ID, config.CoverFormat) + continue + } + } } } return err @@ -1471,6 +1563,50 @@ func conventTTMLToLRC(ttml string) (string, error) { } return strings.Join(lrcLines, "\n"), nil } +func extractMediaQuality(b string) (string, error) { + resp, err := http.Get(b) + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", errors.New(resp.Status) + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + masterString := string(body) + from, listType, err := m3u8.DecodeFrom(strings.NewReader(masterString), true) + if err != nil || listType != m3u8.MASTER { + return "", errors.New("m3u8 not of master type") + } + master := from.(*m3u8.MasterPlaylist) + sort.Slice(master.Variants, func(i, j int) bool { + return master.Variants[i].AverageBandwidth > master.Variants[j].AverageBandwidth + }) + var Quality string + for _, variant := range master.Variants { + if variant.Codecs == "alac" { + split := strings.Split(variant.Audio, "-") + length := len(split) + length_int,err := strconv.Atoi(split[length-2]) + if err != nil { + return "", err + } + if length_int <= config.AlacMax{ + HZ,err:=strconv.Atoi(split[length-2]) + if err != nil { + fmt.Println(err) + } + KHZ:=float64(HZ) / 1000.0 + Quality = fmt.Sprintf("%sB-%.1fkHz", split[length-1], KHZ) + break + } + } + } + return Quality, nil +} func extractMedia(b string) (string, []string, error) { masterUrl, err := url.Parse(b)