├── README.md ├── gmusicgo.go ├── lib ├── clientlogin │ └── clientlogin.go ├── gmusicjson │ └── gmusicjson.go ├── login │ └── login.go ├── playlist │ └── playlist.go ├── plentry │ └── plentry.go ├── request │ └── request.go ├── stream │ └── stream.go ├── tokens │ └── tokens.go └── track │ └── track.go ├── process.txt └── test └── test.go /README.md: -------------------------------------------------------------------------------- 1 | # gmusicgo 2 | ## Disclaimer 3 | The Google Play Music has been [deprecated](https://blog.youtube/news-and-events/youtube-music-will-replace-google-play-music-end-2020/). 4 | 5 | ## Description 6 | 7 | Gmusicgo is a [Google Music](https://music.google.com) API written in [Go](http://golang.org/). 8 | 9 | For details on the ClientLogin authorization, read the documentation of the [original implementation](https://github.com/aleics/Google-Play-Music-for-TV-Interface) in PHP. 10 | 11 | 12 | -------------------------------------------------------------------------------- /gmusicgo.go: -------------------------------------------------------------------------------- 1 | package gmusicgo 2 | 3 | import ( 4 | "errors" 5 | "github.com/aleics/gmusicgo/lib/clientlogin" 6 | "github.com/aleics/gmusicgo/lib/gmusicjson" 7 | "github.com/aleics/gmusicgo/lib/playlist" 8 | "github.com/aleics/gmusicgo/lib/plentry" 9 | "github.com/aleics/gmusicgo/lib/stream" 10 | "github.com/aleics/gmusicgo/lib/tokens" 11 | "github.com/aleics/gmusicgo/lib/track" 12 | "os" 13 | ) 14 | 15 | type Gmusicgo struct { 16 | gclient clientlogin.Clientlogin 17 | gtokens tokens.Tokens 18 | gtracks []track.Track 19 | gplaylists []playlist.Playlist 20 | gplentries []plentry.Plentry 21 | gstream stream.Stream 22 | } 23 | 24 | func Init() *Gmusicgo { 25 | gmusic := new(Gmusicgo) 26 | gmusic.gclient = *clientlogin.Init() 27 | gmusic.gtokens = *tokens.Init() 28 | gmusic.gtracks = make([]track.Track, 0) 29 | gmusic.gplaylists = make([]playlist.Playlist, 0) 30 | gmusic.gplentries = make([]plentry.Plentry, 0) 31 | gmusic.gstream = *stream.Init() 32 | return gmusic 33 | } 34 | func (g Gmusicgo) GetGmusicgo() Gmusicgo { 35 | return g 36 | } 37 | func (g Gmusicgo) SetGmusicgo(gm Gmusicgo) { 38 | g = gm 39 | } 40 | func (g Gmusicgo) GetGclient() clientlogin.Clientlogin { 41 | return g.gclient 42 | } 43 | func (g *Gmusicgo) SetGclient(gc clientlogin.Clientlogin) { 44 | g.gclient = gc 45 | } 46 | func (g Gmusicgo) GetGtokens() tokens.Tokens { 47 | return g.gtokens 48 | } 49 | func (g *Gmusicgo) SetGtokens(gt tokens.Tokens) { 50 | g.gtokens = gt 51 | } 52 | func (g Gmusicgo) GetGtracks() []track.Track { 53 | return g.gtracks 54 | } 55 | func (g *Gmusicgo) SetGtracks(gtr []track.Track) { 56 | g.gtracks = gtr 57 | } 58 | func (g Gmusicgo) GetGplaylists() []playlist.Playlist { 59 | return g.gplaylists 60 | } 61 | func (g *Gmusicgo) SetGplaylists(gpla []playlist.Playlist) { 62 | g.gplaylists = gpla 63 | } 64 | func (g Gmusicgo) GetGplentries() []plentry.Plentry { 65 | return g.gplentries 66 | } 67 | func (g *Gmusicgo) SetGplentries(gple []plentry.Plentry) { 68 | g.gplentries = gple 69 | } 70 | 71 | func (g *Gmusicgo) Connect(accountType string, email string, passwd string, service string, source string, path string) error { 72 | 73 | header := [5]string{accountType, email, passwd, service, source} 74 | g.gclient.SetHeader(accountType, email, passwd, service, source) 75 | 76 | if g.gclient.MakeRequest(header)[0] != "200 OK" { 77 | return errors.New("Error clientlogin request") 78 | os.Exit(1) 79 | } 80 | 81 | if g.gtokens.MakeRequest(g.gclient.GetAuth())[0] != "200 OK" { 82 | return errors.New("Error tokens request") 83 | os.Exit(1) 84 | } 85 | 86 | if path != "" { 87 | g.gclient.SaveInfo(path) 88 | g.gtokens.SaveInfo(path) 89 | } 90 | 91 | g.gtracks = track.TracksRequest(g.gclient.GetAuth(), path) 92 | if g.gtracks[0].GetId() == "" { 93 | return errors.New("Error track request") 94 | os.Exit(1) 95 | } 96 | 97 | g.gplaylists = playlist.PlaylistsRequest(g.gclient.GetAuth(), path) 98 | if g.gplaylists[0].GetId() == "" { 99 | return errors.New("Error playlist request") 100 | os.Exit(1) 101 | } 102 | 103 | g.gplentries = plentry.PlentryRequest(g.gclient.GetAuth(), path) 104 | if g.gplentries[0].GetId() == "" { 105 | return errors.New("Error plentry request") 106 | os.Exit(1) 107 | } 108 | 109 | return nil 110 | } 111 | func (g *Gmusicgo) Update(path string) error { 112 | 113 | if path != "" { 114 | g.gclient.SaveInfo(path) 115 | g.gtokens.SaveInfo(path) 116 | } 117 | 118 | g.gtracks = track.TracksRequest(g.gclient.GetAuth(), path) 119 | if g.gtracks[0].GetId() == "" { 120 | return errors.New("Error track request") 121 | os.Exit(1) 122 | } 123 | 124 | g.gplaylists = playlist.PlaylistsRequest(g.gclient.GetAuth(), path) 125 | if g.gplaylists[0].GetId() == "" { 126 | return errors.New("Error playlist request") 127 | os.Exit(1) 128 | } 129 | 130 | g.gplentries = plentry.PlentryRequest(g.gclient.GetAuth(), path) 131 | if g.gplentries[0].GetId() == "" { 132 | return errors.New("Error plentry request") 133 | os.Exit(1) 134 | } 135 | 136 | return nil 137 | } 138 | func (g Gmusicgo) TracksToMap() ([]map[string]string, error) { 139 | thisMap := make([]map[string]string, 0) 140 | for i := 0; i < len(g.gtracks); i++ { 141 | thisMap = append(thisMap, g.gtracks[i].ToMap()) 142 | } 143 | if len(thisMap) == 0 { 144 | return thisMap, errors.New("Tracks struct empty or error on the function: TracksToMap()") 145 | } 146 | return thisMap, nil 147 | } 148 | func (g Gmusicgo) PlaylistsToMap() ([]map[string]string, error) { 149 | thisMap := make([]map[string]string, 0) 150 | for i := 0; i < len(g.gplaylists); i++ { 151 | thisMap = append(thisMap, g.gplaylists[i].ToMap()) 152 | } 153 | if len(thisMap) == 0 { 154 | return thisMap, errors.New("Playlists struct empty or error on the function: PlaylistsToMap()") 155 | } 156 | return thisMap, nil 157 | } 158 | func (g Gmusicgo) PlentriesToMap() ([]map[string]string, error) { 159 | thisMap := make([]map[string]string, 0) 160 | for i := 0; i < len(g.gplentries); i++ { 161 | thisMap = append(thisMap, g.gplentries[i].ToMap()) 162 | } 163 | if len(thisMap) == 0 { 164 | return thisMap, errors.New("Plentries struct empty or error on the function: PlentriesToMap()") 165 | } 166 | return thisMap, nil 167 | } 168 | 169 | func (g *Gmusicgo) GetSong(songid string, path string) error { 170 | err := g.gstream.StreamRequest(g.gclient.GetAuth(), g.gtokens.GetXt(), songid, path) 171 | if err != nil { 172 | return errors.New("Error stream request") 173 | } 174 | return nil 175 | } 176 | func (g *Gmusicgo) CreatePlaylist(name string, description string, public bool) error { 177 | err := g.gplaylists[0].CreatePlaylist(g.gclient.GetAuth(), g.gtokens.GetXt(), name, description, public) 178 | if err != true { 179 | return errors.New("Error creating playlist: " + name) 180 | } 181 | return nil 182 | } 183 | 184 | func (g *Gmusicgo) LoadUserPlaylist() error { 185 | err := g.gplaylists[0].LoadUserPlaylist(g.gclient.GetAuth(), g.gtokens.GetXt()) 186 | if err != true { 187 | return errors.New("Error loading playlists") 188 | } 189 | return nil 190 | } 191 | 192 | func (g *Gmusicgo) DeletePlaylist(id string) error { 193 | err := g.gplaylists[0].DeletePlaylist(g.gclient.GetAuth(), g.gtokens.GetXt(), id) 194 | if err != true { 195 | return errors.New("Error deleting playlist: " + id) 196 | } 197 | return nil 198 | } 199 | 200 | func (g Gmusicgo) GetIdBySongTitle(songname string) (string, error) { 201 | for i := 0; i < len(g.gtracks); i++ { 202 | if g.gtracks[i].GetTitle() == songname { 203 | return g.gtracks[i].GetId(), nil 204 | } 205 | } 206 | return "", errors.New("Song name not found") 207 | 208 | } 209 | func (g Gmusicgo) GetIdsByArtist(artistname string) ([]string, error) { 210 | out := make([]string, 0) 211 | for i := 0; i < len(g.gtracks); i++ { 212 | if g.gtracks[i].GetArtist() == artistname { 213 | out = append(out, g.gtracks[i].GetId()) 214 | } 215 | } 216 | 217 | if len(out) == 0 { 218 | return out, errors.New("Artist name not found") 219 | } 220 | return out, nil 221 | } 222 | func (g Gmusicgo) GetIdsByAlbum(albumname string) ([]string, error) { 223 | out := make([]string, 0) 224 | for i := 0; i < len(g.gtracks); i++ { 225 | if g.gtracks[i].GetAlbum() == albumname { 226 | out = append(out, g.gtracks[i].GetId()) 227 | } 228 | } 229 | 230 | if len(out) == 0 { 231 | return out, errors.New("Album name not found") 232 | } 233 | 234 | return out, nil 235 | } 236 | func (g Gmusicgo) GetIdsByPlaylist(playlistname string) ([]string, error) { 237 | pla_id := "" 238 | for i := 0; i < len(g.gplaylists); i++ { 239 | if g.gplaylists[i].GetName() == playlistname { 240 | pla_id = g.gplaylists[i].GetId() 241 | } 242 | } 243 | 244 | out := make([]string, 0) 245 | for i := 0; i < len(g.gplentries); i++ { 246 | if g.gplentries[i].GetPlaylistId() == pla_id { 247 | out = append(out, g.gplentries[i].GetTrackId()) 248 | } 249 | } 250 | 251 | if len(out) == 0 { 252 | return out, errors.New("Playlist name not found") 253 | } 254 | 255 | return out, nil 256 | } 257 | 258 | func (g Gmusicgo) Export(path string) error { 259 | _, err := gmusicjson.Export(g.gclient, path+"userinfo.json") 260 | if err != nil { 261 | return errors.New("Error exporting User Info") 262 | } 263 | _, err = gmusicjson.Export(g.gtokens, path+"tokens.json") 264 | if err != nil { 265 | return errors.New("Error exporting Tokens") 266 | } 267 | _, err = gmusicjson.Export(g.gtracks, path+"tracks.json") 268 | if err != nil { 269 | return errors.New("Error exporting Tracks") 270 | } 271 | _, err = gmusicjson.Export(g.gplaylists, path+"playlists.json") 272 | if err != nil { 273 | return errors.New("Error exporting Playlists") 274 | } 275 | _, err = gmusicjson.Export(g.gplentries, path+"plentries.json") 276 | if err != nil { 277 | return errors.New("Error exporting Plentries") 278 | } 279 | return nil 280 | } 281 | 282 | func (g *Gmusicgo) Import(path string) error { 283 | err := gmusicjson.Import(path+"userinfo.json", &g.gclient) 284 | if err != nil { 285 | return errors.New("Error importing User Info") 286 | } 287 | err = gmusicjson.Import(path+"tokens.json", &g.gtokens) 288 | if err != nil { 289 | return errors.New("Error importing Tokens") 290 | } 291 | err = gmusicjson.Import(path+"tracks.json", &g.gtracks) 292 | if err != nil { 293 | return errors.New("Error importing Tracks") 294 | } 295 | err = gmusicjson.Import(path+"playlists.json", &g.gplaylists) 296 | if err != nil { 297 | return errors.New("Error importing Playlists") 298 | } 299 | err = gmusicjson.Import(path+"plentries.json", &g.gplentries) 300 | if err != nil { 301 | return errors.New("Error importing Plentries") 302 | } 303 | 304 | return nil 305 | } 306 | -------------------------------------------------------------------------------- /lib/clientlogin/clientlogin.go: -------------------------------------------------------------------------------- 1 | package clientlogin 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/aleics/gmusicgo/lib/gmusicjson" 7 | "io/ioutil" 8 | "net/http" 9 | "net/url" 10 | "strings" 11 | ) 12 | 13 | //Clientlogin structure 14 | type Clientlogin struct { 15 | Auth string `json:"auth"` 16 | Header [5]string `json:"header"` 17 | } 18 | 19 | func Init() *Clientlogin { //Initialize the Clientlogin structure with default values 20 | c := new(Clientlogin) 21 | return c 22 | } 23 | func (c Clientlogin) GetAuth() string { //Get auth value 24 | return c.Auth 25 | } 26 | func (c *Clientlogin) SetAuth(s string) { //Modify auth value 27 | c.Auth = s 28 | } 29 | func (c *Clientlogin) SetHeader(accountType, email, passwd, service, source string) { //Modify header values 30 | c.Header[0] = accountType 31 | c.Header[1] = email 32 | c.Header[2] = passwd 33 | c.Header[3] = service 34 | c.Header[4] = source 35 | } 36 | func (c Clientlogin) GetHeader() [5]string { //Get header 37 | return c.Header 38 | } 39 | func (c Clientlogin) AccountType() string { //Get accountType of header 40 | return c.Header[0] 41 | } 42 | func (c Clientlogin) User() string { //Get user of header 43 | return c.Header[1] 44 | } 45 | func (c Clientlogin) Passwd() string { //Get password of header 46 | return c.Header[2] 47 | } 48 | func (c Clientlogin) Service() string { //Get name of the service of the header 49 | return c.Header[3] 50 | } 51 | func (c Clientlogin) Source() string { //Get the source of the header 52 | return c.Header[4] 53 | } 54 | 55 | func (c *Clientlogin) MakeRequest(header [5]string) [2]string { //Make the ClientLogin Request. Return the response code and body 56 | 57 | //Host that will be done the request 58 | hostname := "https://developers.google.com" 59 | resource := "/accounts/docs/AuthForInstalledApps" 60 | 61 | //POST values 62 | data := url.Values{} 63 | data.Add("accountType", header[0]) 64 | data.Add("Email", header[1]) 65 | data.Add("Passwd", header[2]) 66 | data.Add("service", header[3]) 67 | data.Add("source", header[4]) 68 | 69 | //Hostname in URL structure 70 | u, _ := url.ParseRequestURI(hostname) 71 | u.Path = resource 72 | urlStr := fmt.Sprintf("%v", u) //Save the URL of the request in urlStr 73 | 74 | cl := &http.Client{} //Initialize Client request 75 | r, _ := http.NewRequest("POST", urlStr, bytes.NewBufferString(data.Encode())) //Insert the values on the request 76 | r.Header.Add("Content-Type", "application/x-www-form-urlencoded") //Add Content-type header 77 | 78 | resp, err := cl.Do(r) //Make the request 79 | if err != nil { //Error management 80 | return [2]string{"404 Not Found", ""} 81 | } 82 | 83 | defer resp.Body.Close() 84 | fmt.Println(r) 85 | b, err := ioutil.ReadAll(resp.Body) //Get the body of the response 86 | if err != nil { //Error management 87 | return [2]string{"404 Not Found", ""} 88 | } 89 | 90 | body := string(b[:]) 91 | 92 | response := [2]string{resp.Status, body} 93 | fmt.Println(response) 94 | 95 | //Delete "Auth=" of the string and save it on auth variable of ClientLogin structure 96 | c.Auth = response[1][(strings.LastIndex(response[1], "Auth="))+5 : (len(response[1]) - 1)] 97 | 98 | return response //Return response array (status,body) 99 | } 100 | 101 | func (c Clientlogin) SaveInfo(path string) bool { //Save UserInfo in one JSON file. Return true if the info was properly saved 102 | 103 | p := []string{path, "userinfo.json"} //Path and name of the file 104 | jsonpath := strings.Join(p, "") 105 | 106 | _, err := gmusicjson.Export(c, jsonpath) 107 | if err != nil { 108 | fmt.Println(err) 109 | return false 110 | } 111 | return true 112 | } 113 | -------------------------------------------------------------------------------- /lib/gmusicjson/gmusicjson.go: -------------------------------------------------------------------------------- 1 | package gmusicjson 2 | 3 | import ( 4 | "errors" 5 | "io/ioutil" 6 | "encoding/json" 7 | ) 8 | 9 | type Gmusicjson struct{ 10 | } 11 | 12 | func Deserialize(t interface{}) ([]byte, error){ 13 | return json.Marshal(t) 14 | return json.Marshal(nil) 15 | } 16 | 17 | func Import(path string, t interface{}) (error) { 18 | if path != "" { 19 | dat, err := ioutil.ReadFile(path) 20 | if err != nil{ 21 | return errors.New("Error importing JSON: reading file") 22 | } 23 | err = json.Unmarshal(dat, &t) 24 | if err != nil { 25 | return errors.New("Error importing JSON: Unmarshaling file") 26 | } 27 | return nil 28 | } 29 | return errors.New("Error importing JSON: path parameter empty") 30 | } 31 | 32 | func Export(input interface{}, path string) (string, error) { 33 | output, err := Deserialize(input) 34 | if err != nil { 35 | return string(output), errors.New("Error exporting JSON: deserializing struct") 36 | } 37 | 38 | if path != "" { 39 | err = ioutil.WriteFile(path, output, 0644) 40 | if err != nil { 41 | return string(output), errors.New("Error exporting JSON: writing file") 42 | } 43 | } 44 | 45 | if string(output) == "" { 46 | return string(output), errors.New("Error exporting JSON: return empty") 47 | } else { 48 | return string(output), nil 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/login/login.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "github.com/headzoo/surf" 5 | "errors" 6 | ) 7 | 8 | //Tokens type 9 | type Tokens struct { 10 | Xt string 11 | SID string 12 | } 13 | 14 | 15 | //Login type 16 | type Login struct { 17 | Email string 18 | Passwd string 19 | } 20 | 21 | //GetSID to get the credentials for the user 22 | func (l *Login) GetSID() (string, error) { 23 | bow := surf.NewBrowser() 24 | bow.AddRequestHeader("service", "sj") 25 | bow.AddRequestHeader("continue", "https://play.google.com/music/listen") 26 | 27 | err := bow.Open("https://accounts.google.com/ServiceLoginAuth") 28 | if err != nil { 29 | return "", errors.New("Error opening browser.") 30 | } 31 | 32 | fm, err := bow.Form("[id='gaia_loginform']") 33 | if err != nil { 34 | return "", errors.New("Error getting form.") 35 | } 36 | 37 | err = fm.Input("Email", l.Email) 38 | if err != nil { 39 | return "", err 40 | } 41 | 42 | err = fm.Submit() 43 | if err != nil { 44 | return "", errors.New("Error submitting form.") 45 | } 46 | 47 | fm, err = bow.Form("form") 48 | if err != nil { 49 | return "", err 50 | } 51 | 52 | err = fm.Input("Passwd", l.Passwd) 53 | if err != nil { 54 | return "", err 55 | } 56 | err = fm.Submit() 57 | if err != nil { 58 | return "", err 59 | } 60 | 61 | cookies := bow.SiteCookies() 62 | for _, v := range cookies { 63 | if v.Name == "SID" { 64 | return v.Value, nil 65 | } 66 | } 67 | 68 | return "", nil 69 | } -------------------------------------------------------------------------------- /lib/playlist/playlist.go: -------------------------------------------------------------------------------- 1 | package playlist 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/aleics/gmusicgo/lib/gmusicjson" 8 | "github.com/aleics/gmusicgo/lib/request" 9 | "io/ioutil" 10 | "net/http" 11 | "net/url" 12 | "os" 13 | "strconv" 14 | "strings" 15 | "time" 16 | ) 17 | 18 | type Playlist struct { 19 | Kind string `json:"kind"` 20 | Id string `json:"id"` 21 | CreationTimestamp string `json:"creationTimestamp"` 22 | LastModifiedTimestamp string `json:"lastModifiedTimestamp"` 23 | Deleted bool `json:"deleted"` 24 | Name string `json:"name"` 25 | TypePlaylist string `json:typePlaylist` 26 | } 27 | 28 | func Init() *Playlist { 29 | p := new(Playlist) 30 | return p 31 | } 32 | func ArrayInit() (p *[]Playlist) { 33 | return p 34 | } 35 | func (p Playlist) GetKind() string { 36 | return p.Kind 37 | } 38 | func (p *Playlist) SetKind(kind string) { 39 | p.Kind = kind 40 | } 41 | func (p Playlist) GetId() string { 42 | return p.Id 43 | } 44 | func (p *Playlist) SetId(id string) { 45 | p.Id = id 46 | } 47 | func (p Playlist) GetCreationTimestamp() string { 48 | return p.CreationTimestamp 49 | } 50 | func (p *Playlist) SetCreationTimestamp(creationTimestamp string) { 51 | p.CreationTimestamp = creationTimestamp 52 | } 53 | func (p Playlist) GetLastModifiedTimestamp() string { 54 | return p.LastModifiedTimestamp 55 | } 56 | func (p *Playlist) SetLastModifiedTimestamp(lastModifiedTimestamp string) { 57 | p.LastModifiedTimestamp = lastModifiedTimestamp 58 | } 59 | func (p Playlist) GetDeleted() bool { 60 | return p.Deleted 61 | } 62 | func (p *Playlist) SetDeleted(deleted bool) { 63 | p.Deleted = deleted 64 | } 65 | func (p Playlist) GetName() string { 66 | return p.Name 67 | } 68 | func (p *Playlist) SetName(name string) { 69 | p.Name = name 70 | } 71 | func (p Playlist) GetType() string { 72 | return p.TypePlaylist 73 | } 74 | func (p *Playlist) SetType(typePlaylist string) { 75 | p.TypePlaylist = typePlaylist 76 | } 77 | func (p *Playlist) NewPlaylist(kind string, id string, creationTimestamp string, lastModifiedTimestamp string, deleted bool, name string, typePlaylist string) { 78 | 79 | p.Kind = kind 80 | p.Id = id 81 | p.CreationTimestamp = creationTimestamp 82 | p.LastModifiedTimestamp = lastModifiedTimestamp 83 | p.Deleted = deleted 84 | p.Name = name 85 | p.TypePlaylist = typePlaylist 86 | } 87 | func (p Playlist) ToMap() map[string]string { 88 | 89 | ret := make(map[string]string) 90 | 91 | ret["kind"] = p.Kind 92 | ret["id"] = p.Id 93 | ret["creationTimestamp"] = p.CreationTimestamp 94 | ret["lastModifiedTimestamp"] = p.LastModifiedTimestamp 95 | ret["deleted"] = strconv.FormatBool(p.Deleted) 96 | ret["name"] = p.Name 97 | ret["typePlaylist"] = p.TypePlaylist 98 | 99 | return ret 100 | } 101 | func PlaylistsRequest(auth string, path string) []Playlist { 102 | 103 | hostname := "https://www.googleapis.com" 104 | resource := "/sj/v1beta1/playlists" 105 | 106 | u, _ := url.ParseRequestURI(hostname) 107 | u.Path = resource 108 | urlStr := fmt.Sprintf("%v", u) 109 | 110 | cl := &http.Client{} 111 | 112 | r, err := http.NewRequest("GET", urlStr, nil) 113 | if err != nil { 114 | os.Exit(1) 115 | } 116 | 117 | auth_header := "GoogleLogin auth=" + auth 118 | 119 | r.Header.Add("Authorization", auth_header) 120 | 121 | resp, err := cl.Do(r) 122 | if err != nil { 123 | os.Exit(1) 124 | } 125 | 126 | defer resp.Body.Close() 127 | 128 | b, err := ioutil.ReadAll(resp.Body) //Get the body of the response 129 | if err != nil { //Error management 130 | os.Exit(1) 131 | } 132 | 133 | var f interface{} 134 | json.Unmarshal(b, &f) 135 | 136 | m := f.(map[string]interface{}) 137 | 138 | playlistsmap := m["data"] 139 | playlists := playlistsmap.(map[string]interface{}) 140 | 141 | itemsmap := playlists["items"] 142 | items := itemsmap.([]interface{}) 143 | 144 | var singleitem map[string]interface{} 145 | 146 | length := len(items) 147 | arrayplaylists := make([]Playlist, length) 148 | 149 | for i := 0; i < length; i++ { 150 | 151 | singleitem = items[i].(map[string]interface{}) 152 | 153 | arrayplaylists[i].NewPlaylist(singleitem["kind"].(string), singleitem["id"].(string), singleitem["creationTimestamp"].(string), singleitem["lastModifiedTimestamp"].(string), singleitem["deleted"].(bool), singleitem["name"].(string), singleitem["type"].(string)) 154 | 155 | } 156 | 157 | pa := []string{path, "playlists.json"} 158 | jsonpath := strings.Join(pa, "") 159 | 160 | _, err = gmusicjson.Export(arrayplaylists, jsonpath) 161 | if err != nil { 162 | fmt.Println("Error exporting Playlist: ") 163 | fmt.Println(err) 164 | } 165 | 166 | return arrayplaylists 167 | } 168 | func (p *Playlist) CreatePlaylist(auth string, xt string, name string, description string, public bool) bool { 169 | 170 | hostname := "https://play.google.com" 171 | resource := "/music/services/createplaylist" + "?u=0&xt=" + xt + "&format=jsarray" 172 | 173 | u, _ := url.ParseRequestURI(hostname) 174 | u.Path = resource 175 | urlStr := hostname + resource 176 | 177 | body_r := `[["",1],[null,"` + name + `", "` + description + `", []]]` 178 | 179 | req := request.Request{} 180 | headers := make(map[string]string) 181 | headers["Content-Type"] = "application/json" 182 | 183 | _, _, err := req.MakeCall("POST", auth, xt, urlStr, body_r, headers) 184 | if err != nil { 185 | os.Exit(1) 186 | return false 187 | } 188 | return true 189 | } 190 | 191 | func (p *Playlist) LoadUserPlaylist(auth string, xt string) bool { 192 | hostname := "https://play.google.com" 193 | resource := "/music/services/loaduserplaylist" + "?u=0&xt=" + xt + "&format=jsarray" 194 | 195 | u, _ := url.ParseRequestURI(hostname) 196 | u.Path = resource 197 | urlStr := hostname + resource 198 | 199 | cl := &http.Client{} 200 | 201 | body_r := `[["", 1, ""],[""]]` 202 | parameters := bytes.NewBufferString(body_r) 203 | 204 | r, err := http.NewRequest("POST", urlStr, parameters) 205 | if err != nil { 206 | os.Exit(1) 207 | return false 208 | } 209 | 210 | auth_header := "GoogleLogin auth=" + auth 211 | 212 | r.Header.Add("Authorization", auth_header) 213 | r.Header.Add("Content-Type", "application/json") 214 | 215 | expire := time.Now().AddDate(0, 0, 1) 216 | cookie := http.Cookie{"xt", xt, "/", "music.google.com", expire, expire.Format(time.UnixDate), 0, true, true, "xt=xttoken", []string{"xt=xttoken"}} 217 | r.AddCookie(&cookie) 218 | 219 | resp, err := cl.Do(r) 220 | if err != nil { 221 | panic(err) 222 | return false 223 | } 224 | 225 | defer resp.Body.Close() 226 | 227 | if resp.Status != "200 OK" { 228 | return false 229 | } 230 | 231 | b, err := ioutil.ReadAll(resp.Body) //Get the body of the response 232 | if err != nil { //Error management 233 | return false 234 | } 235 | result := make(map[string]interface{}) 236 | json.Unmarshal(b, &result) 237 | 238 | for i, el := range result { 239 | fmt.Println(i) 240 | fmt.Println(el.(string)) 241 | } 242 | 243 | return true 244 | } 245 | 246 | func (p *Playlist) DeletePlaylist(auth string, xt string, id string) bool { 247 | 248 | Url, err := url.Parse("https://play.google.com") 249 | Url.Path += "/music/services/deleteplaylist" 250 | 251 | parameters := url.Values{} 252 | 253 | parameters.Add("u", "0") 254 | parameters.Add("xt", xt) 255 | 256 | Url.RawQuery = parameters.Encode() 257 | 258 | cl := &http.Client{} 259 | 260 | body_r := []byte(`{"id": "` + id + `", "requestCause": 1, "requestType": 1, "sessionId": ""}`) 261 | 262 | req, err := http.NewRequest("POST", Url.String(), bytes.NewBuffer(body_r)) 263 | if err != nil { 264 | os.Exit(1) 265 | return false 266 | } 267 | 268 | auth_header := "GoogleLogin auth=" + auth 269 | 270 | req.Header.Add("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8") 271 | req.Header.Add("Authorization", auth_header) 272 | req.Header.Add("referer", "https://play.google.com/music/listen") 273 | 274 | expire := time.Now().AddDate(0, 0, 1) 275 | cookie := http.Cookie{"xt", xt, "/", "music.google.com", expire, expire.Format(time.UnixDate), 0, true, true, "xt=xttoken", []string{"xt=xttoken"}} 276 | req.AddCookie(&cookie) 277 | 278 | resp, err := cl.Do(req) 279 | if err != nil { 280 | panic(err) 281 | return false 282 | } 283 | fmt.Println(req) 284 | fmt.Println(resp) 285 | defer resp.Body.Close() 286 | 287 | if resp.Status != "200 OK" { 288 | return false 289 | } 290 | return true 291 | } 292 | 293 | func (p *Playlist) Print() { 294 | fmt.Print("kind: ") 295 | fmt.Println(p.Kind) 296 | fmt.Print("id: ") 297 | fmt.Println(p.Id) 298 | fmt.Print("creationTimestamp: ") 299 | fmt.Println(p.CreationTimestamp) 300 | fmt.Print("lastModifiedTimestamp: ") 301 | fmt.Println(p.LastModifiedTimestamp) 302 | fmt.Print("deleted: ") 303 | fmt.Println(p.Deleted) 304 | fmt.Print("name: ") 305 | fmt.Println(p.Name) 306 | fmt.Print("type: ") 307 | fmt.Println(p.TypePlaylist) 308 | } 309 | -------------------------------------------------------------------------------- /lib/plentry/plentry.go: -------------------------------------------------------------------------------- 1 | package plentry 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "io/ioutil" 8 | "strings" 9 | "encoding/json" 10 | "os" 11 | "strconv" 12 | "github.com/aleics/gmusicgo/lib/gmusicjson" 13 | ) 14 | 15 | type Plentry struct{ 16 | Kind string `json:"kind"` 17 | Id string `json:"id"` 18 | ClientId string `json:"clientId"` 19 | PlaylistId string `json:"playlistId"` 20 | AbsolutePosition string `json:"absolutePosition"` 21 | TrackId string `json:"trackId"` 22 | CreationTimestamp string `json:"creationTimestamp"` 23 | LastModifiedTimestamp string `json:"lastModifiedTimestamp"` 24 | Deleted bool `json:"deleted"` 25 | Source string `json:"source"` 26 | } 27 | func Init() *Plentry{ 28 | p := new(Plentry) 29 | return p 30 | } 31 | func ArrayInit() (p *[]Plentry){ 32 | return p 33 | } 34 | func (p Plentry) GetKind() string { 35 | return p.Kind 36 | } 37 | func (p *Plentry) SetKind(kind string) { 38 | p.Kind = kind 39 | } 40 | func (p Plentry) GetId() string { 41 | return p.Id 42 | } 43 | func (p *Plentry) SetId(id string) { 44 | p.Id = id 45 | } 46 | func (p Plentry) GetClientId() string { 47 | return p.ClientId 48 | } 49 | func (p *Plentry) SetClientId(clientId string) { 50 | p.ClientId = clientId 51 | } 52 | func (p Plentry) GetPlaylistId() string { 53 | return p.PlaylistId 54 | } 55 | func (p *Plentry) SetPlaylistId(playlistId string) { 56 | p.PlaylistId = playlistId 57 | } 58 | func (p Plentry) GetAbsolutePosition() string { 59 | return p.AbsolutePosition 60 | } 61 | func (p *Plentry) SetAbsolutePosition(absolutePosition string) { 62 | p.AbsolutePosition = absolutePosition 63 | } 64 | func (p Plentry) GetTrackId() string { 65 | return p.TrackId 66 | } 67 | func (p *Plentry) SetTrackId(trackId string) { 68 | p.TrackId = trackId 69 | } 70 | func (p Plentry) GetCreationTimestamp() string { 71 | return p.CreationTimestamp 72 | } 73 | func (p *Plentry) SetCreationTimestamp(creationTimestamp string) { 74 | p.CreationTimestamp = creationTimestamp 75 | } 76 | func (p Plentry) GetLastModifiedTimestamp() string { 77 | return p.LastModifiedTimestamp 78 | } 79 | func (p *Plentry) SetLastModifiedTimestamp(lastModifiedTimestamp string) { 80 | p.LastModifiedTimestamp = lastModifiedTimestamp 81 | } 82 | func (p Plentry) GetDeleted() bool { 83 | return p.Deleted 84 | } 85 | func (p *Plentry) SetDeleted(deleted bool) { 86 | p.Deleted = deleted 87 | } 88 | func (p Plentry) GetSource() string { 89 | return p.Source 90 | } 91 | func (p *Plentry) SetSource(source string) { 92 | p.Source = source 93 | } 94 | func (p *Plentry) NewPlentry(kind string, id string, clientId string, playlistId string, absolutePosition string, trackId string, creationTimestamp string, lastModifiedTimestamp string, deleted bool, source string){ 95 | 96 | p.Kind = kind 97 | p.Id = id 98 | p.ClientId = clientId 99 | p.PlaylistId = playlistId 100 | p.AbsolutePosition = absolutePosition 101 | p.TrackId = trackId 102 | p.CreationTimestamp = creationTimestamp 103 | p.LastModifiedTimestamp = lastModifiedTimestamp 104 | p.Deleted = deleted 105 | p.Source = source 106 | } 107 | func (p Plentry) ToMap() map[string]string { 108 | 109 | ret := make(map[string]string) 110 | 111 | ret["kind"] = p.Kind 112 | ret["id"] = p.Id 113 | ret["clientId"] = p.ClientId 114 | ret["playlistId"] = p.PlaylistId 115 | ret["absolutePosition"] = p.AbsolutePosition 116 | ret["trackId"] = p.TrackId 117 | ret["creationTimestamp"] = p.CreationTimestamp 118 | ret["lastModifiedTimestamp"] = p.LastModifiedTimestamp 119 | ret["deleted"] = strconv.FormatBool(p.Deleted) 120 | ret["source"] = p.Source 121 | 122 | return ret 123 | } 124 | func PlentryRequest(auth string, path string) []Plentry{ 125 | 126 | hostname := "https://www.googleapis.com" 127 | resource := "/sj/v1beta1/plentries" 128 | 129 | u, _ := url.ParseRequestURI(hostname) 130 | u.Path = resource 131 | urlStr := fmt.Sprintf("%v",u) 132 | 133 | cl := &http.Client{} 134 | 135 | r, err := http.NewRequest("GET", urlStr, nil) 136 | if err != nil { 137 | os.Exit(1) 138 | } 139 | 140 | auth_header := "GoogleLogin auth=" + auth 141 | 142 | r.Header.Add("Authorization", auth_header) 143 | 144 | 145 | resp, err := cl.Do(r) 146 | if err != nil { 147 | os.Exit(1) 148 | } 149 | 150 | defer resp.Body.Close() 151 | 152 | b, err := ioutil.ReadAll(resp.Body) //Get the body of the response 153 | 154 | if err != nil { //Error management 155 | os.Exit(1) 156 | } 157 | 158 | pa := []string{path,"plentries.json"} 159 | jsonpath := strings.Join(pa,"") 160 | 161 | var f interface{} 162 | json.Unmarshal(b, &f) 163 | 164 | m := f.(map[string]interface{}) 165 | 166 | plentriesmap := m["data"] 167 | plentries := plentriesmap.(map[string]interface{}) 168 | 169 | 170 | itemsmap := plentries["items"] 171 | items := itemsmap.([]interface{}) 172 | 173 | var singleitem map[string]interface{} 174 | 175 | length := len(items) 176 | arrayplentries := make([]Plentry,length) 177 | 178 | for i := 0; i < length; i++ { 179 | 180 | singleitem = items[i].(map[string]interface{}) 181 | 182 | 183 | arrayplentries[i].NewPlentry(singleitem["kind"].(string), singleitem["id"].(string), singleitem["clientId"].(string), singleitem["playlistId"].(string), singleitem["absolutePosition"].(string), singleitem["trackId"].(string), singleitem["creationTimestamp"].(string), singleitem["lastModifiedTimestamp"].(string), singleitem["deleted"].(bool), singleitem["source"].(string)) 184 | 185 | } 186 | 187 | _, err = gmusicjson.Export(arrayplentries, jsonpath) 188 | if err != nil { 189 | fmt.Println("Error exporting Plentries: ") 190 | fmt.Println(err) 191 | } 192 | 193 | return arrayplentries 194 | } 195 | func (p *Plentry) Print(){ 196 | fmt.Print("kind: ") 197 | fmt.Println(p.Kind) 198 | fmt.Print("id: ") 199 | fmt.Println(p.Id) 200 | fmt.Print("clientId: ") 201 | fmt.Println(p.ClientId) 202 | fmt.Print("playlistId: ") 203 | fmt.Println(p.PlaylistId) 204 | fmt.Print("absolutePosition: ") 205 | fmt.Println(p.AbsolutePosition) 206 | fmt.Print("trackId: ") 207 | fmt.Println(p.TrackId) 208 | fmt.Print("creationTimestamp: ") 209 | fmt.Println(p.CreationTimestamp) 210 | fmt.Print("lastModifiedTimestamp: ") 211 | fmt.Println(p.LastModifiedTimestamp) 212 | fmt.Print("deleted: ") 213 | fmt.Println(p.Deleted) 214 | fmt.Print("source: ") 215 | fmt.Println(p.Source) 216 | } 217 | -------------------------------------------------------------------------------- /lib/request/request.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | //"fmt" 5 | "net/http" 6 | //"net/url" 7 | //"encoding/json" 8 | "os" 9 | "time" 10 | //"bytes" 11 | "errors" 12 | "bytes" 13 | ) 14 | 15 | type Request struct{ 16 | url string 17 | response http.Response 18 | status string 19 | } 20 | func (r *Request) MakeCall(_type string, auth string, xt string, urlStr string, body string, suppHeaders map[string]string) (*http.Response, string, error) { 21 | 22 | r.url = urlStr 23 | 24 | parameters := bytes.NewBufferString(body) 25 | auth_header := "GoogleLogin auth=" + auth 26 | 27 | expire := time.Now().AddDate(0, 0, 1) 28 | cookie := http.Cookie{"xt", xt, "/", "music.google.com", expire, expire.Format(time.UnixDate), 0, true, true, "xt=xttoken", []string{"xt=xttoken"}} 29 | 30 | cl := &http.Client{} 31 | 32 | switch(_type){ 33 | case "GET":{ 34 | req, err := http.NewRequest("GET", urlStr, parameters) 35 | if err != nil { 36 | os.Exit(1) 37 | return &http.Response{}, "", errors.New("GET request error: error creating request") 38 | } 39 | req.Header.Add("Authorization", auth_header) 40 | 41 | for key, value := range(suppHeaders){ 42 | req.Header.Add(key, value) 43 | } 44 | 45 | req.AddCookie(&cookie) 46 | 47 | resp, err := cl.Do(req) 48 | if err != nil { 49 | os.Exit(1) 50 | return &http.Response{}, "", errors.New("GET request error: error making request") 51 | } 52 | defer resp.Body.Close() 53 | 54 | r.response = *resp 55 | r.status = resp.Status 56 | 57 | return resp, resp.Status, nil 58 | break 59 | } 60 | case "POST":{ 61 | req, err := http.NewRequest("POST", urlStr, parameters) 62 | if err != nil { 63 | os.Exit(1) 64 | return &http.Response{}, "", errors.New("POST request error: error creating request") 65 | } 66 | req.Header.Add("Authorization", auth_header) 67 | 68 | for key, value := range(suppHeaders){ 69 | req.Header.Add(key, value) 70 | } 71 | 72 | 73 | req.AddCookie(&cookie) 74 | 75 | resp, err := cl.Do(req) 76 | if err != nil { 77 | os.Exit(1) 78 | return &http.Response{}, "", errors.New("POST request error: error making request") 79 | } 80 | defer resp.Body.Close() 81 | 82 | r.response = *resp 83 | r.status = resp.Status 84 | 85 | return resp, resp.Status, nil 86 | break 87 | } 88 | case "HEAD":{ 89 | req, err := http.NewRequest("HEAD", urlStr, parameters) 90 | if err != nil { 91 | os.Exit(1) 92 | return &http.Response{}, "", errors.New("HEAD request error: error creating request") 93 | } 94 | req.Header.Add("Authorization", auth_header) 95 | for key, value := range(suppHeaders){ 96 | req.Header.Add(key, value) 97 | } 98 | 99 | req.AddCookie(&cookie) 100 | 101 | resp, err := cl.Do(req) 102 | if err != nil { 103 | os.Exit(1) 104 | return &http.Response{}, "", errors.New("HEAD request error: error making request") 105 | } 106 | defer resp.Body.Close() 107 | 108 | r.response = *resp 109 | r.status = resp.Status 110 | 111 | return resp, resp.Status, nil 112 | break 113 | } 114 | case "PUT":{ 115 | req, err := http.NewRequest("PUT", urlStr, parameters) 116 | if err != nil { 117 | os.Exit(1) 118 | return &http.Response{}, "", errors.New("PUT request error: error creating request") 119 | } 120 | req.Header.Add("Authorization", auth_header) 121 | for key, value := range(suppHeaders){ 122 | req.Header.Add(key, value) 123 | } 124 | 125 | req.AddCookie(&cookie) 126 | 127 | resp, err := cl.Do(req) 128 | if err != nil { 129 | os.Exit(1) 130 | return &http.Response{}, "", errors.New("PUT request error: error making request") 131 | } 132 | defer resp.Body.Close() 133 | 134 | r.response = *resp 135 | r.status = resp.Status 136 | 137 | return resp, resp.Status, nil 138 | break 139 | } 140 | } 141 | return &http.Response{}, "", errors.New("Error: no request selected") 142 | } 143 | -------------------------------------------------------------------------------- /lib/stream/stream.go: -------------------------------------------------------------------------------- 1 | package stream 2 | 3 | import( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "io/ioutil" 8 | "errors" 9 | "os" 10 | "time" 11 | "encoding/json" 12 | ) 13 | 14 | type Stream struct{ 15 | streamUrl string 16 | audioFile string 17 | } 18 | func Init() *Stream{ 19 | s := new(Stream) 20 | return s 21 | } 22 | func (s Stream) StreamUrl() string{ 23 | return s.streamUrl 24 | } 25 | func (s Stream) AudioFile() string{ 26 | return s.audioFile 27 | } 28 | func (s *Stream) SetStreamUrl(streamUrl string) { 29 | s.streamUrl = streamUrl 30 | } 31 | func (s *Stream) SetAudioFile(audioFile string) { 32 | s.audioFile = audioFile 33 | } 34 | func (s *Stream) StreamRequest(auth string, xt string, songid string, path string) error{ 35 | b := s.StreamAudioRequest(s.StreamUrlRequest(auth, xt, songid, path + "streamurl_" + songid + ".json"), path + "file_" + songid + ".mp3") 36 | if b != true { 37 | return errors.New("Error stream request") 38 | } 39 | return nil 40 | } 41 | func (s *Stream) StreamAudioRequest(streamUrl string, path string) bool{ 42 | 43 | out := true 44 | urlStr := streamUrl 45 | 46 | cl := &http.Client{} 47 | 48 | r, err := http.NewRequest("GET", urlStr, nil) 49 | if err != nil { 50 | panic(err) 51 | } 52 | r.Header.Add("Referer", "https://play.google.com/music/listen") 53 | resp, err := cl.Do(r) 54 | if err != nil { 55 | panic(err) 56 | out = false 57 | } 58 | 59 | defer resp.Body.Close() 60 | b, err := ioutil.ReadAll(resp.Body) //Get the body of the response 61 | 62 | if path != "" { 63 | f, err := os.Create(path) 64 | if err != nil { 65 | panic(err) 66 | out = false 67 | } 68 | 69 | defer func() { 70 | if err := f.Close(); err != nil { 71 | panic(err) 72 | out = false 73 | } 74 | }() 75 | 76 | _, err = f.Write([]byte(b)) 77 | if err != nil { 78 | panic(err) 79 | out = false 80 | } 81 | } 82 | 83 | return out 84 | 85 | } 86 | func (s *Stream) StreamUrlRequest(auth string, xt string, songid string, path string) string{ 87 | 88 | hostname := "https://play.google.com" 89 | resource := "/music/play?u=0&songid=" + songid + "&pt=e" 90 | 91 | u, _ := url.ParseRequestURI(hostname) 92 | u.Path = resource 93 | urlStr := fmt.Sprintf("%v",u) 94 | 95 | urlStr = hostname + resource 96 | 97 | cl := &http.Client{} 98 | 99 | r, err := http.NewRequest("GET", urlStr, nil) 100 | if err != nil { 101 | panic(err) 102 | } 103 | 104 | auth_header := "GoogleLogin auth=" + auth 105 | 106 | r.Header.Add("Authorization", auth_header) 107 | r.Header.Add("Content-Type", "application/json") 108 | 109 | 110 | expire := time.Now().AddDate(0, 0, 1) 111 | cookie := http.Cookie{"sjsaid", "", "/", "music.google.com", expire, expire.Format(time.UnixDate), 0, true, true, "sjsaid=sjsaidtoken", []string{"sjsaid=sjsaidtoken"}} 112 | r.AddCookie(&cookie) 113 | cookie = http.Cookie{"xt", xt, "/", "music.google.com", expire, expire.Format(time.UnixDate), 0, true, true, "xt=xttoken", []string{"xt=xttoken"}} 114 | r.AddCookie(&cookie) 115 | 116 | resp, err := cl.Do(r) 117 | if err != nil { 118 | panic(err) 119 | } 120 | 121 | defer resp.Body.Close() 122 | 123 | b, err := ioutil.ReadAll(resp.Body) //Get the body of the response 124 | 125 | result := make(map[string]interface{}) 126 | json.Unmarshal(b, &result) //Decode the json body response 127 | 128 | if err != nil { //Error management 129 | panic(err) 130 | } 131 | 132 | s.SetStreamUrl(result["url"].(string)) 133 | 134 | if path != "" { 135 | f, err := os.Create(path) 136 | if err != nil { 137 | panic(err) 138 | } 139 | 140 | defer func() { 141 | if err := f.Close(); err != nil { 142 | panic(err) 143 | } 144 | }() 145 | 146 | _, err = f.Write([]byte(b)) 147 | if err != nil { 148 | panic(err) 149 | } 150 | } 151 | 152 | return s.streamUrl 153 | } 154 | -------------------------------------------------------------------------------- /lib/tokens/tokens.go: -------------------------------------------------------------------------------- 1 | package tokens 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "strings" 8 | "github.com/aleics/gmusicgo/lib/gmusicjson" 9 | ) 10 | //Declaration of the Tokens struct 11 | type Tokens struct { 12 | Xt string `json:"xt"` 13 | } 14 | func Init() *Tokens{ 15 | t := new(Tokens) 16 | return t 17 | } 18 | func (t Tokens) GetXt() string{ 19 | return t.Xt 20 | } 21 | func (t *Tokens) SetXt(s string){ 22 | t.Xt = s 23 | } 24 | func (t *Tokens) MakeRequest(auth string) [2]string{ 25 | 26 | hostname := "https://play.google.com" 27 | 28 | resource := "/music/listen" 29 | 30 | u, _ := url.ParseRequestURI(hostname) 31 | u.Path = resource 32 | urlStr := fmt.Sprintf("%v",u) 33 | 34 | cl := &http.Client{} 35 | 36 | r, err := http.NewRequest("GET", urlStr, nil) //GET Request 37 | if err != nil { 38 | return [2]string{"404 ERROR",""} 39 | } 40 | 41 | auth_header := "GoogleLogin auth=" + auth //Add the auth value on the Authorization header 42 | 43 | r.Header.Add("Authorization", auth_header) 44 | 45 | 46 | resp, err := cl.Do(r) 47 | if err != nil { 48 | return [2]string{"404 ERROR",""} 49 | } 50 | 51 | defer resp.Body.Close() 52 | 53 | responsehead := resp.Header 54 | 55 | xt := responsehead["Set-Cookie"][0][3:79] //Get the sjsaid token from the Response header 56 | 57 | 58 | t.Xt = xt 59 | 60 | response := [2]string{resp.Status, xt} //return the tokens and the status of the communication 61 | 62 | return response 63 | } 64 | func (t Tokens) SaveInfo(path string) bool{ 65 | 66 | p := []string{path,"tokens.json"} 67 | jsonpath := strings.Join(p,"") 68 | 69 | _, err := gmusicjson.Export(t, jsonpath) 70 | if err != nil { 71 | fmt.Println(err) 72 | return false 73 | } 74 | 75 | return true 76 | } 77 | -------------------------------------------------------------------------------- /lib/track/track.go: -------------------------------------------------------------------------------- 1 | package track 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "io/ioutil" 8 | "strings" 9 | "encoding/json" 10 | "os" 11 | "strconv" 12 | "github.com/aleics/gmusicgo/lib/gmusicjson" 13 | ) 14 | 15 | type Track struct{ 16 | Kind string `json:"kind"` 17 | Id string `json:"id"` 18 | ClientId string `json:"clientId"` 19 | CreationTimestamp string `json:"creationTimestamp"` 20 | LastModifiedTimestamp string `json:"lastModifiedTimestamp"` 21 | Deleted bool `json:"deleted"` 22 | Title string `json:"title"` 23 | Artist string `json:"artist"` 24 | Composer string `json:"composer"` 25 | Album string `json:"album"` 26 | AlbumArtist string `json:"albumArtist"` 27 | Year float64 `json:"year"` 28 | Comment string `json:"comment"` 29 | TrackNumber float64 `json:"trackNumber"` 30 | Genre string `json:"genre"` 31 | DurationMillis string `json:"durationMillis"` 32 | BeatsPerMinute float64 `json:"beatsPerMinute"` 33 | AlbumArtRefurl string `json:"albumArtRefurl"` 34 | PlayCount float64 `json:"playCount"` 35 | TotalTrackCount float64 `json:"totalTrackCount"` 36 | DiscNumber float64 `json:"discNumber"` 37 | TotalDiscCount float64 `json:"totalDiscount"` 38 | Rating string `json:"rating"` 39 | EstimatedSize string `json:"estimatedSize"` 40 | } 41 | func Init() *Track{ 42 | t := new(Track) 43 | return t 44 | } 45 | func ArrayInit() (t *[]Track){ 46 | return t 47 | } 48 | func (t Track) GetKind() string { 49 | return t.Kind 50 | } 51 | func (t *Track) SetKind(kind string) { 52 | t.Kind = kind 53 | } 54 | func (t Track) GetId() string { 55 | return t.Id 56 | } 57 | func (t *Track) SetId(id string) { 58 | t.Id = id 59 | } 60 | func (t Track) GetClientId() string { 61 | return t.ClientId 62 | } 63 | func (t *Track) SetClientId(clientId string) { 64 | t.ClientId = clientId 65 | } 66 | func (t Track) GetCreationTimestamp() string { 67 | return t.CreationTimestamp 68 | } 69 | func (t *Track) SetCreationTimestamp(creationTimestamp string) { 70 | t.CreationTimestamp = creationTimestamp 71 | } 72 | func (t Track) GetLastModifiedTimestamp() string { 73 | return t.LastModifiedTimestamp 74 | } 75 | func (t *Track) SetLastModifiedTimestamp(lastModifiedTimestamp string) { 76 | t.LastModifiedTimestamp = lastModifiedTimestamp 77 | } 78 | func (t Track) GetDeleted() bool { 79 | return t.Deleted 80 | } 81 | func (t *Track) SetDeleted(deleted bool) { 82 | t.Deleted = deleted 83 | } 84 | func (t Track) GetTitle() string { 85 | return t.Title 86 | } 87 | func (t *Track) SetTitle(title string) { 88 | t.Title = title 89 | } 90 | func (t Track) GetArtist() string { 91 | return t.Artist 92 | } 93 | func (t *Track) SetArtist(artist string) { 94 | t.Artist = artist 95 | } 96 | func (t Track) GetComposer() string { 97 | return t.Composer 98 | } 99 | func (t *Track) SetComposer(composer string) { 100 | t.Composer = composer 101 | } 102 | func (t Track) GetAlbum() string { 103 | return t.Album 104 | } 105 | func (t *Track) SetAlbum(album string) { 106 | t.Album = album 107 | } 108 | func (t Track) GetAlbumArtist() string { 109 | return t.AlbumArtist 110 | } 111 | func (t *Track) SetAlbumArtist(albumArtist string) { 112 | t.AlbumArtist = albumArtist 113 | } 114 | func (t Track) GetYear() float64 { 115 | return t.Year 116 | } 117 | func (t *Track) SetYear(year float64) { 118 | t.Year = year 119 | } 120 | func (t Track) GetComment() string { 121 | return t.Comment 122 | } 123 | func (t *Track) SetComment(comment string) { 124 | t.Comment = comment 125 | } 126 | func (t Track) GetTrackNumber() float64 { 127 | return t.TrackNumber 128 | } 129 | func (t *Track) SetTrackNumber(trackNumber float64) { 130 | t.TrackNumber = trackNumber 131 | } 132 | func (t Track) GetGenre() string { 133 | return t.Genre 134 | } 135 | func (t *Track) SetGenre(genre string) { 136 | t.Genre = genre 137 | } 138 | func (t Track) GetDurationMillis() string { 139 | return t.DurationMillis 140 | } 141 | func (t *Track) SetDurationMillis(durationMillis string) { 142 | t.DurationMillis = durationMillis 143 | } 144 | func (t Track) GetBeatsPerMinute() float64 { 145 | return t.BeatsPerMinute 146 | } 147 | func (t *Track) SetBeatsPerMinute(beatsPerMinute float64) { 148 | t.BeatsPerMinute = beatsPerMinute 149 | } 150 | func (t Track) GetAlbumArtRefurl() string { 151 | return t.AlbumArtRefurl 152 | } 153 | func (t *Track) SetAlbumArtRefurl(albumArtRefurl string) { 154 | t.AlbumArtRefurl = albumArtRefurl 155 | } 156 | func (t Track) GetPlayCount() float64 { 157 | return t.PlayCount 158 | } 159 | func (t *Track) SetPlayCount(playCount float64) { 160 | t.PlayCount = playCount 161 | } 162 | func (t Track) GetTotalTrackCount() float64 { 163 | return t.TotalTrackCount 164 | } 165 | func (t *Track) SetTotalTrackCount(totalTrackCount float64) { 166 | t.TotalTrackCount = totalTrackCount 167 | } 168 | func (t Track) GetDiscNumber() float64 { 169 | return t.DiscNumber 170 | } 171 | func (t *Track) SetDiscNumber(discNumber float64) { 172 | t.DiscNumber = discNumber 173 | } 174 | func (t Track) GetTotalDiscCount() float64 { 175 | return t.TotalDiscCount 176 | } 177 | func (t *Track) SetTotalDiscCount(totalDiscCount float64) { 178 | t.TotalDiscCount = totalDiscCount 179 | } 180 | func (t Track) GetRating() string { 181 | return t.Rating 182 | } 183 | func (t *Track) SetRating(rating string) { 184 | t.Rating = rating 185 | } 186 | func (t Track) GetEstimatedSize() string { 187 | return t.EstimatedSize 188 | } 189 | func (t *Track) SetEstimatedSize(estimatedSize string) { 190 | t.EstimatedSize = estimatedSize 191 | } 192 | func (t *Track) NewTrack(kind string, id string, clientId string, creationTimestamp string, lastModifiedTimestamp string, deleted bool, title string, artist string, composer string, album string, albumArtist string, year float64, comment string, trackNumber float64, genre string, durationMillis string, beatsPerMinute float64, albumArtRefurl string, playCount float64, totalTrackCount float64, discNumber float64, totalDiscCount float64,rating string, estimatedSize string){ 193 | t.Kind = kind 194 | t.Id = id 195 | t.ClientId = clientId 196 | t.CreationTimestamp = creationTimestamp 197 | t.LastModifiedTimestamp = lastModifiedTimestamp 198 | t.Deleted = deleted 199 | t.Title = title 200 | t.Artist = artist 201 | t.Composer = composer 202 | t.Album = album 203 | t.AlbumArtist = albumArtist 204 | t.Year = year 205 | t.Comment = comment 206 | t.TrackNumber = trackNumber 207 | t.Genre = genre 208 | t.DurationMillis = durationMillis 209 | t.BeatsPerMinute = beatsPerMinute 210 | t.AlbumArtRefurl = albumArtRefurl 211 | t.PlayCount = playCount 212 | t.TotalTrackCount = totalTrackCount 213 | t.DiscNumber = discNumber 214 | t.TotalDiscCount = totalDiscCount 215 | t.Rating = rating 216 | t.EstimatedSize = estimatedSize 217 | } 218 | func (t Track) ToMap() map[string]string { 219 | 220 | ret := make(map[string]string) 221 | 222 | ret["kind"] = t.Kind 223 | ret["id"] = t.Id 224 | ret["creationTimestamp"] = t.CreationTimestamp 225 | ret["lastModifiedTimestamp"] = t.LastModifiedTimestamp 226 | ret["deleted"] = strconv.FormatBool(t.Deleted) 227 | ret["title"] = t.Title 228 | ret["artist"] = t.Artist 229 | ret["composer"] = t.Composer 230 | ret["album"] = t.Album 231 | ret["albumArtist"] = t.AlbumArtist 232 | ret["year"] = strconv.FormatFloat(t.Year, 'f', 0, 64) 233 | ret["comment"] = t.Comment 234 | ret["trackNumber"] = strconv.FormatFloat(t.TrackNumber, 'f', 0, 64) 235 | ret["genre"] = t.Genre 236 | ret["durationMillis"] = t.DurationMillis 237 | ret["beatsPerMinute"] = strconv.FormatFloat(t.BeatsPerMinute, 'f', 0, 64) 238 | ret["albumArtRefurl"] = t.AlbumArtRefurl 239 | ret["playCount"] = strconv.FormatFloat(t.PlayCount, 'f', 0, 64) 240 | ret["totalTrackCount"] = strconv.FormatFloat(t.TotalTrackCount, 'f', 0, 64) 241 | ret["discNumber"] = strconv.FormatFloat(t.DiscNumber, 'f', 0, 64) 242 | ret["totalDiscCount"] = strconv.FormatFloat(t.TotalDiscCount, 'f', 0, 64) 243 | ret["rating"] = t.Rating 244 | ret["estimatedSize"] = t.EstimatedSize 245 | 246 | return ret 247 | } 248 | 249 | func TracksRequest(auth string, path string) []Track{ 250 | 251 | hostname := "https://www.googleapis.com" 252 | resource := "/sj/v1beta1/tracks" 253 | 254 | u, _ := url.ParseRequestURI(hostname) 255 | u.Path = resource 256 | urlStr := fmt.Sprintf("%v",u) 257 | 258 | cl := &http.Client{} 259 | 260 | r, err := http.NewRequest("GET", urlStr, nil) 261 | if err != nil { 262 | os.Exit(1) 263 | } 264 | 265 | auth_header := "GoogleLogin auth=" + auth 266 | 267 | r.Header.Add("Authorization", auth_header) 268 | 269 | 270 | resp, err := cl.Do(r) 271 | if err != nil { 272 | os.Exit(1) 273 | } 274 | 275 | defer resp.Body.Close() 276 | 277 | b, err := ioutil.ReadAll(resp.Body) //Get the body of the response 278 | if err != nil { //Error management 279 | os.Exit(1) 280 | } 281 | 282 | var f interface{} 283 | json.Unmarshal(b, &f) 284 | 285 | m := f.(map[string]interface{}) 286 | 287 | tracksmap := m["data"] 288 | tracks := tracksmap.(map[string]interface{}) 289 | 290 | 291 | 292 | itemsmap := tracks["items"] 293 | items := itemsmap.([]interface{}) 294 | 295 | var singleitem map[string]interface{} 296 | 297 | var singlealbumrefs map[string]interface{} 298 | var albumref string 299 | 300 | length := len(items) 301 | arraytracks := make([]Track,length) 302 | 303 | for i := 0; i < length; i++ { 304 | 305 | singleitem = items[i].(map[string]interface{}) 306 | if singleitem["albumArtRef"] == nil { 307 | albumref = "" 308 | } else { 309 | albumrefs := singleitem["albumArtRef"].([]interface{}) 310 | singlealbumrefs = albumrefs[0].(map[string]interface{}) 311 | albumref = singlealbumrefs["url"].(string) 312 | } 313 | 314 | arraytracks[i].NewTrack(singleitem["kind"].(string), singleitem["id"].(string), singleitem["clientId"].(string), singleitem["creationTimestamp"].(string), singleitem["lastModifiedTimestamp"].(string), singleitem["deleted"].(bool), singleitem["title"].(string), singleitem["artist"].(string), singleitem["composer"].(string), singleitem["album"].(string), singleitem["albumArtist"].(string), singleitem["year"].(float64), singleitem["comment"].(string), singleitem["trackNumber"].(float64), singleitem["genre"].(string), singleitem["durationMillis"].(string), singleitem["beatsPerMinute"].(float64), albumref, singleitem["playCount"].(float64), singleitem["totalTrackCount"].(float64), singleitem["discNumber"].(float64), singleitem["totalDiscCount"].(float64), singleitem["rating"].(string), singleitem["estimatedSize"].(string)) 315 | 316 | } 317 | 318 | p := []string{path,"tracks.json"} 319 | jsonpath := strings.Join(p,"") 320 | 321 | 322 | _, err = gmusicjson.Export(arraytracks, jsonpath) 323 | if err != nil { 324 | fmt.Println("Error exporting Tracks") 325 | fmt.Println(err) 326 | } 327 | 328 | return arraytracks 329 | } 330 | 331 | func (t *Track) Print(){ 332 | fmt.Print("kind: ") 333 | fmt.Println(t.Kind) 334 | fmt.Print("id: ") 335 | fmt.Println(t.Id) 336 | fmt.Print("clientId: ") 337 | fmt.Println(t.ClientId) 338 | fmt.Print("creationTimestamp: ") 339 | fmt.Println(t.CreationTimestamp) 340 | fmt.Print("lastModifiedTimestamp: ") 341 | fmt.Println(t.LastModifiedTimestamp) 342 | fmt.Print("deleted: ") 343 | fmt.Println(t.Deleted) 344 | fmt.Print("title: ") 345 | fmt.Println(t.Title) 346 | fmt.Print("artist: ") 347 | fmt.Println(t.Artist) 348 | fmt.Print("composer: ") 349 | fmt.Println(t.Composer) 350 | fmt.Print("album: ") 351 | fmt.Println(t.Album) 352 | fmt.Print("albumArtist: ") 353 | fmt.Println(t.AlbumArtist) 354 | fmt.Print("year: ") 355 | fmt.Println(t.Year) 356 | fmt.Print("comment: ") 357 | fmt.Println(t.Comment) 358 | fmt.Print("trackNumber: ") 359 | fmt.Println(t.TrackNumber) 360 | fmt.Print("genre: ") 361 | fmt.Println(t.Genre) 362 | fmt.Print("durationMillis: ") 363 | fmt.Println(t.DurationMillis) 364 | fmt.Print("beatsPerMinute: ") 365 | fmt.Println(t.BeatsPerMinute) 366 | fmt.Print("playCount: ") 367 | fmt.Println(t.PlayCount) 368 | fmt.Print("albumArtRefurl: ") 369 | fmt.Println(t.AlbumArtRefurl) 370 | fmt.Print("totalTrackCount: ") 371 | fmt.Println(t.TotalTrackCount) 372 | fmt.Print("discNumber: ") 373 | fmt.Println(t.DiscNumber) 374 | fmt.Print("totalDiscCount: ") 375 | fmt.Println(t.TotalDiscCount) 376 | fmt.Print("rating: ") 377 | fmt.Println(t.Rating) 378 | fmt.Print("estimatedSize: ") 379 | fmt.Println(t.EstimatedSize) 380 | 381 | } 382 | -------------------------------------------------------------------------------- /process.txt: -------------------------------------------------------------------------------- 1 | Queue 2 | ===== 3 | 4 | - Make deletePlaylist working -> Error "404" for no reason. 5 | - MakeCall working for all requests 6 | -------------------------------------------------------------------------------- /test/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/aleics/gmusicgo" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | gmusic := gmusicgo.Init() 11 | path := "/home/aleix/gmusic/" 12 | 13 | var header [5]string 14 | _, err := fmt.Scan(&header[0]) 15 | if err != nil { 16 | os.Exit(1) 17 | } 18 | _, err = fmt.Scan(&header[1]) 19 | if err != nil { 20 | os.Exit(1) 21 | } 22 | _, err = fmt.Scan(&header[2]) 23 | if err != nil { 24 | os.Exit(1) 25 | } 26 | _, err = fmt.Scan(&header[3]) 27 | if err != nil { 28 | os.Exit(1) 29 | } 30 | _, err = fmt.Scan(&header[4]) 31 | if err != nil { 32 | os.Exit(1) 33 | } 34 | 35 | err = gmusic.Connect(header[0], header[1], header[2], header[3], header[4], path) 36 | if err != nil { 37 | fmt.Println("Couldn't connect with Gmusic") 38 | } 39 | 40 | err = gmusic.GetSong("b7e5d43b-0293-3020-8277-a686bd394eec", path+"songs/") 41 | if err != nil { 42 | fmt.Println("Couldn't get the song") 43 | } 44 | err = gmusic.Import(path) 45 | if err != nil { 46 | fmt.Println(err) 47 | fmt.Println("Couldn't import all the data. Check exporting path") 48 | } 49 | 50 | err = gmusic.CreatePlaylist("Test", "test google api", true) 51 | 52 | if err != nil { 53 | fmt.Println(err) 54 | fmt.Println("Couldn't create the playlist.") 55 | } 56 | 57 | _ = gmusic.LoadUserPlaylist() 58 | 59 | //_ = gmusic.DeletePlaylist("") 60 | } 61 | 62 | /*package main 63 | 64 | import( 65 | "fmt" 66 | "os" 67 | "github.com/aleics/clientlogin" 68 | "github.com/aleics/tokens" 69 | "github.com/aleics/track" 70 | "github.com/aleics/playlist" 71 | "github.com/aleics/plentry" 72 | "github.com/aleics/stream" 73 | ) 74 | 75 | func main(){ 76 | 77 | path := "/home/aleix/gmusic/" 78 | client := clientlogin.Init() 79 | 80 | var header [5]string 81 | _, err := fmt.Scan(&header[0]) 82 | if err != nil { 83 | os.Exit(1) 84 | } 85 | _, err = fmt.Scan(&header[1]) 86 | if err != nil { 87 | os.Exit(1) 88 | } 89 | _, err = fmt.Scan(&header[2]) 90 | if err != nil { 91 | os.Exit(1) 92 | } 93 | _, err = fmt.Scan(&header[3]) 94 | if err != nil { 95 | os.Exit(1) 96 | } 97 | _, err = fmt.Scan(&header[4]) 98 | if err != nil { 99 | os.Exit(1) 100 | } 101 | 102 | 103 | client.SetHeader(header[0],header[1],header[2],header[3],header[4]) 104 | 105 | value := client.MakeRequest(client.Header()) 106 | 107 | 108 | if value[0] == "200 OK"{ 109 | fmt.Println("AUTHORIZATION") 110 | fmt.Println("Good Request") 111 | fmt.Println("Auth saved on: " + path) 112 | fmt.Println(client.Auth()) 113 | save := client.SaveInfo(path) 114 | if save != true { 115 | fmt.Println("User info couldn't be saved") 116 | } else { 117 | fmt.Println("User info saved!") 118 | } 119 | } 120 | 121 | fmt.Println("") 122 | fmt.Println("----------------------------------------------------------------------------------------------------") 123 | fmt.Println("") 124 | 125 | tokenvalues := tokens.Init() 126 | 127 | value2 := tokenvalues.MakeRequest(client.Auth()) 128 | 129 | if value2[0] == "200 OK"{ 130 | fmt.Println("TOKENS") 131 | fmt.Println("Good Request") 132 | fmt.Println("Tokens saved on: " + path) 133 | fmt.Println(tokenvalues.Xt()) 134 | fmt.Println(tokenvalues.Sjsaid()) 135 | save2 := tokenvalues.SaveInfo(path) 136 | if save2 != true { 137 | fmt.Println("Tokens value couldn't be saved") 138 | } else { 139 | fmt.Println("Tokens saved!") 140 | } 141 | } 142 | 143 | fmt.Println("") 144 | fmt.Println("----------------------------------------------------------------------------------------------------") 145 | fmt.Println("") 146 | 147 | track := track.Init() 148 | 149 | tracks := track.TracksRequest(client.Auth(), path) 150 | if tracks[0].Id() != "" { 151 | fmt.Println("TRACKS") 152 | fmt.Println("Good Request") 153 | fmt.Println("Tracks saved on: " + path) 154 | length := len(tracks) 155 | if length != 0 { 156 | fmt.Println("Good Response") 157 | } else { fmt.Println("Error saving Tracks")} 158 | } 159 | 160 | fmt.Println("") 161 | fmt.Println("----------------------------------------------------------------------------------------------------") 162 | fmt.Println("") 163 | 164 | 165 | playlist := playlist.Init() 166 | 167 | playlists := playlist.PlaylistsRequest(client.Auth(), path) 168 | if playlists[0].Id() != "" { 169 | fmt.Println("PLAYLISTS") 170 | fmt.Println("Good Request") 171 | fmt.Println("Playlists saved on: " + path) 172 | length := len(playlists) 173 | if length != 0 { 174 | fmt.Println("Good Response") 175 | } else {fmt.Println("Error saving Playlists")} 176 | } 177 | 178 | fmt.Println("") 179 | fmt.Println("----------------------------------------------------------------------------------------------------") 180 | fmt.Println("") 181 | 182 | 183 | plentry := plentry.Init() 184 | 185 | plentries := plentry.PlentryRequest(client.Auth(), path) 186 | if plentries[0].Id() != "" { 187 | fmt.Println("PLENTRIES") 188 | fmt.Println("Good Request") 189 | fmt.Println("Plentries saved on: " + path) 190 | length := len(plentries) 191 | if length != 0 { 192 | fmt.Println("Good Response") 193 | } else {fmt.Println("Error saving Plentries")} 194 | } 195 | 196 | fmt.Println("") 197 | fmt.Println("----------------------------------------------------------------------------------------------------") 198 | fmt.Println("") 199 | 200 | stream := stream.Init() 201 | 202 | stream.StreamRequest(client.Auth(), tokenvalues.Sjsaid(), tokenvalues.Xt(), tracks[0].Id(), path) 203 | if stream.StreamUrl() != "" { 204 | fmt.Println("STREAM") 205 | fmt.Println("Good Request") 206 | fmt.Println("Stream saved on: " + path) 207 | } else {fmt.Println("Error saving Stream")} 208 | 209 | fmt.Println("") 210 | fmt.Println("-----------------------------------------------------------------------------------------------------") 211 | }*/ 212 | --------------------------------------------------------------------------------