aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThibaut Horel <thibaut.horel@gmail.com>2017-06-17 12:49:28 -0400
committerThibaut Horel <thibaut.horel@gmail.com>2017-06-17 12:49:28 -0400
commit858de1edf50cc1128f6b621a5413b2975ca446eb (patch)
tree09cec370362844ac9a3fc7c6a128808f632894c7
parent060b315f74f437fe36175c4ddb52379d29808d64 (diff)
downloadlastfm-api-858de1edf50cc1128f6b621a5413b2975ca446eb.tar.gz
Clean fecthing of song metadata from Last.fm
-rw-r--r--apiv1.go17
-rw-r--r--data.go35
-rw-r--r--lfmclient.go129
3 files changed, 113 insertions, 68 deletions
diff --git a/apiv1.go b/apiv1.go
index 1f96819..4cf8941 100644
--- a/apiv1.go
+++ b/apiv1.go
@@ -180,7 +180,7 @@ func (app *App) scrobbleHandler(w http.ResponseWriter, r *http.Request) {
scrobbles, _ := parseScrobbles(r.Form, session)
for i, s := range scrobbles {
- app.GetSong(&s)
+ app.GetScrobbleSong(&s)
scrobbles[i] = s
}
@@ -211,6 +211,19 @@ func parseNowPlaying(values url.Values) (Scrobble, error) {
return scrobble, nil
}
+func (app *App) GetScrobbleSong(s *Scrobble) {
+ song := Song{
+ Artist: s.Artist.Name,
+ Album: s.Album.Name,
+ Name: s.TrackName.Name,
+ TrackNumber: s.TrackNumber,
+ Duration: s.Duration * 1000,
+ Mbid: s.Mbid,
+ }
+ app.GetSong(&song)
+ s.SongId = song.Id
+}
+
func (app *App) nowPlayingHandler(w http.ResponseWriter, r *http.Request) {
session, err := app.GetSession(r.FormValue("s"))
if err != nil {
@@ -221,7 +234,7 @@ func (app *App) nowPlayingHandler(w http.ResponseWriter, r *http.Request) {
s, err := parseNowPlaying(r.Form)
s.SessionKey = session.Key
s.UserId = session.UserId
- app.GetSong(&s)
+ app.GetScrobbleSong(&s)
if err := app.PutNowPlaying(s); err != nil {
log.Println(err)
fmt.Fprintln(w, "Failed Database")
diff --git a/data.go b/data.go
index b97d4a4..5f1f0fb 100644
--- a/data.go
+++ b/data.go
@@ -35,6 +35,17 @@ type Session struct {
Subscriber int64 `json:"subscriber" xml:"subscriber"`
}
+type Song struct {
+ Id int
+ Artist string
+ Album string
+ Name string
+ TrackNumber int
+ Duration int
+ Mbid string
+ Image string
+}
+
type DataStore interface {
PutSession(*Session) error
GetSession(key string) (*Session, error)
@@ -42,8 +53,9 @@ type DataStore interface {
PutNowPlaying(s Scrobble) error
NowPlaying(userId int) *Scrobble
RecentScrobbles(userId int) []*Scrobble
- GetSongId(artist, album, name string) (int, error)
- InsertSong(s *Scrobble) (int, error)
+
+ GetSongId(s *Song) error
+ InsertSong(s *Song) error
GetScrobblingUser(lfmName string) (int, string, error)
GetUser(u *User) error
@@ -166,28 +178,23 @@ func (store *SqlStore) NowPlaying(userId int) *Scrobble {
return scrobble
}
-func (store *SqlStore) GetSongId(artist, album, song string) (int, error) {
+func (store *SqlStore) GetSongId(s *Song) error {
query := `
SELECT song_id FROM songs
WHERE artist=$1 AND album=$2 AND name=$3
`
- var id int
- row := store.QueryRow(query, artist, album, song)
- err := row.Scan(&id)
- return id, err
-
+ row := store.QueryRow(query, s.Artist, s.Album, s.Name)
+ return row.Scan(&s.Id)
}
-func (store *SqlStore) InsertSong(s *Scrobble) (int, error) {
+func (store *SqlStore) InsertSong(s *Song) error {
query := `
INSERT INTO songs (artist, album, name, track_number, duration, mbid, image)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING song_id`
- var id int
- row := store.QueryRow(query, s.Artist, s.Album, s.TrackName, s.TrackNumber,
- s.Duration*1000, s.Mbid, s.Image)
- err := row.Scan(&id)
- return id, err
+ row := store.QueryRow(query, s.Artist, s.Album, s.Name, s.TrackNumber,
+ s.Duration, s.Mbid, s.Image)
+ return row.Scan(&s.Id)
}
func (store *SqlStore) InsertUser(user *User) error {
diff --git a/lfmclient.go b/lfmclient.go
index 9c500b7..41ecd37 100644
--- a/lfmclient.go
+++ b/lfmclient.go
@@ -2,35 +2,41 @@ package main
import (
"encoding/json"
+ "fmt"
"io/ioutil"
"log"
"net/http"
- "strconv"
)
-type AlbumImage struct {
+type Image struct {
Size string `json:"size"`
Href string `json:"#text"`
}
-func (a AlbumInfo) GetImage(size string) string {
- images := a.Images
- for _, image := range images {
- if image.Size == size {
- return image.Href
- }
- }
- return "https://lastfm-img2.akamaized.net/i/u/64s/4128a6eb29f94943c9d206c08e625904.png"
+type AlbumInfo struct {
+ Images []Image `json:"image"`
+ Mbid string
+ Name string `json:"title"`
+ Url string
+ Position `json:"@attr"`
}
-type AlbumInfo struct {
- Images []AlbumImage `json:"image"`
- Mbid string `json:"mbid"`
- Name string `json:"title"`
+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 `json:"name"`
+ Name string
+ Mbid string
+ Url string
}
type Position struct {
@@ -38,12 +44,11 @@ type Position struct {
}
type TrackInfo struct {
- Name string `json:"name"`
- Mbid string `json:"mbid"`
- Duration string `json:"duration"`
- Artist ArtistInfo `json:"artist"`
- Album AlbumInfo `json:"album"`
- Position `json:"@attr"`
+ Name string
+ Mbid string
+ Duration string
+ Artist ArtistInfo
+ Album AlbumInfo
}
func (app *App) LfmQuery(payload map[string]string) []byte {
@@ -57,10 +62,21 @@ func (app *App) LfmQuery(payload map[string]string) []byte {
r.URL.RawQuery = values.Encode()
resp, _ := http.DefaultClient.Do(r)
body, _ := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
return body
}
-func (app *App) AlbumImage(artist, album string) string {
+func (a AlbumInfo) GetImage(size string) string {
+ images := a.Images
+ 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,
@@ -68,10 +84,10 @@ func (app *App) AlbumImage(artist, album string) string {
})
var dst map[string]AlbumInfo
json.Unmarshal(r, &dst)
- return dst["album"].GetImage("medium")
+ return dst["album"]
}
-func (app *App) TrackInfo(artist, name string) *Scrobble {
+func (app *App) TrackInfo(artist, name string) TrackInfo {
r := app.LfmQuery(map[string]string{
"method": "track.getInfo",
"artist": artist,
@@ -80,40 +96,49 @@ func (app *App) TrackInfo(artist, name string) *Scrobble {
})
var dst map[string]TrackInfo
json.Unmarshal(r, &dst)
- track := dst["track"]
- duration, _ := strconv.Atoi(track.Duration)
- position, _ := strconv.Atoi(track.TrackNumber)
- s := &Scrobble{
- Artist: NewCorrectable(track.Artist.Name),
- Album: NewCorrectable(track.Album.Name),
- TrackName: NewCorrectable(track.Name),
- Duration: duration * 1000,
- TrackNumber: position,
- Mbid: track.Mbid,
- Image: track.Album.GetImage("medium"),
- }
- return s
+ return dst["track"]
+}
+
+func (app *App) RecentTracks(user string) {
+ r := app.LfmQuery(map[string]string{
+ "method": "user.getRecentTracks",
+ "limit": "10",
+ "user": user,
+ })
+ fmt.Println(string(r))
+}
+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 *Scrobble) {
- var err error
- if s.Album.Name != "" {
- id, _ := app.GetSongId(s.Artist.Name, s.Album.Name, s.TrackName.Name)
- if id == 0 {
- s.Image = app.AlbumImage(s.Artist.Name, s.Album.Name)
- id, err = app.InsertSong(s)
- if err != nil {
+func (app *App) GetSong(s *Song) {
+ if s.Album != "" {
+ if app.GetSongId(s) != nil {
+ if s.Image == "" {
+ s.Image = app.AlbumInfo(s.Artist, s.Album).GetImage("medium")
+ }
+ if err := app.InsertSong(s); err != nil {
log.Println(err)
}
}
- s.SongId = id
} else {
- s2 := app.TrackInfo(s.Artist.Name, s.TrackName.Name)
- id, err := app.InsertSong(s2)
- if err != nil {
- log.Println(err)
- }
- s.SongId = id
+ t := app.TrackInfo(s.Artist, s.Name)
+ s.Album = t.Album.Name
+ s.Mbid = t.Mbid
+ s.Image = t.Album.GetImage("medium")
+ app.InsertSong(s)
}
}