From 3e308ab9e79a613f49a4fb306f433993f49e89d5 Mon Sep 17 00:00:00 2001 From: zhaarey Date: Sun, 7 Apr 2024 12:57:56 +0800 Subject: [PATCH] fix --- main.go | 100 +++++++++++++++++++++++++++++++++++++++ main_atmos.go | 126 ++++++++++++++++++++++++++++++++++++++++++++++++- main_select.go | 99 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 86a0c6a..bfbfb15 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ import ( "sort" "strings" "time" + "strconv" "github.com/abema/go-mp4" "github.com/grafov/m3u8" @@ -919,6 +920,7 @@ func checkUrlPlaylist(url string) (string, string) { func getMeta(albumId string, token string, storefront string) (*AutoGenerated, error) { var mtype string + var page int if strings.Contains(albumId, "pl.") { mtype = "playlists" } else { @@ -953,6 +955,42 @@ func getMeta(albumId string, token string, storefront string) (*AutoGenerated, e if err != nil { return nil, err } + if strings.Contains(albumId, "pl.") { + obj.Data[0].Attributes.ArtistName="Apple Music" + if len(obj.Data[0].Relationships.Tracks.Next) > 0 { + page=0 + for{ + page=page+100 + pageStr := strconv.Itoa(page) + req, err := http.NewRequest("GET", fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/%s/%s/tracks?offset=%s", storefront, mtype, albumId, pageStr), nil) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") + req.Header.Set("Origin", "https://music.apple.com") + do, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer do.Body.Close() + if do.StatusCode != http.StatusOK { + return nil, errors.New(do.Status) + } + obj2 := new(AutoGeneratedTrack) + err = json.NewDecoder(do.Body).Decode(&obj2) + if err != nil { + return nil, err + } + for _, value := range obj2.Data { + obj.Data[0].Relationships.Tracks.Data = append(obj.Data[0].Relationships.Tracks.Data, value) + } + if len(obj2.Next)==0{ + break + } + } + } + } return obj, nil } @@ -1001,6 +1039,9 @@ func rip(albumId string, token string, storefront string) error { return err } albumFolder := fmt.Sprintf("%s - %s", meta.Data[0].Attributes.ArtistName, meta.Data[0].Attributes.Name) + if strings.HasSuffix(albumFolder, ".") { + albumFolder = strings.ReplaceAll(albumFolder, ".", "") + } sanAlbumFolder := filepath.Join("AM-DL downloads", forbiddenNames.ReplaceAllString(albumFolder, "_")) os.MkdirAll(sanAlbumFolder, os.ModePerm) fmt.Println(albumFolder) @@ -1609,6 +1650,7 @@ type AutoGenerated struct { } `json:"artists"` Tracks struct { Href string `json:"href"` + Next string `json:"next"` Data []struct { ID string `json:"id"` Type string `json:"type"` @@ -1666,3 +1708,61 @@ type AutoGenerated struct { } `json:"relationships"` } `json:"data"` } + +type AutoGeneratedTrack struct { + Href string `json:"href"` + Next string `json:"next"` + Data []struct { + ID string `json:"id"` + Type string `json:"type"` + Href string `json:"href"` + Attributes struct { + Previews []struct { + URL string `json:"url"` + } `json:"previews"` + Artwork struct { + Width int `json:"width"` + Height int `json:"height"` + URL string `json:"url"` + BgColor string `json:"bgColor"` + TextColor1 string `json:"textColor1"` + TextColor2 string `json:"textColor2"` + TextColor3 string `json:"textColor3"` + TextColor4 string `json:"textColor4"` + } `json:"artwork"` + ArtistName string `json:"artistName"` + URL string `json:"url"` + DiscNumber int `json:"discNumber"` + GenreNames []string `json:"genreNames"` + HasTimeSyncedLyrics bool `json:"hasTimeSyncedLyrics"` + IsMasteredForItunes bool `json:"isMasteredForItunes"` + DurationInMillis int `json:"durationInMillis"` + ReleaseDate string `json:"releaseDate"` + Name string `json:"name"` + Isrc string `json:"isrc"` + AudioTraits []string `json:"audioTraits"` + HasLyrics bool `json:"hasLyrics"` + AlbumName string `json:"albumName"` + PlayParams struct { + ID string `json:"id"` + Kind string `json:"kind"` + } `json:"playParams"` + TrackNumber int `json:"trackNumber"` + AudioLocale string `json:"audioLocale"` + ComposerName string `json:"composerName"` + } `json:"attributes"` + Relationships struct { + Artists struct { + Href string `json:"href"` + Data []struct { + ID string `json:"id"` + Type string `json:"type"` + Href string `json:"href"` + Attributes struct { + Name string `json:"name"` + } `json:"attributes"` + } `json:"data"` + } `json:"artists"` + } `json:"relationships"` + } `json:"data"` +} \ No newline at end of file diff --git a/main_atmos.go b/main_atmos.go index e0c7bd3..bd64f0c 100644 --- a/main_atmos.go +++ b/main_atmos.go @@ -18,6 +18,7 @@ import ( "sort" "strings" "time" + "strconv" "github.com/abema/go-mp4" "github.com/grafov/m3u8" @@ -909,8 +910,26 @@ func checkUrl(url string) (string, string) { } } +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) + + if matches == nil { + return "", "" + } else { + return matches[0][1], matches[0][2] + } +} + func getMeta(albumId string, token string, storefront string) (*AutoGenerated, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/albums/%s", storefront, albumId), nil) + var mtype string + var page int + if strings.Contains(albumId, "pl.") { + mtype = "playlists" + } else { + mtype = "albums" + } + req, err := http.NewRequest("GET", fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/%s/%s", storefront,mtype, albumId), nil) if err != nil { return nil, err } @@ -939,6 +958,42 @@ func getMeta(albumId string, token string, storefront string) (*AutoGenerated, e if err != nil { return nil, err } + if strings.Contains(albumId, "pl.") { + obj.Data[0].Attributes.ArtistName="Apple Music" + if len(obj.Data[0].Relationships.Tracks.Next) > 0 { + page=0 + for{ + page=page+100 + pageStr := strconv.Itoa(page) + req, err := http.NewRequest("GET", fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/%s/%s/tracks?offset=%s", storefront, mtype, albumId, pageStr), nil) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") + req.Header.Set("Origin", "https://music.apple.com") + do, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer do.Body.Close() + if do.StatusCode != http.StatusOK { + return nil, errors.New(do.Status) + } + obj2 := new(AutoGeneratedTrack) + err = json.NewDecoder(do.Body).Decode(&obj2) + if err != nil { + return nil, err + } + for _, value := range obj2.Data { + obj.Data[0].Relationships.Tracks.Data = append(obj.Data[0].Relationships.Tracks.Data, value) + } + if len(obj2.Next)==0{ + break + } + } + } + } return obj, nil } @@ -985,6 +1040,9 @@ func rip(albumId string, token string, storefront string) error { return err } albumFolder := fmt.Sprintf("%s - %s", meta.Data[0].Attributes.ArtistName, meta.Data[0].Attributes.Name) + if strings.HasSuffix(albumFolder, ".") { + albumFolder = strings.ReplaceAll(albumFolder, ".", "") + } sanAlbumFolder := filepath.Join("AM-DL downloads", forbiddenNames.ReplaceAllString(albumFolder, "_")) os.MkdirAll(sanAlbumFolder, os.ModePerm) fmt.Println(albumFolder) @@ -1056,7 +1114,12 @@ func main() { albumTotal := len(os.Args[1:]) for albumNum, url := range os.Args[1:] { fmt.Printf("Album %d of %d:\n", albumNum+1, albumTotal) - storefront, albumId := checkUrl(url) + var storefront, albumId string + if strings.Contains(url, "playlist") { + storefront, albumId = checkUrlPlaylist(url) + } else { + storefront, albumId = checkUrl(url) + } if albumId == "" { fmt.Printf("Invalid URL: %s\n", url) continue @@ -1586,6 +1649,7 @@ type AutoGenerated struct { } `json:"artists"` Tracks struct { Href string `json:"href"` + Next string `json:"next"` Data []struct { ID string `json:"id"` Type string `json:"type"` @@ -1643,3 +1707,61 @@ type AutoGenerated struct { } `json:"relationships"` } `json:"data"` } + +type AutoGeneratedTrack struct { + Href string `json:"href"` + Next string `json:"next"` + Data []struct { + ID string `json:"id"` + Type string `json:"type"` + Href string `json:"href"` + Attributes struct { + Previews []struct { + URL string `json:"url"` + } `json:"previews"` + Artwork struct { + Width int `json:"width"` + Height int `json:"height"` + URL string `json:"url"` + BgColor string `json:"bgColor"` + TextColor1 string `json:"textColor1"` + TextColor2 string `json:"textColor2"` + TextColor3 string `json:"textColor3"` + TextColor4 string `json:"textColor4"` + } `json:"artwork"` + ArtistName string `json:"artistName"` + URL string `json:"url"` + DiscNumber int `json:"discNumber"` + GenreNames []string `json:"genreNames"` + HasTimeSyncedLyrics bool `json:"hasTimeSyncedLyrics"` + IsMasteredForItunes bool `json:"isMasteredForItunes"` + DurationInMillis int `json:"durationInMillis"` + ReleaseDate string `json:"releaseDate"` + Name string `json:"name"` + Isrc string `json:"isrc"` + AudioTraits []string `json:"audioTraits"` + HasLyrics bool `json:"hasLyrics"` + AlbumName string `json:"albumName"` + PlayParams struct { + ID string `json:"id"` + Kind string `json:"kind"` + } `json:"playParams"` + TrackNumber int `json:"trackNumber"` + AudioLocale string `json:"audioLocale"` + ComposerName string `json:"composerName"` + } `json:"attributes"` + Relationships struct { + Artists struct { + Href string `json:"href"` + Data []struct { + ID string `json:"id"` + Type string `json:"type"` + Href string `json:"href"` + Attributes struct { + Name string `json:"name"` + } `json:"attributes"` + } `json:"data"` + } `json:"artists"` + } `json:"relationships"` + } `json:"data"` +} \ No newline at end of file diff --git a/main_select.go b/main_select.go index edb2e36..03c099c 100644 --- a/main_select.go +++ b/main_select.go @@ -921,6 +921,7 @@ func checkUrlPlaylist(url string) (string, string) { func getMeta(albumId string, token string, storefront string) (*AutoGenerated, error) { var mtype string + var page int if strings.Contains(albumId, "pl.") { mtype = "playlists" } else { @@ -955,6 +956,42 @@ func getMeta(albumId string, token string, storefront string) (*AutoGenerated, e if err != nil { return nil, err } + if strings.Contains(albumId, "pl.") { + obj.Data[0].Attributes.ArtistName="Apple Music" + if len(obj.Data[0].Relationships.Tracks.Next) > 0 { + page=0 + for{ + page=page+100 + pageStr := strconv.Itoa(page) + req, err := http.NewRequest("GET", fmt.Sprintf("https://amp-api.music.apple.com/v1/catalog/%s/%s/%s/tracks?offset=%s", storefront, mtype, albumId, pageStr), nil) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") + req.Header.Set("Origin", "https://music.apple.com") + do, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer do.Body.Close() + if do.StatusCode != http.StatusOK { + return nil, errors.New(do.Status) + } + obj2 := new(AutoGeneratedTrack) + err = json.NewDecoder(do.Body).Decode(&obj2) + if err != nil { + return nil, err + } + for _, value := range obj2.Data { + obj.Data[0].Relationships.Tracks.Data = append(obj.Data[0].Relationships.Tracks.Data, value) + } + if len(obj2.Next)==0{ + break + } + } + } + } return obj, nil } @@ -1011,6 +1048,9 @@ func rip(albumId string, token string, storefront string) error { return err } albumFolder := fmt.Sprintf("%s - %s", meta.Data[0].Attributes.ArtistName, meta.Data[0].Attributes.Name) + if strings.HasSuffix(albumFolder, ".") { + albumFolder = strings.ReplaceAll(albumFolder, ".", "") + } sanAlbumFolder := filepath.Join("AM-DL downloads", forbiddenNames.ReplaceAllString(albumFolder, "_")) os.MkdirAll(sanAlbumFolder, os.ModePerm) fmt.Println(albumFolder) @@ -1648,6 +1688,7 @@ type AutoGenerated struct { } `json:"artists"` Tracks struct { Href string `json:"href"` + Next string `json:"next"` Data []struct { ID string `json:"id"` Type string `json:"type"` @@ -1705,3 +1746,61 @@ type AutoGenerated struct { } `json:"relationships"` } `json:"data"` } + +type AutoGeneratedTrack struct { + Href string `json:"href"` + Next string `json:"next"` + Data []struct { + ID string `json:"id"` + Type string `json:"type"` + Href string `json:"href"` + Attributes struct { + Previews []struct { + URL string `json:"url"` + } `json:"previews"` + Artwork struct { + Width int `json:"width"` + Height int `json:"height"` + URL string `json:"url"` + BgColor string `json:"bgColor"` + TextColor1 string `json:"textColor1"` + TextColor2 string `json:"textColor2"` + TextColor3 string `json:"textColor3"` + TextColor4 string `json:"textColor4"` + } `json:"artwork"` + ArtistName string `json:"artistName"` + URL string `json:"url"` + DiscNumber int `json:"discNumber"` + GenreNames []string `json:"genreNames"` + HasTimeSyncedLyrics bool `json:"hasTimeSyncedLyrics"` + IsMasteredForItunes bool `json:"isMasteredForItunes"` + DurationInMillis int `json:"durationInMillis"` + ReleaseDate string `json:"releaseDate"` + Name string `json:"name"` + Isrc string `json:"isrc"` + AudioTraits []string `json:"audioTraits"` + HasLyrics bool `json:"hasLyrics"` + AlbumName string `json:"albumName"` + PlayParams struct { + ID string `json:"id"` + Kind string `json:"kind"` + } `json:"playParams"` + TrackNumber int `json:"trackNumber"` + AudioLocale string `json:"audioLocale"` + ComposerName string `json:"composerName"` + } `json:"attributes"` + Relationships struct { + Artists struct { + Href string `json:"href"` + Data []struct { + ID string `json:"id"` + Type string `json:"type"` + Href string `json:"href"` + Attributes struct { + Name string `json:"name"` + } `json:"attributes"` + } `json:"data"` + } `json:"artists"` + } `json:"relationships"` + } `json:"data"` +} \ No newline at end of file