aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--data.go79
-rw-r--r--lfmclient.go75
-rw-r--r--migrations/20170619201706_like.sql25
-rw-r--r--templates/settings.tmpl10
-rw-r--r--web.go17
5 files changed, 170 insertions, 36 deletions
diff --git a/data.go b/data.go
index c2ecba4..4897665 100644
--- a/data.go
+++ b/data.go
@@ -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, &lt.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">
diff --git a/web.go b/web.go
index 73871b3..25f7b8f 100644
--- a/web.go
+++ b/web.go
@@ -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)
}