add dl-albumcover-for-playlist
This commit is contained in:
parent
1f20fa5977
commit
0979ae0e23
@ -26,3 +26,7 @@ artist-folder-format: "{ArtistName}"
|
|||||||
explicit-choice : "[E]"
|
explicit-choice : "[E]"
|
||||||
clean-choice : "[C]"
|
clean-choice : "[C]"
|
||||||
apple-master-choice : "[M]"
|
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
|
||||||
|
54
main.go
54
main.go
@ -56,6 +56,8 @@ type Config struct {
|
|||||||
Check string `yaml:"check"`
|
Check string `yaml:"check"`
|
||||||
GetM3u8FromDevice bool `yaml:"get-m3u8-from-device"`
|
GetM3u8FromDevice bool `yaml:"get-m3u8-from-device"`
|
||||||
AlacMax int `yaml:"alac-max"`
|
AlacMax int `yaml:"alac-max"`
|
||||||
|
UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"`
|
||||||
|
DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
@ -688,13 +690,18 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
AlbumName:=meta.Data[0].Relationships.Tracks.Data[index].Attributes.AlbumName
|
||||||
err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, 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 {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -759,12 +766,12 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
if len(meta.Data) > 0 {
|
if len(meta.Data) > 0 {
|
||||||
album := 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 {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -822,17 +829,24 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trkn := make([]byte, 8)
|
trkn := make([]byte, 8)
|
||||||
|
disk := make([]byte, 8)
|
||||||
binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
|
binary.BigEndian.PutUint32(trkn, uint32(meta.Data[0].Relationships.Tracks.Data[index].Attributes.TrackNumber))
|
||||||
binary.BigEndian.PutUint16(trkn[4:], uint16(trackTotal))
|
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)
|
err = addMeta(mp4.BoxType{'t', 'r', 'k', 'n'}, trkn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
err = addMeta(mp4.BoxType{'d', 'i', 's', 'k'}, disk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1101,8 +1115,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCover(sanAlbumFolder, url string) error {
|
func writeCover(sanAlbumFolder,name string, url string) error {
|
||||||
covPath := filepath.Join(sanAlbumFolder, "cover." + config.CoverFormat)
|
covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat)
|
||||||
exists, err := fileExists(covPath)
|
exists, err := fileExists(covPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to check if cover exists.")
|
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, "_"))
|
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
||||||
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
||||||
fmt.Println(albumFolder)
|
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 {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
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),
|
fmt.Sprintf("lyrics=%s", lrc),
|
||||||
}
|
}
|
||||||
if config.EmbedCover {
|
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, ":")
|
tagsString := strings.Join(tags, ":")
|
||||||
cmd := exec.Command("MP4Box", "-itags", tagsString, trackPath)
|
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)
|
fmt.Printf("Embed failed: %v\n", err)
|
||||||
continue
|
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
|
oktrackNum += 1
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -52,6 +52,8 @@ type Config struct {
|
|||||||
CleanChoice string `yaml:"clean-choice"`
|
CleanChoice string `yaml:"clean-choice"`
|
||||||
AppleMasterChoice string `yaml:"apple-master-choice"`
|
AppleMasterChoice string `yaml:"apple-master-choice"`
|
||||||
AtmosMax int `yaml:"atmos-max"`
|
AtmosMax int `yaml:"atmos-max"`
|
||||||
|
UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"`
|
||||||
|
DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
@ -1061,8 +1063,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCover(sanAlbumFolder, url string) error {
|
func writeCover(sanAlbumFolder,name string, url string) error {
|
||||||
covPath := filepath.Join(sanAlbumFolder, "cover." + config.CoverFormat)
|
covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat)
|
||||||
exists, err := fileExists(covPath)
|
exists, err := fileExists(covPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to check if cover exists.")
|
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, "_"))
|
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
||||||
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
||||||
fmt.Println(albumFolder)
|
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 {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
fmt.Println("Failed to write cover.")
|
||||||
}
|
}
|
||||||
@ -1310,7 +1312,6 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
tags := []string{
|
tags := []string{
|
||||||
"tool=",
|
"tool=",
|
||||||
fmt.Sprintf("lyrics=%s", lrc),
|
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("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("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("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("copyright=%s", meta.Data[0].Attributes.Copyright),
|
||||||
fmt.Sprintf("ISRC=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc),
|
fmt.Sprintf("ISRC=%s", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc),
|
||||||
fmt.Sprintf("UPC=%s", meta.Data[0].Attributes.Upc),
|
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 {
|
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, ":")
|
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)
|
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)
|
fmt.Printf("Error deleting file: %v\n", err)
|
||||||
continue
|
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))
|
fmt.Printf("Successfully processed and deleted %s\n", filepath.Base(trackPath))
|
||||||
oktrackNum += 1
|
oktrackNum += 1
|
||||||
|
|
||||||
|
230
main_select.go
230
main_select.go
@ -53,6 +53,8 @@ type Config struct {
|
|||||||
CleanChoice string `yaml:"clean-choice"`
|
CleanChoice string `yaml:"clean-choice"`
|
||||||
AppleMasterChoice string `yaml:"apple-master-choice"`
|
AppleMasterChoice string `yaml:"apple-master-choice"`
|
||||||
AlacMax int `yaml:"alac-max"`
|
AlacMax int `yaml:"alac-max"`
|
||||||
|
UseSongInfoForPlaylist bool `yaml:"use-songinfo-for-playlist"`
|
||||||
|
DlAlbumcoverForPlaylist bool `yaml:"dl-albumcover-for-playlist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
@ -679,7 +681,22 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -689,25 +706,45 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
return err
|
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)
|
err = addMeta(mp4.BoxType{'\251', 'w', 'r', 't'}, meta.Data[0].Relationships.Tracks.Data[index].Attributes.ComposerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// cnID, err := strconv.ParseUint(meta.Data[0].Relationships.Tracks.Data[index].ID, 10, 32)
|
err = addMeta(mp4.BoxType{'\251', 'd', 'a', 'y'}, meta.Data[0].Attributes.ReleaseDate)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return err
|
return err
|
||||||
// }
|
}
|
||||||
|
|
||||||
// err = addMeta(mp4.BoxType{'c', 'n', 'I', 'D'}, uint32(cnID))
|
cnID, err := strconv.ParseUint(meta.Data[0].Relationships.Tracks.Data[index].ID, 10, 32)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return err
|
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)
|
err = addExtendedMeta("ISRC", meta.Data[0].Relationships.Tracks.Data[index].Attributes.Isrc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -724,7 +761,12 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
if len(meta.Data) > 0 {
|
if len(meta.Data) > 0 {
|
||||||
album := 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -743,6 +785,11 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = addMeta(mp4.BoxType{'\251', 'p', 'u', 'b'}, album.Attributes.RecordLabel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = addExtendedMeta("LABEL", album.Attributes.RecordLabel)
|
err = addExtendedMeta("LABEL", album.Attributes.RecordLabel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -752,44 +799,53 @@ func writeM4a(w *mp4.Writer, info *SongInfo, meta *AutoGenerated, data []byte, t
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// plID, err := strconv.ParseUint(album.ID, 10, 32)
|
if !strings.Contains(meta.Data[0].ID, "pl."){
|
||||||
// if err != nil {
|
plID, err := strconv.ParseUint(meta.Data[0].ID, 10, 32)
|
||||||
// return err
|
if err != nil {
|
||||||
// }
|
return err
|
||||||
|
}
|
||||||
// err = addMeta(mp4.BoxType{'p', 'l', 'I', 'D'}, uint32(plID))
|
|
||||||
// if err != nil {
|
err = addMeta(mp4.BoxType{'p', 'l', 'I', 'D'}, uint32(plID))
|
||||||
// return err
|
if err != nil {
|
||||||
// }
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if len(meta.Data[0].Relationships.Artists.Data) > 0 {
|
if len(meta.Data[0].Relationships.Tracks.Data[index].Relationships.Artists.Data[0].ID) > 0 {
|
||||||
// atID, err := strconv.ParseUint(meta.Data[0].Relationships.Artists.Data[index].ID, 10, 32)
|
atID, err := strconv.ParseUint(meta.Data[0].Relationships.Tracks.Data[index].Relationships.Artists.Data[0].ID, 10, 32)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return err
|
return err
|
||||||
// }
|
}
|
||||||
|
|
||||||
// err = addMeta(mp4.BoxType{'a', 't', 'I', 'D'}, uint32(atID))
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
err = addMeta(mp4.BoxType{'a', 't', 'I', 'D'}, uint32(atID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
trkn := make([]byte, 8)
|
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.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)
|
err = addMeta(mp4.BoxType{'t', 'r', 'k', 'n'}, trkn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = addMeta(mp4.BoxType{'d', 'i', 's', 'k'}, disk)
|
||||||
// disk := make([]byte, 8)
|
if err != nil {
|
||||||
// binary.BigEndian.PutUint32(disk, uint32(meta.Attributes.DiscNumber))
|
return err
|
||||||
// err = addMeta(mp4.BoxType{'d', 'i', 's', 'k'}, disk)
|
}
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
ctx.UnderIlst = false
|
ctx.UnderIlst = false
|
||||||
|
|
||||||
@ -1054,8 +1110,8 @@ func getSongLyrics(songId string, storefront string, token string, userToken str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeCover(sanAlbumFolder, url string) error {
|
func writeCover(sanAlbumFolder,name string, url string) error {
|
||||||
covPath := filepath.Join(sanAlbumFolder, "cover." + config.CoverFormat)
|
covPath := filepath.Join(sanAlbumFolder, name+"." + config.CoverFormat)
|
||||||
exists, err := fileExists(covPath)
|
exists, err := fileExists(covPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to check if cover exists.")
|
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, " ")
|
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
|
var albumFolder string
|
||||||
if strings.Contains(albumId, "pl.") {
|
if strings.Contains(albumId, "pl.") {
|
||||||
albumFolder = strings.NewReplacer(
|
albumFolder = strings.NewReplacer(
|
||||||
"{ArtistName}", "Apple Music",
|
"{ArtistName}", "Apple Music",
|
||||||
"{PlaylistName}", meta.Data[0].Attributes.Name,
|
"{PlaylistName}", meta.Data[0].Attributes.Name,
|
||||||
"{PlaylistId}", albumId,
|
"{PlaylistId}", albumId,
|
||||||
"{Quality}","",
|
"{Quality}",Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}",Tag_string,
|
||||||
).Replace(config.PlaylistFolderFormat)
|
).Replace(config.PlaylistFolderFormat)
|
||||||
@ -1181,7 +1251,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{UPC}", meta.Data[0].Attributes.Upc,
|
"{UPC}", meta.Data[0].Attributes.Upc,
|
||||||
"{Copyright}", meta.Data[0].Attributes.Copyright,
|
"{Copyright}", meta.Data[0].Attributes.Copyright,
|
||||||
"{AlbumId}", albumId,
|
"{AlbumId}", albumId,
|
||||||
"{Quality}", "",
|
"{Quality}", Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}",Tag_string,
|
||||||
).Replace(config.AlbumFolderFormat)
|
).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, "_"))
|
sanAlbumFolder := filepath.Join(singerFolder, forbiddenNames.ReplaceAllString(albumFolder, "_"))
|
||||||
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
os.MkdirAll(sanAlbumFolder, os.ModePerm)
|
||||||
fmt.Println(albumFolder)
|
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 {
|
if err != nil {
|
||||||
fmt.Println("Failed to write cover.")
|
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.")
|
fmt.Println("Unavailable in ALAC.")
|
||||||
continue
|
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{}
|
stringsToJoin := []string{}
|
||||||
if track.Attributes.IsAppleDigitalMaster{
|
if track.Attributes.IsAppleDigitalMaster{
|
||||||
if config.AppleMasterChoice != ""{
|
if config.AppleMasterChoice != ""{
|
||||||
@ -1278,7 +1356,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
"{SongName}", track.Attributes.Name,
|
"{SongName}", track.Attributes.Name,
|
||||||
"{DiscNumber}", string(track.Attributes.DiscNumber),
|
"{DiscNumber}", string(track.Attributes.DiscNumber),
|
||||||
"{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber),
|
"{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber),
|
||||||
"{Quality}","",
|
"{Quality}",Quality,
|
||||||
"{Codec}", "ALAC",
|
"{Codec}", "ALAC",
|
||||||
"{Tag}",Tag_string,
|
"{Tag}",Tag_string,
|
||||||
).Replace(config.SongFileFormat)
|
).Replace(config.SongFileFormat)
|
||||||
@ -1378,7 +1456,15 @@ func rip(albumId string, token string, storefront string, userToken string) erro
|
|||||||
fmt.Sprintf("lyrics=%s", lrc),
|
fmt.Sprintf("lyrics=%s", lrc),
|
||||||
}
|
}
|
||||||
if config.EmbedCover {
|
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, ":")
|
tagsString := strings.Join(tags, ":")
|
||||||
cmd := exec.Command("MP4Box", "-itags", tagsString, trackPath)
|
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)
|
fmt.Printf("Embed failed: %v\n", err)
|
||||||
continue
|
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
|
return err
|
||||||
@ -1471,6 +1563,50 @@ func conventTTMLToLRC(ttml string) (string, error) {
|
|||||||
}
|
}
|
||||||
return strings.Join(lrcLines, "\n"), nil
|
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) {
|
func extractMedia(b string) (string, []string, error) {
|
||||||
masterUrl, err := url.Parse(b)
|
masterUrl, err := url.Parse(b)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user