diff options
| -rw-r--r-- | data.go | 79 | ||||
| -rw-r--r-- | lfmclient.go | 75 | ||||
| -rw-r--r-- | migrations/20170619201706_like.sql | 25 | ||||
| -rw-r--r-- | templates/settings.tmpl | 10 | ||||
| -rw-r--r-- | web.go | 17 |
5 files changed, 170 insertions, 36 deletions
@@ -55,6 +55,12 @@ type Import struct { Count int } +type LoveImport struct { + LfmName string + Time time.Time + Count int +} + type DataStore interface { PutSession(*Session) error GetSession(key string) (*Session, error) @@ -74,7 +80,12 @@ type DataStore interface { SaveImport(i *Import) error InsertImport(i *Import) error NewImport(name string) *Import - ImportStats(user int) (time.Time, int, error) + ImportStats(name string) (*Import, error) + + InsertLoveImport(i *LoveImport) error + LoveImportStats(name string) (*LoveImport, error) + + InsertLovedTracks([]LovedTrack, *Session) error InsertUserSession(s *UserSession) error Api @@ -295,23 +306,55 @@ func (store *SqlStore) NewImport(name string) *Import { return i } -func (store *SqlStore) ImportStats(user int) (time.Time, int, error) { +func (store *SqlStore) ImportStats(name string) (*Import, error) { query := ` - SELECT "last", ct - FROM ( - SELECT max("to") "last", sum(count) ct, lfm_name - FROM scrobble_import - GROUP BY lfm_name - ) i - JOIN users - ON users.lfm_name = i.lfm_name - WHERE users.user_id = $1` - var t time.Time - var count int - row := store.QueryRow(query, user) - if err := row.Scan(&t, &count); err != nil { - return t, count, err - } else { - return t, count, nil + SELECT max("to"), sum(count) + FROM scrobble_import + WHERE lfm_name=$1 + GROUP BY lfm_name` + i := new(Import) + row := store.QueryRow(query, name) + err := row.Scan(&i.To, &i.Count) + return i, err +} + +func (store *SqlStore) InsertLoveImport(i *LoveImport) error { + query := ` + INSERT INTO love_import (lfm_name, count) VALUES ($1, $2)` + _, err := store.Exec(query, i.LfmName, i.Count) + return err +} + +func (store *SqlStore) InsertLovedTracks(lt []LovedTrack, se *Session) error { + tx, err := store.Begin() + if err != nil { + return err } + query := ` + INSERT INTO love + (artist, name, mbid, time, session, "user") + VALUES ($1, $2, $3, $4, $5, $6)` + st, err := tx.Prepare(query) + if err != nil { + return err + } + + for _, t := range lt { + _, err = st.Exec(t.Artist.Name, t.Name, t.Mbid, t.Date.ToTime(), + se.Key, se.UserId) + if err != nil { + tx.Rollback() + return err + } + } + return tx.Commit() +} +func (store *SqlStore) LoveImportStats(name string) (*LoveImport, error) { + query := ` + SELECT max(time), sum(count) FROM love_import + WHERE lfm_name = $1 GROUP BY lfm_name` + li := new(LoveImport) + row := store.QueryRow(query, name) + err := row.Scan(&li.Time, &li.Count) + return li, err } diff --git a/lfmclient.go b/lfmclient.go index bbc0492..1ce822d 100644 --- a/lfmclient.go +++ b/lfmclient.go @@ -229,20 +229,73 @@ func (app *App) ImportRecentTracks(user *User) { } } -func (app *App) LovedTracks(user string) []LovedTrack { - r := app.LfmQuery(map[string]string{ - "method": "user.getLovedTracks", - "limit": "100", - "user": user, - }) - var dst map[string]struct { +type LovedTracks struct { + dst map[string]struct { Attrs PageAttrs `json:"@attr"` Tracks []LovedTrack `json:"track"` } - json.Unmarshal(r, &dst) - root := dst["lovedtracks"] - tracks := root.Tracks - return tracks + payload map[string]string + page int + done bool + *App +} + +func NewLovedTracks(name string, app *App) *LovedTracks { + lt := &LovedTracks{App: app, page: 1} + lt.payload = map[string]string{ + "method": "user.getLovedTracks", + "limit": "200", + "user": name, + } + return lt +} + +func (lt *LovedTracks) Next() []LovedTrack { + if lt.done { + return nil + } + lt.payload["page"] = strconv.Itoa(lt.page) + r := lt.App.LfmQuery(lt.payload) + json.Unmarshal(r, <.dst) + root := lt.dst["lovedtracks"] + totalPages, _ := strconv.Atoi(root.Attrs.TotalPages) + if totalPages == lt.page { + lt.done = true + } + lt.page++ + return root.Tracks +} + +func (app *App) ImportLovedTracks(user *User) { + s := &Session{ + UserId: user.Id, + Client: "import", + ClientVersion: "", + Key: randomToken(16), + Protocol: "1.2.1", + } + app.PutSession(s) + ll, _ := app.LoveImportStats(user.LfmName) + lt := NewLovedTracks(user.LfmName, app) + ltracks := make([]LovedTrack, 0, 200) + li := LoveImport{Count: 0, LfmName: user.LfmName} + for tracks := lt.Next(); len(tracks) > 0; tracks = lt.Next() { + ltracks = ltracks[:0] + for _, t := range tracks { + if t.Date.ToTime().Before(ll.Time) { + break + } + ltracks = append(ltracks, t) + } + if err := app.InsertLovedTracks(ltracks, s); err != nil { + log.Println(err) + return + } + li.Count += len(ltracks) + } + if err := app.InsertLoveImport(&li); err != nil { + log.Println(err) + } } func (app *App) GetSong(s *Song) { diff --git a/migrations/20170619201706_like.sql b/migrations/20170619201706_like.sql new file mode 100644 index 0000000..88a1f59 --- /dev/null +++ b/migrations/20170619201706_like.sql @@ -0,0 +1,25 @@ + +-- +goose Up +-- SQL in section 'Up' is executed when this migration is applied + +CREATE TABLE love ( + id serial PRIMARY KEY, + time timestamptz, + artist text, + name text, + mbid text, + session text REFERENCES scrobbling_sessions(session_key), + "user" int REFERENCES users(user_id) +); + +CREATE TABLE love_import ( + lfm_name text, + time timestamptz DEFAULT NOW(), + "count" int +); + +-- +goose Down +-- SQL section 'Down' is executed when this migration is rolled back + +DROP TABLE love_import; +DROP TABLE love; diff --git a/templates/settings.tmpl b/templates/settings.tmpl index da3dabb..5632cda 100644 --- a/templates/settings.tmpl +++ b/templates/settings.tmpl @@ -30,10 +30,14 @@ </div> <p> - {{if not .LastImport.IsZero}} - {{.ImportCount}} listens imported from Last.fm (last import on {{.LastImport.Format "Mon, Jan 2 15:04"}}). + {{if not .Import.To.IsZero}} + {{.Import.Count}} listens imported from Last.fm (last import on {{.Import.To.Format "Mon, Jan 2 15:04"}}). {{end}} - <input type="submit" name="import" value="IMPORT"> + <input type="submit" name="import" value="IMPORT"><br/> + {{if not .LoveImport.Time.IsZero}} + {{.LoveImport.Count}} loved tracks imported from Last.fm (last import on {{.LoveImport.Time.Format "Mon, Jan 2 15:04"}}). + {{end}} + <input type="submit" name="love_import" value="IMPORT"> </p> </section> <div class="row"> @@ -136,17 +136,26 @@ func (app *App) settings(w http.ResponseWriter, r *http.Request) { go app.ImportRecentTracks(u) } + if r.Method == "POST" && r.FormValue("love_import") != "" { + u := &User{ + Id: se.UserId, + } + app.GetUser(u) + go app.ImportLovedTracks(u) + } + user := &User{Id: se.UserId} if err := app.GetUser(user); err != nil { log.Println(err) } - li, ct, err := app.ImportStats(user.Id) + i, err := app.ImportStats(user.LfmName) + li, err := app.LoveImportStats(user.LfmName) err = app.Template.ExecuteTemplate(w, "settings.tmpl", struct { Session *UserSession *User - LastImport time.Time - ImportCount int - }{Session: se, User: user, LastImport: li, ImportCount: ct}) + LoveImport *LoveImport + Import *Import + }{Session: se, User: user, LoveImport: li, Import: i}) if err != nil { log.Println(err) } |
