|
|
@ -45,6 +45,10 @@ type Config struct { |
|
|
|
AlacSaveFolder string `yaml:"alac-save-folder"` |
|
|
|
AlacSaveFolder string `yaml:"alac-save-folder"` |
|
|
|
AtmosSaveFolder string `yaml:"atmos-save-folder"` |
|
|
|
AtmosSaveFolder string `yaml:"atmos-save-folder"` |
|
|
|
AlbumFolderFormat string `yaml:"album-folder-format"` |
|
|
|
AlbumFolderFormat string `yaml:"album-folder-format"` |
|
|
|
|
|
|
|
SongFileFormat string `yaml:"song-file-format"` |
|
|
|
|
|
|
|
ExplicitChoice string `yaml:"explicit-choice"` |
|
|
|
|
|
|
|
CleanChoice string `yaml:"clean-choice"` |
|
|
|
|
|
|
|
AppleMasterChoice string `yaml:"apple-master-choice"` |
|
|
|
AtmosMax int `yaml:"atmos-max"` |
|
|
|
AtmosMax int `yaml:"atmos-max"` |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1130,6 +1134,21 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
"{Copyright}", meta.Data[0].Attributes.Copyright, |
|
|
|
"{Copyright}", meta.Data[0].Attributes.Copyright, |
|
|
|
"{AlbumId}", albumId, |
|
|
|
"{AlbumId}", albumId, |
|
|
|
).Replace(config.AlbumFolderFormat) |
|
|
|
).Replace(config.AlbumFolderFormat) |
|
|
|
|
|
|
|
if meta.Data[0].Attributes.IsMasteredForItunes{ |
|
|
|
|
|
|
|
if config.AppleMasterChoice != ""{ |
|
|
|
|
|
|
|
albumFolder = fmt.Sprintf("%s %s", albumFolder,config.AppleMasterChoice) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if meta.Data[0].Attributes.ContentRating=="explicit"{ |
|
|
|
|
|
|
|
if config.ExplicitChoice != ""{ |
|
|
|
|
|
|
|
albumFolder = fmt.Sprintf("%s %s", albumFolder,config.ExplicitChoice) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if meta.Data[0].Attributes.ContentRating=="clean"{ |
|
|
|
|
|
|
|
if config.CleanChoice != ""{ |
|
|
|
|
|
|
|
albumFolder = fmt.Sprintf("%s %s", albumFolder,config.CleanChoice) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
albumFolder = fmt.Sprintf("%s [Atmos]", albumFolder) |
|
|
|
albumFolder = fmt.Sprintf("%s [Atmos]", albumFolder) |
|
|
|
if strings.HasSuffix(albumFolder, ".") { |
|
|
|
if strings.HasSuffix(albumFolder, ".") { |
|
|
|
albumFolder = strings.ReplaceAll(albumFolder, ".", "") |
|
|
|
albumFolder = strings.ReplaceAll(albumFolder, ".", "") |
|
|
@ -1157,9 +1176,31 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
fmt.Println("Unavailable in ALAC.") |
|
|
|
fmt.Println("Unavailable in ALAC.") |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|
filename := fmt.Sprintf("%02d. %s.ec3", trackNum, forbiddenNames.ReplaceAllString(track.Attributes.Name, "_")) |
|
|
|
songName := strings.NewReplacer( |
|
|
|
m4afilename := fmt.Sprintf("%02d. %s.m4a", trackNum, forbiddenNames.ReplaceAllString(track.Attributes.Name, "_")) |
|
|
|
"{SongNumer}", fmt.Sprintf("%02d", trackNum), |
|
|
|
lrcFilename := fmt.Sprintf("%02d. %s.lrc", trackNum, forbiddenNames.ReplaceAllString(track.Attributes.Name, "_")) |
|
|
|
"{SongName}", track.Attributes.Name, |
|
|
|
|
|
|
|
"{DiscNumber}", string(track.Attributes.DiscNumber), |
|
|
|
|
|
|
|
"{TrackNumber}", fmt.Sprintf("%02d", track.Attributes.TrackNumber), |
|
|
|
|
|
|
|
).Replace(config.SongFileFormat) |
|
|
|
|
|
|
|
if track.Attributes.IsAppleDigitalMaster{ |
|
|
|
|
|
|
|
if config.AppleMasterChoice != ""{ |
|
|
|
|
|
|
|
songName = fmt.Sprintf("%s %s", songName,config.AppleMasterChoice) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if track.Attributes.ContentRating=="explicit"{ |
|
|
|
|
|
|
|
if config.ExplicitChoice != ""{ |
|
|
|
|
|
|
|
songName = fmt.Sprintf("%s %s", songName,config.ExplicitChoice) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if track.Attributes.ContentRating=="clean"{ |
|
|
|
|
|
|
|
if config.CleanChoice != ""{ |
|
|
|
|
|
|
|
songName = fmt.Sprintf("%s %s", songName,config.CleanChoice) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
fmt.Println(songName) |
|
|
|
|
|
|
|
filename := fmt.Sprintf("%s.ec3", forbiddenNames.ReplaceAllString(songName, "_")) |
|
|
|
|
|
|
|
m4afilename := fmt.Sprintf("%s.m4a", forbiddenNames.ReplaceAllString(songName, "_")) |
|
|
|
|
|
|
|
lrcFilename := fmt.Sprintf("%s.lrc", forbiddenNames.ReplaceAllString(songName, "_")) |
|
|
|
trackPath := filepath.Join(sanAlbumFolder, filename) |
|
|
|
trackPath := filepath.Join(sanAlbumFolder, filename) |
|
|
|
m4atrackPath := filepath.Join(sanAlbumFolder, m4afilename) |
|
|
|
m4atrackPath := filepath.Join(sanAlbumFolder, m4afilename) |
|
|
|
exists, err := fileExists(trackPath) |
|
|
|
exists, err := fileExists(trackPath) |
|
|
@ -1240,6 +1281,7 @@ func rip(albumId string, token string, storefront string, userToken string) erro |
|
|
|
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=%d/%d", trackNum, trackTotal), |
|
|
|
fmt.Sprintf("track=%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)) |
|
|
|
tags = append(tags, fmt.Sprintf("cover=%s/cover.%s", sanAlbumFolder, config.CoverFormat)) |
|
|
@ -1650,6 +1692,8 @@ type SongAttributes struct { |
|
|
|
EnhancedHls string `json:"enhancedHls"` |
|
|
|
EnhancedHls string `json:"enhancedHls"` |
|
|
|
} `json:"extendedAssetUrls"` |
|
|
|
} `json:"extendedAssetUrls"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
|
|
|
|
IsAppleDigitalMaster bool `json:"isAppleDigitalMaster"` |
|
|
|
|
|
|
|
ContentRating string `json:"contentRating"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
Name string `json:"name"` |
|
|
|
Name string `json:"name"` |
|
|
|
Isrc string `json:"isrc"` |
|
|
|
Isrc string `json:"isrc"` |
|
|
@ -1665,6 +1709,8 @@ type AlbumAttributes struct { |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
TrackCount int `json:"trackCount"` |
|
|
|
TrackCount int `json:"trackCount"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
|
|
|
|
IsAppleDigitalMaster bool `json:"isAppleDigitalMaster"` |
|
|
|
|
|
|
|
ContentRating string `json:"contentRating"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
Name string `json:"name"` |
|
|
|
Name string `json:"name"` |
|
|
|
RecordLabel string `json:"recordLabel"` |
|
|
|
RecordLabel string `json:"recordLabel"` |
|
|
@ -1839,6 +1885,8 @@ type AutoGenerated struct { |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
TrackCount int `json:"trackCount"` |
|
|
|
TrackCount int `json:"trackCount"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
|
|
|
|
IsAppleDigitalMaster bool `json:"isAppleDigitalMaster"` |
|
|
|
|
|
|
|
ContentRating string `json:"contentRating"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
Name string `json:"name"` |
|
|
|
Name string `json:"name"` |
|
|
|
RecordLabel string `json:"recordLabel"` |
|
|
|
RecordLabel string `json:"recordLabel"` |
|
|
@ -1894,6 +1942,8 @@ type AutoGenerated struct { |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
HasTimeSyncedLyrics bool `json:"hasTimeSyncedLyrics"` |
|
|
|
HasTimeSyncedLyrics bool `json:"hasTimeSyncedLyrics"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
|
|
|
|
IsAppleDigitalMaster bool `json:"isAppleDigitalMaster"` |
|
|
|
|
|
|
|
ContentRating string `json:"contentRating"` |
|
|
|
DurationInMillis int `json:"durationInMillis"` |
|
|
|
DurationInMillis int `json:"durationInMillis"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
Name string `json:"name"` |
|
|
|
Name string `json:"name"` |
|
|
@ -1955,6 +2005,8 @@ type AutoGeneratedTrack struct { |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
GenreNames []string `json:"genreNames"` |
|
|
|
HasTimeSyncedLyrics bool `json:"hasTimeSyncedLyrics"` |
|
|
|
HasTimeSyncedLyrics bool `json:"hasTimeSyncedLyrics"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
IsMasteredForItunes bool `json:"isMasteredForItunes"` |
|
|
|
|
|
|
|
IsAppleDigitalMaster bool `json:"isAppleDigitalMaster"` |
|
|
|
|
|
|
|
ContentRating string `json:"contentRating"` |
|
|
|
DurationInMillis int `json:"durationInMillis"` |
|
|
|
DurationInMillis int `json:"durationInMillis"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
ReleaseDate string `json:"releaseDate"` |
|
|
|
Name string `json:"name"` |
|
|
|
Name string `json:"name"` |
|
|
|