2021-03-28 08:52:34 +00:00
|
|
|
package goscrobble
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"errors"
|
2021-04-02 09:24:00 +00:00
|
|
|
"fmt"
|
2021-03-28 08:52:34 +00:00
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Scrobble struct {
|
|
|
|
Uuid string `json:"uuid"`
|
|
|
|
CreatedAt time.Time `json:"created_at"`
|
|
|
|
CreatedIp net.IP `json:"created_ip"`
|
|
|
|
User string `json:"user"`
|
|
|
|
Track string `json:"track"`
|
|
|
|
}
|
|
|
|
|
2021-04-02 09:24:00 +00:00
|
|
|
type ScrobbleResponse struct {
|
|
|
|
Meta ScrobbleResponseMeta `json:"meta"`
|
|
|
|
Items []ScrobbleResponseItem `json:"items"`
|
2021-03-29 07:56:34 +00:00
|
|
|
}
|
|
|
|
|
2021-04-02 09:24:00 +00:00
|
|
|
type ScrobbleResponseMeta struct {
|
2021-03-29 07:56:34 +00:00
|
|
|
Count int `json:"count"`
|
|
|
|
Total int `json:"total"`
|
|
|
|
Page int `json:"page"`
|
|
|
|
}
|
|
|
|
|
2021-04-02 09:24:00 +00:00
|
|
|
type ScrobbleResponseItem struct {
|
2021-03-29 07:56:34 +00:00
|
|
|
UUID string `json:"uuid"`
|
|
|
|
Timestamp time.Time `json:"time"`
|
|
|
|
Artist string `json:"artist"`
|
|
|
|
Album string `json:"album"`
|
|
|
|
Track string `json:"track"`
|
2021-04-02 09:24:00 +00:00
|
|
|
Source string `json:"source"`
|
2021-03-29 07:56:34 +00:00
|
|
|
}
|
|
|
|
|
2021-03-28 08:52:34 +00:00
|
|
|
// insertScrobble - This will return if it exists or create it based on MBID > Name
|
2021-04-02 09:24:00 +00:00
|
|
|
func insertScrobble(user string, track string, source string, timestamp time.Time, ip net.IP, tx *sql.Tx) error {
|
|
|
|
err := insertNewScrobble(user, track, source, timestamp, ip, tx)
|
2021-03-28 08:52:34 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error inserting scrobble %s %+v", user, err)
|
|
|
|
return errors.New("Failed to insert scrobble!")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-04-02 09:24:00 +00:00
|
|
|
func fetchScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse, error) {
|
|
|
|
scrobbleReq := ScrobbleResponse{}
|
2021-03-29 07:56:34 +00:00
|
|
|
var count int
|
|
|
|
|
|
|
|
// Yeah this isn't great. But for now.. it works! Cache later
|
|
|
|
total, err := getDbCount(
|
|
|
|
"SELECT COUNT(*) FROM `scrobbles` "+
|
|
|
|
"JOIN tracks ON scrobbles.track = tracks.uuid "+
|
|
|
|
"JOIN track_artist ON track_artist.track = tracks.uuid "+
|
|
|
|
"JOIN track_album ON track_album.track = tracks.uuid "+
|
|
|
|
"JOIN artists ON track_artist.artist = artists.uuid "+
|
|
|
|
"JOIN albums ON track_album.album = albums.uuid "+
|
|
|
|
"JOIN users ON scrobbles.user = users.uuid "+
|
2021-04-02 09:24:00 +00:00
|
|
|
"WHERE user = UUID_TO_BIN(?, true) "+
|
|
|
|
"GROUP BY scrobbles.uuid",
|
2021-03-29 07:56:34 +00:00
|
|
|
userUuid)
|
2021-03-28 08:52:34 +00:00
|
|
|
|
|
|
|
if err != nil {
|
2021-03-29 07:56:34 +00:00
|
|
|
log.Printf("Failed to fetch scrobble count: %+v", err)
|
|
|
|
return scrobbleReq, errors.New("Failed to fetch scrobbles")
|
|
|
|
}
|
|
|
|
|
|
|
|
rows, err := db.Query(
|
2021-04-02 09:24:00 +00:00
|
|
|
"SELECT BIN_TO_UUID(`scrobbles`.`uuid`, true), `scrobbles`.`created_at`, `artists`.`name`, `albums`.`name`,`tracks`.`name`, `scrobbles`.`source` FROM `scrobbles` "+
|
2021-03-29 07:56:34 +00:00
|
|
|
"JOIN tracks ON scrobbles.track = tracks.uuid "+
|
|
|
|
"JOIN track_artist ON track_artist.track = tracks.uuid "+
|
|
|
|
"JOIN track_album ON track_album.track = tracks.uuid "+
|
|
|
|
"JOIN artists ON track_artist.artist = artists.uuid "+
|
|
|
|
"JOIN albums ON track_album.album = albums.uuid "+
|
|
|
|
"JOIN users ON scrobbles.user = users.uuid "+
|
|
|
|
"WHERE user = UUID_TO_BIN(?, true) "+
|
2021-04-01 10:17:46 +00:00
|
|
|
"ORDER BY scrobbles.created_at DESC LIMIT ?",
|
|
|
|
userUuid, limit)
|
2021-03-29 07:56:34 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Failed to fetch scrobbles: %+v", err)
|
|
|
|
return scrobbleReq, errors.New("Failed to fetch scrobbles")
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
for rows.Next() {
|
2021-04-02 09:24:00 +00:00
|
|
|
item := ScrobbleResponseItem{}
|
|
|
|
err := rows.Scan(&item.UUID, &item.Timestamp, &item.Artist, &item.Album, &item.Track, &item.Source)
|
2021-03-29 07:56:34 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Failed to fetch scrobbles: %+v", err)
|
|
|
|
return scrobbleReq, errors.New("Failed to fetch scrobbles")
|
2021-03-28 08:52:34 +00:00
|
|
|
}
|
2021-03-29 07:56:34 +00:00
|
|
|
count++
|
|
|
|
scrobbleReq.Items = append(scrobbleReq.Items, item)
|
2021-03-28 08:52:34 +00:00
|
|
|
}
|
|
|
|
|
2021-03-29 07:56:34 +00:00
|
|
|
err = rows.Err()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Failed to fetch scrobbles: %+v", err)
|
|
|
|
return scrobbleReq, errors.New("Failed to fetch scrobbles")
|
|
|
|
}
|
|
|
|
|
|
|
|
scrobbleReq.Meta.Count = count
|
|
|
|
scrobbleReq.Meta.Total = total
|
|
|
|
scrobbleReq.Meta.Page = page
|
|
|
|
|
|
|
|
return scrobbleReq, nil
|
2021-03-28 08:52:34 +00:00
|
|
|
}
|
|
|
|
|
2021-04-02 09:24:00 +00:00
|
|
|
func insertNewScrobble(user string, track string, source string, timestamp time.Time, ip net.IP, tx *sql.Tx) error {
|
2021-04-01 10:17:46 +00:00
|
|
|
_, err := tx.Exec("INSERT INTO `scrobbles` (`uuid`, `created_at`, `created_ip`, `user`, `track`, `source`) "+
|
2021-04-02 09:24:00 +00:00
|
|
|
"VALUES (UUID_TO_BIN(UUID(), true), ?, ?, UUID_TO_BIN(?, true), UUID_TO_BIN(?, true), ?)", timestamp, ip, user, track, source)
|
2021-03-28 08:52:34 +00:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
2021-04-02 09:24:00 +00:00
|
|
|
|
|
|
|
func checkIfScrobbleExists(userUuid string, timestamp time.Time, source string) bool {
|
|
|
|
count, err := getDbCount("SELECT COUNT(*) FROM `scrobbles` WHERE `user` = UUID_TO_BIN(?, true) AND `created_at` = ? AND `source` = ?",
|
|
|
|
userUuid, timestamp, source)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error fetching scrobble exists count: %+v", err)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return count != 0
|
|
|
|
}
|