diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ed8e18b1..9f94275c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,7 @@ stages: - build variables: - VERSION: 0.1.3 + VERSION: 0.1.4 build-go: image: golang:1.17 diff --git a/docs/changelog.md b/docs/changelog.md index 57cbcfd5..22f3cf81 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,9 @@ +# 0.1.4 +- Fix spotify image import on scrobble for new artists/albums +- Create image resizer + # 0.1.3 -- +- Added date ranges to profile scrobbles # 0.1.2 - Add docker-compose file for local dev diff --git a/go.mod b/go.mod index 4ad57be1..ddd5e23f 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/disintegration/imaging v1.6.2 github.com/go-redis/redis/v8 v8.8.0 github.com/go-sql-driver/mysql v1.5.0 github.com/golang-migrate/migrate v3.5.4+incompatible @@ -38,6 +39,7 @@ require ( go.opentelemetry.io/otel v0.19.0 // indirect go.opentelemetry.io/otel/metric v0.19.0 // indirect go.opentelemetry.io/otel/trace v0.19.0 // indirect + golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3 // indirect diff --git a/go.sum b/go.sum index c65885f0..2e7e6450 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8= @@ -220,6 +222,9 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/internal/goscrobble/album.go b/internal/goscrobble/album.go index a0340380..5289e71e 100644 --- a/internal/goscrobble/album.go +++ b/internal/goscrobble/album.go @@ -62,8 +62,14 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, i if album.Img == "" { if img != "" { - album.Img = img - album.updateAlbum("img", img, tx) + err := importImage(album.UUID, img) + if err != nil { + log.Printf("Failed to import image: %+v. For Album: %s", err, album.Name) + return album, nil + } + + album.Img = "pending" + _ = album.updateAlbum("img", "pending", tx) } } diff --git a/internal/goscrobble/artist.go b/internal/goscrobble/artist.go index 4ad703d5..d68d8e82 100644 --- a/internal/goscrobble/artist.go +++ b/internal/goscrobble/artist.go @@ -72,8 +72,14 @@ func insertArtist(name string, mbid string, spotifyId string, img string, tx *sq if artist.Img == "" { if img != "" { - artist.Img = img - artist.updateArtist("img", img, tx) + err := importImage(artist.UUID, img) + if err != nil { + log.Printf("Failed to import image: %+v. For Album: %s", err, artist.Name) + return artist, nil + } + + artist.Img = "pending" + _ = artist.updateArtist("img", "pending", tx) } } diff --git a/internal/goscrobble/image.go b/internal/goscrobble/image.go index cb1b584c..be10c9a3 100644 --- a/internal/goscrobble/image.go +++ b/internal/goscrobble/image.go @@ -3,8 +3,11 @@ package goscrobble import ( "fmt" "io" + "log" "net/http" "os" + + "github.com/disintegration/imaging" ) func importImage(uuid string, url string) error { @@ -33,13 +36,67 @@ func importImage(uuid string, url string) error { return err } - // Goroutine the resize to keep it _faaaast_ - go resizeImage(uuid) return nil } -func resizeImage(uuid string) { - // resize to 300x300 and maybe smaller? - - return +func resizeImages() { + resizeBulk("artists") + resizeBulk("albums") +} + +func resizeBulk(recordType string) { + // Fetch pending 500 at a time cause we do it every minute anyway + rows, err := db.Query("SELECT BIN_TO_UUID(`uuid`, true) FROM `" + recordType + "` WHERE `img` = 'pending' LIMIT 500") + if err != nil { + log.Printf("Failed to get pending images: %+v", err) + return + } + + // Fetch pending 100 at a time + for rows.Next() { + var uuid string + err := rows.Scan(&uuid) + if err != nil { + log.Printf("Failed to fetch record image resize: %+v", err) + rows.Close() + return + } + + // Run the resize to 300px + success := resizeImage(uuid, 300) + if !success { + // If we get an error.. lets just remove the image link for now so it can reimport + _, err = db.Exec("UPDATE `"+recordType+"` SET `img` = NULL WHERE `uuid` = UUID_TO_BIN(?,true)", uuid) + } else { + // Update DB to reflect complete + _, err = db.Exec("UPDATE `"+recordType+"` SET `img` = 'complete' WHERE `uuid` = UUID_TO_BIN(?,true)", uuid) + } + } + + rows.Close() +} + +func resizeAlbums() { + +} + +func resizeImage(uuid string, size int) bool { + // Open source image + src, err := imaging.Open(DataDirectory + string(os.PathSeparator) + "img" + string(os.PathSeparator) + uuid + "_full.jpg") + if err != nil { + log.Printf("Failed to open image: %+v", err) + return false + } + + // Resize image to specified size + resizedImage := imaging.Resize(src, size, size, imaging.Lanczos) + + // Save resized image + err = imaging.Save(resizedImage, DataDirectory+string(os.PathSeparator)+"img"+string(os.PathSeparator)+uuid+"_300px.jpg") + if err != nil { + log.Printf("failed to save image: %v", err) + return false + } + + return true } diff --git a/internal/goscrobble/ingress_spotify.go b/internal/goscrobble/ingress_spotify.go index 78f45887..edb4099d 100644 --- a/internal/goscrobble/ingress_spotify.go +++ b/internal/goscrobble/ingress_spotify.go @@ -324,12 +324,14 @@ func (user *User) updateImageDataFromSpotify() { for uuid, img := range toUpdate { album, err = getAlbumByUUID(uuid) err = importImage(uuid, img) - if err != nil { continue } + + // Update _ = album.updateAlbum("img", "pending", tx) } + tx.Commit() return diff --git a/internal/goscrobble/server.go b/internal/goscrobble/server.go index bba6aef6..df5054b6 100644 --- a/internal/goscrobble/server.go +++ b/internal/goscrobble/server.go @@ -821,7 +821,7 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) { } info := ServerInfo{ - Version: "0.1.3", + Version: "0.1.4", RegistrationEnabled: registrationEnabled, } diff --git a/internal/goscrobble/timers.go b/internal/goscrobble/timers.go index 070e2bcb..61736e74 100644 --- a/internal/goscrobble/timers.go +++ b/internal/goscrobble/timers.go @@ -10,8 +10,8 @@ var endTicker chan bool func StartBackgroundWorkers() { endTicker := make(chan bool) - hourTicker := time.NewTicker(time.Duration(1) * time.Hour) minuteTicker := time.NewTicker(time.Duration(60) * time.Second) + hourTicker := time.NewTicker(time.Duration(1) * time.Hour) go func() { for { @@ -19,6 +19,15 @@ func StartBackgroundWorkers() { case <-endTicker: fmt.Println("Stopping background workers") return + case <-minuteTicker.C: + // Update playdata from Spotify + go updateSpotifyData() + + // Update playdate from Navidrome + go updateNavidromeData() + + // There should only be whatever new images are in pending + go resizeImages() case <-hourTicker.C: // Clear old password reset tokens go clearOldResetTokens() @@ -26,12 +35,6 @@ func StartBackgroundWorkers() { // Attempt to pull missing images from spotify - hackerino version! user, _ := getUserByUsername("idanoo") go user.updateImageDataFromSpotify() - case <-minuteTicker.C: - // Update playdata from Spotify - go updateSpotifyData() - - // Update playdate from Navidrome - go updateNavidromeData() } } }()