package main import ( "encoding/json" "io/ioutil" "log" "net/http" "strconv" "time" ) type Image struct { Size string `json:"size"` Href string `json:"#text"` } type AlbumInfo struct { Images []Image `json:"image"` Mbid string Name string `json:"title"` Url string Position `json:"@attr"` Artist string } type Date struct { Date string `json:"#text"` Uts string } type PageAttrs struct { TotalPages string Total string Page string User string } type ArtistInfo struct { Name string Mbid string Url string } type Position struct { TrackNumber string `json:"position"` } type TrackInfo struct { Name string Mbid string Duration string Artist ArtistInfo Album AlbumInfo PlayCount string Listeners string } type RecentTrack struct { Name string Mbid string Url string Artist struct { Name string `json:"#text"` Mbid string } Album struct { Name string `json:"#text"` Mbid string } Images []Image `json:"image"` Date Date } func (app *App) LfmQuery(payload map[string]string) []byte { r, _ := http.NewRequest("GET", "http://ws.audioscrobbler.com/2.0/", nil) values := r.URL.Query() values.Add("api_key", app.Config.Lfm.ApiKey) values.Add("format", "json") for key, value := range payload { values.Add(key, value) } r.URL.RawQuery = values.Encode() resp, _ := http.DefaultClient.Do(r) body, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() return body } func GetImage(images []Image, size string) string { for _, image := range images { if image.Size == size { return image.Href } } return "https://lastfm-img2.akamaized.net/i/u/64s/4128a6eb29f94943c9d206c08e625904.png" } func (app *App) AlbumInfo(artist, album string) AlbumInfo { r := app.LfmQuery(map[string]string{ "method": "album.getInfo", "artist": artist, "album": album, }) var dst map[string]AlbumInfo json.Unmarshal(r, &dst) return dst["album"] } func (app *App) TrackInfo(artist, name string) TrackInfo { r := app.LfmQuery(map[string]string{ "method": "track.getInfo", "artist": artist, "track": name, "autocorrect": "1", }) var dst map[string]TrackInfo json.Unmarshal(r, &dst) return dst["track"] } func (app *App) ImportRecentTracks(user *User) { s := &Session{ UserId: user.Id, Client: "import", ClientVersion: "", Key: randomToken(16), Protocol: "1.2.1", } app.PutSession(s) i := app.NewImport(user.LfmName) payload := map[string]string{ "method": "user.getRecentTracks", "limit": "200", "user": user.LfmName, "to": strconv.Itoa(int(i.To.Unix())), } if i.From.IsZero() { payload["from"] = "0" } else { payload["from"] = strconv.Itoa(int(i.From.Unix())) } var dst map[string]struct { Attrs PageAttrs `json:"@attr"` Tracks []RecentTrack `json:"track"` } scrobbles := make([]Scrobble, 0, 200) var st time.Time for { scrobbles = scrobbles[:0] if !i.LastFetch.IsZero() { payload["to"] = strconv.Itoa(int(i.LastFetch.Unix())) } r := app.LfmQuery(payload) json.Unmarshal(r, &dst) tracks := dst["recenttracks"].Tracks if len(tracks) == 0 { i.Done = true break } for _, t := range tracks { ts, _ := strconv.Atoi(t.Date.Uts) if ts == 0 { continue } st = time.Unix(int64(ts), 0) scrobble := Scrobble{ Artist: NewCorrectable(t.Artist.Name), Album: NewCorrectable(t.Album.Name), TrackName: NewCorrectable(t.Name), Mbid: t.Mbid, Time: st, UserId: user.Id, SessionKey: s.Key, Image: GetImage(t.Images, "medium"), } app.GetScrobbleSong(&scrobble) scrobbles = append(scrobbles, scrobble) } if err := app.PutScrobbles(scrobbles); err != nil { log.Println(err) } i.LastFetch = st i.Count += len(scrobbles) if err := app.SaveImport(i); err != nil { log.Println(err) } } if err := app.SaveImport(i); err != nil { log.Println(err) } } func (app *App) LovedTracks(user string) []TrackInfo { r := app.LfmQuery(map[string]string{ "method": "user.getLovedTracks", "limit": "100", "user": user, }) var dst map[string]struct { Attrs PageAttrs `json:"@attr"` Tracks []TrackInfo `json:"track"` } json.Unmarshal(r, &dst) root := dst["lovedtracks"] tracks := root.Tracks return tracks } func (app *App) GetSong(s *Song) { if s.Album != "" || s.Mbid != "" { if app.GetSongId(s) != nil { if s.Image == "" { s.Image = GetImage(app.AlbumInfo(s.Artist, s.Album).Images, "medium") } if err := app.InsertSong(s); err != nil { log.Println(err) } } } else { t := app.TrackInfo(s.Artist, s.Name) s.Album = t.Album.Name s.Mbid = t.Mbid s.Image = GetImage(t.Album.Images, "medium") if app.GetSongId(s) != nil { app.InsertSong(s) } } }