@ -1019,116 +1019,6 @@ func checkUrlPlaylist(url string) (string, string) {
}
}
func checkUrlArtist ( url string ) ( string , string ) {
pat := regexp . MustCompile ( ` ^(?:https:\/\/(?:beta\.music|music)\.apple\.com\/(\w { 2})(?:\/artist|\/artist\/.+))\/(?:id)?(\d[^\D]+)(?:$|\?) ` )
matches := pat . FindAllStringSubmatch ( url , - 1 )
if matches == nil {
return "" , ""
} else {
return matches [ 0 ] [ 1 ] , matches [ 0 ] [ 2 ]
}
}
func checkArtist ( artistUrl string , token string ) ( [ ] string , error ) {
storefront , artistId := checkUrlArtist ( artistUrl )
Num := 0
var args [ ] string
var urls [ ] string
var options [ ] string
for {
req , err := http . NewRequest ( "GET" , fmt . Sprintf ( "https://amp-api.music.apple.com/v1/catalog/%s/artists/%s/albums?limit=100&offset=%d" , storefront , artistId , Num ) , 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 )
}
obj := new ( AutoGeneratedArtist )
err = json . NewDecoder ( do . Body ) . Decode ( & obj )
if err != nil {
return nil , err
}
for _ , album := range obj . Data {
urls = append ( urls , album . Attributes . URL )
options = append ( options , fmt . Sprintf ( "%s(%s)" , album . Attributes . Name , album . ID ) )
}
Num = Num + 100
if len ( obj . Next ) == 0 {
break
}
}
for i , option := range options {
fmt . Printf ( "%02d: %s\n" , i + 1 , option )
}
reader := bufio . NewReader ( os . Stdin )
fmt . Println ( "Please select from the following options (multiple options separated by commas, ranges supported, or type 'all' to select all)" )
fmt . Print ( "Enter your choice: " )
input , _ := reader . ReadString ( '\n' )
// Remove newline and whitespace
input = strings . TrimSpace ( input )
if input == "all" {
fmt . Println ( "You have selected all options:" )
return urls , nil
}
// Split input into string slices
selectedOptions := [ ] [ ] string { }
parts := strings . Split ( input , "," )
for _ , part := range parts {
if strings . Contains ( part , "-" ) { // Range setting
rangeParts := strings . Split ( part , "-" )
selectedOptions = append ( selectedOptions , rangeParts )
} else { // Single option
selectedOptions = append ( selectedOptions , [ ] string { part } )
}
}
// Print selected options
fmt . Println ( "You have selected the following options:" )
for _ , opt := range selectedOptions {
if len ( opt ) == 1 { // Single option
num , err := strconv . Atoi ( opt [ 0 ] )
if err != nil {
fmt . Println ( "Invalid option:" , opt [ 0 ] )
continue
}
if num > 0 && num <= len ( options ) {
args = append ( args , urls [ num - 1 ] )
} else {
fmt . Println ( "Option out of range:" , opt [ 0 ] )
}
} else if len ( opt ) == 2 { // Range
start , err1 := strconv . Atoi ( opt [ 0 ] )
end , err2 := strconv . Atoi ( opt [ 1 ] )
if err1 != nil || err2 != nil {
fmt . Println ( "Invalid range:" , opt )
continue
}
if start < 1 || end > len ( options ) || start > end {
fmt . Println ( "Range out of range:" , opt )
continue
}
for i := start ; i <= end ; i ++ {
args = append ( args , urls [ i - 1 ] )
}
} else {
fmt . Println ( "Invalid option:" , opt )
}
}
return args , nil
}
func getMeta ( albumId string , token string , storefront string ) ( * AutoGenerated , error ) {
var mtype string
var page int
@ -1549,14 +1439,6 @@ func main() {
fmt . Println ( "Failed to get token." )
return
}
if strings . Contains ( os . Args [ 1 ] , "/artist/" ) {
newArgs , err := checkArtist ( os . Args [ 1 ] , token )
if err != nil {
fmt . Println ( "Failed to get artist." )
return
}
os . Args = append ( [ ] string { os . Args [ 0 ] } , newArgs ... )
}
albumTotal := len ( os . Args [ 1 : ] )
for albumNum , url := range os . Args [ 1 : ] {
fmt . Printf ( "Album %d of %d:\n" , albumNum + 1 , albumTotal )
@ -2440,52 +2322,6 @@ type AutoGeneratedTrack struct {
} ` json:"data" `
}
type AutoGeneratedArtist struct {
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" `
IsAppleDigitalMaster bool ` json:"isAppleDigitalMaster" `
ContentRating string ` json:"contentRating" `
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" `
} ` json:"data" `
}
type SongLyrics struct {
Data [ ] struct {
Id string ` json:"id" `