diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d3a416b6..faf455d2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,7 @@ stages:
- bundle
variables:
- VERSION: 0.0.24
+ VERSION: 0.0.25
build-go:
image: golang:1.16.2
diff --git a/docs/changelog.md b/docs/changelog.md
index 47bcdadc..a689004a 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -1,3 +1,7 @@
+# 0.0.25
+- Images now pull from spotify if setup!
+- Show top artists/album
+
# 0.0.24
- Spotify will now add images on scrobble
- Renamed /api/v1/track to tracks to bypass blocklists... (uBlock :()
diff --git a/internal/goscrobble/artist.go b/internal/goscrobble/artist.go
index e29b0a59..136befc2 100644
--- a/internal/goscrobble/artist.go
+++ b/internal/goscrobble/artist.go
@@ -15,6 +15,17 @@ type Artist struct {
SpotifyID string `json:"spotify_id"`
}
+type TopArtist struct {
+ UUID string `json:"uuid"`
+ Name string `json:"name"`
+ Img string `json:"img"`
+ Plays int `json:"plays"`
+}
+
+type TopArtists struct {
+ Artists map[int]TopArtist `json:"artists"`
+}
+
// insertArtist - This will return if it exists or create it based on MBID > Name
func insertArtist(name string, mbid string, spotifyId string, img string, tx *sql.Tx) (Artist, error) {
artist := Artist{}
@@ -114,3 +125,42 @@ func getArtistByUUID(uuid string) (Artist, error) {
return artist, nil
}
+
+func getTopArtists(userUuid string) (TopArtists, error) {
+ var topArtist TopArtists
+
+ rows, err := db.Query("SELECT BIN_TO_UUID(`artists`.`uuid`, true), `artists`.`name`, IFNULL(`artists`.`img`,''), count(*) "+
+ "FROM `scrobbles` "+
+ "JOIN `tracks` ON `tracks`.`uuid` = `scrobbles`.`track` "+
+ "JOIN track_artist ON track_artist.track = tracks.uuid "+
+ "JOIN artists ON track_artist.artist = artists.uuid "+
+ "WHERE `scrobbles`.`user` = UUID_TO_BIN(?, true) "+
+ "GROUP BY `artists`.`uuid` "+
+ "ORDER BY count(*) DESC "+
+ "LIMIT 14;",
+ userUuid)
+ if err != nil {
+ log.Printf("Failed to fetch top artist: %+v", err)
+ return topArtist, errors.New("Failed to fetch top artist")
+ }
+ defer rows.Close()
+
+ i := 1
+ tempArtists := make(map[int]TopArtist)
+
+ for rows.Next() {
+ var artist TopArtist
+ err := rows.Scan(&artist.UUID, &artist.Name, &artist.Img, &artist.Plays)
+ if err != nil {
+ log.Printf("Failed to fetch artist: %+v", err)
+ return topArtist, errors.New("Failed to fetch artist")
+ }
+
+ tempArtists[i] = artist
+ i++
+ }
+
+ topArtist.Artists = tempArtists
+
+ return topArtist, nil
+}
diff --git a/internal/goscrobble/ingress_spotify.go b/internal/goscrobble/ingress_spotify.go
index e549ee0e..9a89657d 100644
--- a/internal/goscrobble/ingress_spotify.go
+++ b/internal/goscrobble/ingress_spotify.go
@@ -214,6 +214,102 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client
return nil
}
-func (track *Track) updateImageFromSpotify() error {
+// updateImageDataFromSpotify update artist/album images from spotify ;D
+func (user *User) updateImageDataFromSpotify() error {
+ // Check that data is set before we attempt to pull
+ val, _ := getConfigValue("SPOTIFY_APP_SECRET")
+ if val == "" {
+ return nil
+ }
+
+ // TO BE REWORKED TO NOT USE A DAMN USER ARGHHH
+ dbToken, err := user.getSpotifyTokens()
+ if err != nil {
+ return nil
+ }
+
+ token := new(oauth2.Token)
+ token.AccessToken = dbToken.AccessToken
+ token.RefreshToken = dbToken.RefreshToken
+ token.Expiry = dbToken.Expiry
+ token.TokenType = "Bearer"
+
+ auth := getSpotifyAuthHandler()
+ client := auth.NewClient(token)
+ client.AutoRetry = true
+
+ rows, err := db.Query("SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `artists` WHERE IFNULL(`img`,'') = '' LIMIT 50")
+ if err != nil {
+ log.Printf("Failed to fetch config: %+v", err)
+ return errors.New("Failed to fetch artists")
+ }
+
+ toUpdate := make(map[string]string)
+ for rows.Next() {
+ var uuid string
+ var name string
+ err := rows.Scan(&uuid, &name)
+ if err != nil {
+ log.Printf("Failed to fetch artists: %+v", err)
+ rows.Close()
+ return errors.New("Failed to fetch artist")
+ }
+ res, err := client.Search(name, spotify.SearchTypeArtist)
+ if len(res.Artists.Artists) > 0 {
+ if len(res.Artists.Artists[0].Images) > 0 {
+ toUpdate[uuid] = res.Artists.Artists[0].Images[0].URL
+ }
+ }
+
+ }
+ rows.Close()
+
+ var artist Artist
+ tx, _ := db.Begin()
+ for uuid, img := range toUpdate {
+ artist, err = getArtistByUUID(uuid)
+ if err != nil {
+ continue
+ }
+ _ = artist.updateArtist("img", img, tx)
+ }
+ tx.Commit()
+
+ rows, err = db.Query("SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `albums` WHERE IFNULL(`img`,'') = '' LIMIT 50")
+ if err != nil {
+ log.Printf("Failed to fetch config: %+v", err)
+ return errors.New("Failed to fetch artists")
+ }
+
+ toUpdate = make(map[string]string)
+ for rows.Next() {
+ var uuid string
+ var name string
+ err := rows.Scan(&uuid, &name)
+ if err != nil {
+ log.Printf("Failed to fetch albums: %+v", err)
+ rows.Close()
+ return errors.New("Failed to fetch album")
+ }
+ res, err := client.Search(name, spotify.SearchTypeAlbum)
+ if len(res.Albums.Albums) > 0 {
+ if len(res.Albums.Albums[0].Images) > 0 {
+ toUpdate[uuid] = res.Albums.Albums[0].Images[0].URL
+ }
+ }
+
+ }
+ rows.Close()
+
+ var album Album
+ tx, _ = db.Begin()
+ for uuid, img := range toUpdate {
+ album, err = getAlbumByUUID(uuid)
+ if err != nil {
+ continue
+ }
+ _ = album.updateAlbum("img", img, tx)
+ }
+ tx.Commit()
return nil
}
diff --git a/internal/goscrobble/server.go b/internal/goscrobble/server.go
index 460eca3b..02def728 100644
--- a/internal/goscrobble/server.go
+++ b/internal/goscrobble/server.go
@@ -550,13 +550,13 @@ func getArtists(w http.ResponseWriter, r *http.Request) {
return
}
- artist, err := getArtistByUUID(uuid)
+ track, err := getTopArtists(uuid)
if err != nil {
throwOkError(w, err.Error())
return
}
- json, _ := json.Marshal(&artist)
+ json, _ := json.Marshal(&track)
w.WriteHeader(http.StatusOK)
w.Write(json)
}
@@ -665,7 +665,7 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) {
}
info := ServerInfo{
- Version: "0.0.24",
+ Version: "0.0.25",
RegistrationEnabled: cachedRegistrationEnabled,
}
diff --git a/internal/goscrobble/timers.go b/internal/goscrobble/timers.go
index e2d74906..61c6d09b 100644
--- a/internal/goscrobble/timers.go
+++ b/internal/goscrobble/timers.go
@@ -8,11 +8,10 @@ import (
var endTicker chan bool
func StartBackgroundWorkers() {
- updateSpotifyData()
endTicker := make(chan bool)
- hourTicker := time.NewTicker(time.Hour)
+ hourTicker := time.NewTicker(time.Duration(1) * time.Hour)
minuteTicker := time.NewTicker(time.Duration(60) * time.Second)
go func() {
@@ -25,6 +24,9 @@ func StartBackgroundWorkers() {
// Clear old password reset tokens
clearOldResetTokens()
+ // Attempt to pull missing images from spotify - hackerino version!
+ user, _ := getUserByUsername("idanoo")
+ user.updateImageDataFromSpotify()
case <-minuteTicker.C:
// Update playdata from spotify
updateSpotifyData()
diff --git a/internal/goscrobble/track.go b/internal/goscrobble/track.go
index 4958fe06..d920f610 100644
--- a/internal/goscrobble/track.go
+++ b/internal/goscrobble/track.go
@@ -178,11 +178,11 @@ func getTrackByUUID(uuid string) (Track, error) {
func getTopTracks(userUuid string) (TopTracks, error) {
var topTracks TopTracks
- rows, err := db.Query("SELECT BIN_TO_UUID(`tracks`.`uuid`, true), `tracks`.`name`, IFNULL(`artists`.`img`,''), count(*) "+
+ rows, err := db.Query("SELECT BIN_TO_UUID(`tracks`.`uuid`, true), `tracks`.`name`, IFNULL(`albums`.`img`,''), count(*) "+
"FROM `scrobbles` "+
"JOIN `tracks` ON `tracks`.`uuid` = `scrobbles`.`track` "+
- "JOIN track_artist ON track_artist.track = tracks.uuid "+
- "JOIN artists ON track_artist.artist = artists.uuid "+
+ "JOIN track_album ON track_album.track = tracks.uuid "+
+ "JOIN albums ON track_album.album = albums.uuid "+
"WHERE `user` = UUID_TO_BIN(?, true) "+
"GROUP BY `scrobbles`.`track` "+
"ORDER BY count(*) DESC "+
diff --git a/web/src/Api/index.js b/web/src/Api/index.js
index 5e8ee6ce..64754e49 100644
--- a/web/src/Api/index.js
+++ b/web/src/Api/index.js
@@ -326,3 +326,12 @@ export const getTopTracks = (uuid) => {
return handleErrorResp(error)
});
}
+
+export const getTopArtists = (uuid) => {
+ return axios.get(process.env.REACT_APP_API_URL + "artists/top/" + uuid).then(
+ (data) => {
+ return data.data;
+ }).catch((error) => {
+ return handleErrorResp(error)
+ });
+}
\ No newline at end of file
diff --git a/web/src/Components/TopTable.js b/web/src/Components/TopTable.js
index a7559ae2..4e5b378b 100644
--- a/web/src/Components/TopTable.js
+++ b/web/src/Components/TopTable.js
@@ -3,13 +3,13 @@ import './TopTable.css'
import TopTableBox from './TopTableBox';
const TopTable = (props) => {
- if (!props.items || !props.items.tracks) {
+ if (!props.items || Object.keys(props.items).length < 1) {
return (
- No data.
+ Not enough data to show top {props.type}s.
)
}
- let tracks = props.items.tracks;
+ let tracks = props.items;
return (