diff --git a/README.md b/README.md index 30c0944..3525ad9 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Original script by Sorrow. Modified by me to include some fixes and improvements 7. Start downloading some albums: `go run main.go https://music.apple.com/us/album/whenever-you-need-somebody-2022-remaster/1624945511`. -8. Start downloading single : `go run main.go --song https://music.apple.com/us/album/never-gonna-give-you-up-2022-remaster/1624945511?i=1624945512`. +8. Start downloading single song: `go run main.go --song https://music.apple.com/us/album/never-gonna-give-you-up-2022-remaster/1624945511?i=1624945512` or `go run main.go https://music.apple.com/us/song/you-move-me-2022-remaster/1624945520`. 9. Start downloading select: `go run main.go --select https://music.apple.com/us/album/whenever-you-need-somebody-2022-remaster/1624945511` input numbers separated by spaces. 10. Start downloading some playlists: `go run main.go https://music.apple.com/us/playlist/taylor-swift-essentials/pl.3950454ced8c45a3b0cc693c2a7db97b` or `go run main.go https://music.apple.com/us/playlist/hi-res-lossless-24-bit-192khz/pl.u-MDAWvpjt38370N`. 11. For dolby atmos: `go run main.go --atmos https://music.apple.com/us/album/1989-taylors-version-deluxe/1713845538`. diff --git a/config.yaml b/config.yaml index 1da4d38..2dffba7 100644 --- a/config.yaml +++ b/config.yaml @@ -19,7 +19,7 @@ get-m3u8-port: "127.0.0.1:20020" get-m3u8-from-device: true #set 'all' to retrieve all m3u8, and set 'hires' to only detect hires m3u8. get-m3u8-mode: hires # all hires -aac-type: aac-lc # aac-lc aac aac-binaural aac-downmix +aac-type: aac # aac-lc aac aac-binaural aac-downmix alac-max: 192000 #192000 96000 48000 44100 atmos-max: 2768 #2768 2448 limit-max: 200 diff --git a/main.go b/main.go index 677098b..95bac42 100644 --- a/main.go +++ b/main.go @@ -100,6 +100,16 @@ func checkUrl(url string) (string, string) { return matches[0][1], matches[0][2] } } +func checkUrlSong(url string) (string, string) { + pat := regexp.MustCompile(`^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w{2})(?:\/song|\/song\/.+))\/(?:id)?(\d[^\D]+)(?:$|\?)`) + matches := pat.FindAllStringSubmatch(url, -1) + + if matches == nil { + return "", "" + } else { + return matches[0][1], matches[0][2] + } +} func checkUrlPlaylist(url string) (string, string) { pat := regexp.MustCompile(`^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w{2})(?:\/playlist|\/playlist\/.+))\/(?:id)?(pl\.[\w-]+)(?:$|\?)`) matches := pat.FindAllStringSubmatch(url, -1) @@ -121,6 +131,18 @@ func checkUrlArtist(url string) (string, string) { return matches[0][1], matches[0][2] } } +func getUrlSong(songUrl string, token string) (string, error) { + storefront, songId := checkUrlSong(songUrl) + manifest, err := getInfoFromAdam(songId, token, storefront) + if err != nil { + fmt.Println("\u26A0 Failed to get manifest:", err) + counter.NotSong++ + return "", err + } + albumId := manifest.Relationships.Albums.Data[0].ID + songAlbumUrl := fmt.Sprintf("https://music.apple.com/%s/album/1/%s?i=%s", storefront, albumId, songId) + return songAlbumUrl, nil +} func getUrlArtistName(artistUrl string, token string) (string, error) { storefront, artistId := checkUrlArtist(artistUrl) req, err := http.NewRequest("GET", fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/artists/%s", storefront, artistId), nil) @@ -1093,6 +1115,13 @@ func main() { for albumNum, urlRaw := range os.Args { fmt.Printf("Album %d of %d:\n", albumNum+1, albumTotal) var storefront, albumId string + if strings.Contains(urlRaw, "/song/") { + urlRaw, err = getUrlSong(urlRaw, token) + dl_song = true + if err != nil { + fmt.Println("Failed to get Song info.") + } + } if strings.Contains(urlRaw, "/playlist/") { storefront, albumId = checkUrlPlaylist(urlRaw) } else { @@ -1502,12 +1531,17 @@ func extractMedia(b string) (string, error) { fmt.Printf("Debug: Found Dolby Atmos variant - %s (Bitrate: %d kbps)\n", variant.Audio, variant.Bandwidth/1000) } - streamUrlTemp, err := masterUrl.Parse(variant.URI) - if err != nil { - return "", err + if int(variant.Bandwidth)/1000 <= Config.AtmosMax { + if !debug_mode { + fmt.Printf("%s\n", variant.Audio) + } + streamUrlTemp, err := masterUrl.Parse(variant.URI) + if err != nil { + return "", err + } + streamUrl = streamUrlTemp + break } - streamUrl = streamUrlTemp - break } else if variant.Codecs == "ac-3" { // Add Dolby Audio support if debug_mode { fmt.Printf("Debug: Found Dolby Audio variant - %s (Bitrate: %d kbps)\n", @@ -1528,6 +1562,9 @@ func extractMedia(b string) (string, error) { aacregex := regexp.MustCompile(`audio-stereo-\d+`) replaced := aacregex.ReplaceAllString(variant.Audio, "aac") if replaced == Config.AacType { + if !debug_mode { + fmt.Printf("%s\n", variant.Audio) + } streamUrlTemp, err := masterUrl.Parse(variant.URI) if err != nil { panic(err) @@ -1545,6 +1582,9 @@ func extractMedia(b string) (string, error) { return "", err } if length_int <= Config.AlacMax { + if !debug_mode { + fmt.Printf("%s-bit / %s Hz\n", split[length-1], split[length-2]) + } streamUrlTemp, err := masterUrl.Parse(variant.URI) if err != nil { panic(err)