From 99f9e7cfb3687fcb4c54dccc8e44ff5bf014b990 Mon Sep 17 00:00:00 2001 From: Daniel Mason Date: Sun, 4 Apr 2021 21:54:53 +1200 Subject: [PATCH] 0.0.19 - Tidy init/goscrobble.service - Add routers for Artist/Album/Track endpoints + basic pages - Move UUID generation into Go so we don't have to query the record!! Wooo! --- .gitlab-ci.yml | 2 +- docs/changelog.md | 5 + go.mod | 1 + go.sum | 2 + init/goscrobble.service | 4 +- internal/goscrobble/album.go | 73 ++++++----- internal/goscrobble/artist.go | 89 +++++++------ internal/goscrobble/genre.go | 2 +- internal/goscrobble/ingress_jellyfin.go | 8 +- internal/goscrobble/ingress_multiscrobbler.go | 6 +- internal/goscrobble/ingress_spotify.go | 10 +- internal/goscrobble/profile.go | 4 +- internal/goscrobble/scrobble.go | 4 +- internal/goscrobble/server.go | 118 +++++++++++++++--- internal/goscrobble/server_middleware.go | 2 +- internal/goscrobble/stats.go | 6 +- internal/goscrobble/track.go | 93 +++++++------- internal/goscrobble/user.go | 2 +- internal/goscrobble/utils.go | 7 +- web/src/Api/index.js | 30 +++++ web/src/Components/Navigation.js | 2 +- web/src/Pages/About.css | 1 + web/src/Pages/Album.js | 32 ++--- web/src/Pages/Artist.js | 32 ++--- web/src/Pages/Docs.css | 1 + web/src/Pages/Docs.js | 25 ++++ web/src/Pages/Track.js | 39 +++--- web/src/Pages/User.js | 2 +- 28 files changed, 388 insertions(+), 214 deletions(-) create mode 100644 web/src/Pages/Docs.css create mode 100644 web/src/Pages/Docs.js diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 157e1ebf..388e81a8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ stages: - bundle variables: - VERSION: 0.0.18 + VERSION: 0.0.19 build-go: image: golang:1.16.2 diff --git a/docs/changelog.md b/docs/changelog.md index 0b64ab50..b8bf03dd 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,8 @@ +# 0.0.19 +- Tidy init/goscrobble.service +- Add routers for Artist/Album/Track endpoints + basic pages +- Move UUID generation into Go so we don't have to query the record!! Wooo! + # 0.0.18 - Add MBID/Spotify Autolinking if track exists - Add Genre table + .go files diff --git a/go.mod b/go.mod index 903723b7..9669d030 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/gogo/protobuf v1.3.1 // indirect github.com/golang-migrate/migrate v3.5.4+incompatible github.com/golang/protobuf v1.4.3 // indirect + github.com/google/uuid v1.2.0 // indirect github.com/gorilla/mux v1.8.0 github.com/joho/godotenv v1.3.0 github.com/opencontainers/go-digest v1.0.0 // indirect diff --git a/go.sum b/go.sum index 430b4d2b..44e5ec60 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= diff --git a/init/goscrobble.service b/init/goscrobble.service index b6ba98ad..30578c8f 100644 --- a/init/goscrobble.service +++ b/init/goscrobble.service @@ -4,8 +4,8 @@ After=network.target [Service] Type=simple -User=www-data -ExecStart=/opt/goscrobble/goscrobble +User=root +ExecStart=/bin/bash -c 'cd /root/go-scrobble && ./goscrobble' Restart=on-failure [Install] diff --git a/internal/goscrobble/album.go b/internal/goscrobble/album.go index 038c5d00..31274988 100644 --- a/internal/goscrobble/album.go +++ b/internal/goscrobble/album.go @@ -3,17 +3,16 @@ package goscrobble import ( "database/sql" "errors" - "fmt" "log" ) type Album struct { - Uuid string `json:"uuid"` - Name string `json:"name"` - Desc sql.NullString `json:"desc"` - Img sql.NullString `json:"img"` - MusicBrainzID string `json:"mbid"` - SpotifyID string `json:"spotify_id"` + UUID string `json:"uuid"` + Name string `json:"name"` + Desc string `json:"desc"` + Img string `json:"img"` + MusicBrainzID string `json:"mbid"` + SpotifyID string `json:"spotify_id"` } // insertAlbum - This will return if it exists or create it based on MBID > Name @@ -22,32 +21,25 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, t // Try locate our album if mbid != "" { - album = fetchAlbum("mbid", mbid, tx) + album = getAlbumByCol("mbid", mbid, tx) } else if spotifyId != "" { - album = fetchAlbum("spotify_id", spotifyId, tx) + album = getAlbumByCol("spotify_id", spotifyId, tx) } // If it didn't match above, lookup by name - if album.Uuid == "" { - album = fetchAlbum("name", name, tx) + if album.UUID == "" { + album = getAlbumByCol("name", name, tx) } // If we can't find it. Lets add it! - if album.Uuid == "" { - err := insertNewAlbum(name, mbid, spotifyId, tx) + if album.UUID == "" { + err := insertNewAlbum(&album, name, mbid, spotifyId, tx) if err != nil { return album, errors.New("Failed to insert album") } - // Fetch the recently inserted album to get the UUID - if mbid != "" { - album = fetchAlbum("mbid", mbid, tx) - } else if spotifyId != "" { - album = fetchAlbum("spotify_id", spotifyId, tx) - } - - if album.Uuid == "" { - album = fetchAlbum("name", name, tx) + if album.UUID == "" { + return album, errors.New("Failed to fetch album") } // Try linkem up @@ -57,10 +49,7 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, t } } - if album.Uuid == "" { - return album, errors.New("Unable to fetch album!") - } - + // Updates these values if we match earlier! if album.MusicBrainzID != mbid { album.MusicBrainzID = mbid album.updateAlbum("mbid", mbid, tx) @@ -74,11 +63,11 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, t return album, nil } -func fetchAlbum(col string, val string, tx *sql.Tx) Album { +func getAlbumByCol(col string, val string, tx *sql.Tx) Album { var album Album err := tx.QueryRow( - "SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `albums` WHERE `"+col+"` = ?", - val).Scan(&album.Uuid, &album.Name, &album.Desc, &album.Img, &album.MusicBrainzID) + "SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`, ''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `albums` WHERE `"+col+"` = ?", + val).Scan(&album.UUID, &album.Name, &album.Desc, &album.Img, &album.MusicBrainzID, &album.SpotifyID) if err != nil { if err != sql.ErrNoRows { @@ -89,9 +78,14 @@ func fetchAlbum(col string, val string, tx *sql.Tx) Album { return album } -func insertNewAlbum(name string, mbid string, spotifyId string, tx *sql.Tx) error { +func insertNewAlbum(album *Album, name string, mbid string, spotifyId string, tx *sql.Tx) error { + album.UUID = newUUID() + album.Name = name + album.MusicBrainzID = mbid + album.SpotifyID = spotifyId + _, err := tx.Exec("INSERT INTO `albums` (`uuid`, `name`, `mbid`, `spotify_id`) "+ - "VALUES (UUID_TO_BIN(UUID(), true),?,?,?)", name, mbid, spotifyId) + "VALUES (UUID_TO_BIN(?, true),?,?,?)", album.UUID, album.Name, album.MusicBrainzID, album.SpotifyID) return err } @@ -100,9 +94,8 @@ func (album *Album) linkAlbumToArtists(artists []string, tx *sql.Tx) error { var err error for _, artist := range artists { _, err = tx.Exec("INSERT INTO `album_artist` (`album`, `artist`) "+ - "VALUES (UUID_TO_BIN(?, true), UUID_TO_BIN(?, true))", album.Uuid, artist) + "VALUES (UUID_TO_BIN(?, true), UUID_TO_BIN(?, true))", album.UUID, artist) if err != nil { - fmt.Println(err) return err } } @@ -111,7 +104,19 @@ func (album *Album) linkAlbumToArtists(artists []string, tx *sql.Tx) error { } func (album *Album) updateAlbum(col string, val string, tx *sql.Tx) error { - _, err := tx.Exec("UPDATE `albums` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, album.Uuid) + _, err := tx.Exec("UPDATE `albums` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, album.UUID) return err } + +func getAlbumByUUID(uuid string) (Album, error) { + var album Album + err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `albums` WHERE `uuid` = UUID_TO_BIN(?, true)", + uuid).Scan(&album.UUID, &album.Name, &album.Desc, &album.Img, &album.MusicBrainzID, &album.SpotifyID) + + if err != nil { + return album, errors.New("Invalid UUID") + } + + return album, nil +} diff --git a/internal/goscrobble/artist.go b/internal/goscrobble/artist.go index 5e4331e5..9349d60f 100644 --- a/internal/goscrobble/artist.go +++ b/internal/goscrobble/artist.go @@ -7,12 +7,12 @@ import ( ) type Artist struct { - Uuid string `json:"uuid"` - Name string `json:"name"` - Desc sql.NullString `json:"desc"` - Img sql.NullString `json:"img"` - MusicBrainzID string `json:"mbid"` - SpotifyID string `json:"spotify_id"` + UUID string `json:"uuid"` + Name string `json:"name"` + Desc string `json:"desc"` + Img string `json:"img"` + MusicBrainzID string `json:"mbid"` + SpotifyID string `json:"spotify_id"` } // insertArtist - This will return if it exists or create it based on MBID > Name @@ -21,58 +21,52 @@ func insertArtist(name string, mbid string, spotifyId string, tx *sql.Tx) (Artis // Try locate our artist if mbid != "" { - artist = fetchArtist("mbid", mbid, tx) + artist = getArtistByCol("mbid", mbid, tx) } else if spotifyId != "" { - artist = fetchArtist("spotify_id", spotifyId, tx) + artist = getArtistByCol("spotify_id", spotifyId, tx) } // If it didn't match above, lookup by name - if artist.Uuid == "" { - artist = fetchArtist("name", name, tx) + if artist.UUID == "" { + artist = getArtistByCol("name", name, tx) } // If we can't find it. Lets add it! - if artist.Uuid == "" { - err := insertNewArtist(name, mbid, spotifyId, tx) + if artist.UUID == "" { + err := insertNewArtist(&artist, name, mbid, spotifyId, tx) if err != nil { log.Printf("Error inserting artist: %+v", err) return artist, errors.New("Failed to insert artist") } + + if artist.UUID == "" { + return artist, errors.New("Unable to fetch artist!") + } } - // Fetch the recently inserted artist to get the UUID - if mbid != "" { - artist = fetchArtist("mbid", mbid, tx) - } else if spotifyId != "" { - artist = fetchArtist("spotify_id", spotifyId, tx) + // Updates these values if we match earlier!M + if artist.MusicBrainzID == "" { + if artist.MusicBrainzID != mbid { + artist.MusicBrainzID = mbid + artist.updateArtist("mbid", mbid, tx) + } } - if artist.Uuid == "" { - artist = fetchArtist("name", name, tx) - } - - if artist.Uuid == "" { - return artist, errors.New("Unable to fetch artist!") - } - - if artist.MusicBrainzID != mbid { - artist.MusicBrainzID = mbid - artist.updateArtist("mbid", mbid, tx) - } - - if artist.SpotifyID != spotifyId { - artist.SpotifyID = spotifyId - artist.updateArtist("spotify_id", spotifyId, tx) + if artist.SpotifyID == "" { + if artist.SpotifyID != spotifyId { + artist.SpotifyID = spotifyId + artist.updateArtist("spotify_id", spotifyId, tx) + } } return artist, nil } -func fetchArtist(col string, val string, tx *sql.Tx) Artist { +func getArtistByCol(col string, val string, tx *sql.Tx) Artist { var artist Artist err := tx.QueryRow( - "SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `artists` WHERE `"+col+"` = ?", - val).Scan(&artist.Uuid, &artist.Name, &artist.Desc, &artist.Img, &artist.MusicBrainzID) + "SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `artists` WHERE `"+col+"` = ?", + val).Scan(&artist.UUID, &artist.Name, &artist.Desc, &artist.Img, &artist.MusicBrainzID, &artist.SpotifyID) if err != nil { if err != sql.ErrNoRows { @@ -83,15 +77,32 @@ func fetchArtist(col string, val string, tx *sql.Tx) Artist { return artist } -func insertNewArtist(name string, mbid string, spotifyId string, tx *sql.Tx) error { +func insertNewArtist(artist *Artist, name string, mbid string, spotifyId string, tx *sql.Tx) error { + artist.UUID = newUUID() + artist.Name = name + artist.MusicBrainzID = mbid + artist.SpotifyID = spotifyId + _, err := tx.Exec("INSERT INTO `artists` (`uuid`, `name`, `mbid`, `spotify_id`) "+ - "VALUES (UUID_TO_BIN(UUID(), true),?,?,?)", name, mbid, spotifyId) + "VALUES (UUID_TO_BIN(?, true),?,?,?)", artist.UUID, artist.Name, artist.MusicBrainzID, artist.SpotifyID) return err } func (artist *Artist) updateArtist(col string, val string, tx *sql.Tx) error { - _, err := tx.Exec("UPDATE `artists` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, artist.Uuid) + _, err := tx.Exec("UPDATE `artists` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, artist.UUID) return err } + +func getArtistByUUID(uuid string) (Artist, error) { + var artist Artist + err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`, ''), IFNULL(`img`,''), `mbid`, `spotify_id` FROM `artists` WHERE `uuid` = UUID_TO_BIN(?, true)", + uuid).Scan(&artist.UUID, &artist.Name, &artist.Desc, &artist.Img, &artist.MusicBrainzID, &artist.SpotifyID) + + if err == sql.ErrNoRows { + return artist, errors.New("Invalid UUID") + } + + return artist, nil +} diff --git a/internal/goscrobble/genre.go b/internal/goscrobble/genre.go index 57468ec6..de265c93 100644 --- a/internal/goscrobble/genre.go +++ b/internal/goscrobble/genre.go @@ -10,7 +10,7 @@ type Genre struct { Name string `json:"name"` } -func getGenre(uuid string) Genre { +func getGenreByUUID(uuid string) Genre { var genre Genre err := db.QueryRow( "SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `artists` WHERE `uuid` = UUID_TO_BIN(?,true)", diff --git a/internal/goscrobble/ingress_jellyfin.go b/internal/goscrobble/ingress_jellyfin.go index 3b4fe2af..3121b4fd 100644 --- a/internal/goscrobble/ingress_jellyfin.go +++ b/internal/goscrobble/ingress_jellyfin.go @@ -3,7 +3,6 @@ package goscrobble import ( "database/sql" "errors" - "fmt" "log" "net" "time" @@ -80,7 +79,7 @@ func ParseJellyfinInput(userUUID string, jf JellyfinRequest, ip net.IP, tx *sql. } // Insert album if not exist - artists := []string{artist.Uuid} + artists := []string{artist.UUID} album, err := insertAlbum(jf.Album, jf.ProviderMusicbrainzalbum, "", artists, tx) if err != nil { log.Printf("%+v", err) @@ -89,7 +88,7 @@ func ParseJellyfinInput(userUUID string, jf JellyfinRequest, ip net.IP, tx *sql. // Insert track if not exist length := timestampToSeconds(jf.RunTime) - track, err := insertTrack(jf.Name, length, jf.ProviderMusicbrainztrack, "", album.Uuid, artists, tx) + track, err := insertTrack(jf.Name, length, jf.ProviderMusicbrainztrack, "", album.UUID, artists, tx) if err != nil { log.Printf("%+v", err) return errors.New("Failed to map track") @@ -97,8 +96,7 @@ func ParseJellyfinInput(userUUID string, jf JellyfinRequest, ip net.IP, tx *sql. // Insert scrobble if not exist timestamp := time.Now() - fmt.Println(timestamp) - err = insertScrobble(userUUID, track.Uuid, "jellyfin", timestamp, ip, tx) + err = insertScrobble(userUUID, track.UUID, "jellyfin", timestamp, ip, tx) if err != nil { log.Printf("%+v", err) return errors.New("Failed to map track") diff --git a/internal/goscrobble/ingress_multiscrobbler.go b/internal/goscrobble/ingress_multiscrobbler.go index e82a05bc..37720f87 100644 --- a/internal/goscrobble/ingress_multiscrobbler.go +++ b/internal/goscrobble/ingress_multiscrobbler.go @@ -37,7 +37,7 @@ func ParseMultiScrobblerInput(userUUID string, data MultiScrobblerRequest, ip ne log.Printf("%+v", err) return errors.New("Failed to map artist: " + artist.Name) } - artists = append(artists, artist.Uuid) + artists = append(artists, artist.UUID) } // Insert album if not exist @@ -48,14 +48,14 @@ func ParseMultiScrobblerInput(userUUID string, data MultiScrobblerRequest, ip ne } // Insert track if not exist - track, err := insertTrack(data.Track, data.Duration, "", "", album.Uuid, artists, tx) + track, err := insertTrack(data.Track, data.Duration, "", "", album.UUID, artists, tx) if err != nil { log.Printf("%+v", err) return errors.New("Failed to map track") } // Insert scrobble if not exist - err = insertScrobble(userUUID, track.Uuid, "multiscrobbler", data.PlayedAt, ip, tx) + err = insertScrobble(userUUID, track.UUID, "multiscrobbler", data.PlayedAt, ip, tx) if err != nil { log.Printf("%+v", err) return errors.New("Failed to map track") diff --git a/internal/goscrobble/ingress_spotify.go b/internal/goscrobble/ingress_spotify.go index 1410d0db..14c0f5d1 100644 --- a/internal/goscrobble/ingress_spotify.go +++ b/internal/goscrobble/ingress_spotify.go @@ -61,7 +61,6 @@ func connectSpotifyResponse(r *http.Request) error { auth := getSpotifyAuthHandler() token, err := auth.Token(userUuid, r) if err != nil { - fmt.Printf("%+v", err) return err } @@ -74,7 +73,6 @@ func connectSpotifyResponse(r *http.Request) error { time := time.Now().UTC().Add(-(time.Duration(30) * time.Minute)) err = insertOauthToken(userUuid, "spotify", token.AccessToken, token.RefreshToken, token.Expiry, spotifyUser.DisplayName, time) if err != nil { - fmt.Printf("%+v", err) return err } @@ -153,7 +151,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client log.Printf("%+v", err) return errors.New("Failed to map artist: " + artist.Name) } - artists = append(artists, artist.Uuid) + artists = append(artists, artist.UUID) } // Get full track data (album / track info) @@ -171,7 +169,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client log.Printf("%+v", err) return errors.New("Failed to map album: " + artist.Name) } - albumartists = append(albumartists, albumartist.Uuid) + albumartists = append(albumartists, albumartist.UUID) } // Insert album if not exist @@ -183,7 +181,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client // Insert track if not exist length := int(fulltrack.Duration / 1000) - track, err := insertTrack(fulltrack.Name, length, "", fulltrack.ID.String(), album.Uuid, artists, tx) + track, err := insertTrack(fulltrack.Name, length, "", fulltrack.ID.String(), album.UUID, artists, tx) if err != nil { log.Printf("%+v", err) return errors.New("Failed to map track") @@ -191,7 +189,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client // Insert scrobble if not exist ip := net.ParseIP("0.0.0.0") - err = insertScrobble(userUUID, track.Uuid, "spotify", data.PlayedAt, ip, tx) + err = insertScrobble(userUUID, track.UUID, "spotify", data.PlayedAt, ip, tx) if err != nil { log.Printf("%+v", err) return errors.New("Failed to map track") diff --git a/internal/goscrobble/profile.go b/internal/goscrobble/profile.go index 3cfc43f6..14fcfa3e 100644 --- a/internal/goscrobble/profile.go +++ b/internal/goscrobble/profile.go @@ -6,12 +6,12 @@ type ProfileResponse struct { Scrobbles []ScrobbleResponseItem `json:"scrobbles"` } -func getProfile(user User) (ProfileResponse, error) { +func getProfileForUser(user User) (ProfileResponse, error) { resp := ProfileResponse{ UUID: user.UUID, Username: user.Username, } - scrobbleReq, err := fetchScrobblesForUser(user.UUID, 10, 1) + scrobbleReq, err := getScrobblesForUser(user.UUID, 10, 1) if err != nil { return resp, err } diff --git a/internal/goscrobble/scrobble.go b/internal/goscrobble/scrobble.go index 13615a96..433bd0b3 100644 --- a/internal/goscrobble/scrobble.go +++ b/internal/goscrobble/scrobble.go @@ -48,7 +48,7 @@ func insertScrobble(user string, track string, source string, timestamp time.Tim return nil } -func fetchScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse, error) { +func getScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse, error) { scrobbleReq := ScrobbleResponse{} var count int @@ -106,7 +106,7 @@ func fetchScrobblesForUser(userUuid string, limit int, page int) (ScrobbleRespon func insertNewScrobble(user string, track string, source string, timestamp time.Time, ip net.IP, tx *sql.Tx) error { _, err := tx.Exec("INSERT INTO `scrobbles` (`uuid`, `created_at`, `created_ip`, `user`, `track`, `source`) "+ - "VALUES (UUID_TO_BIN(UUID(), true), ?, ?, UUID_TO_BIN(?, true), UUID_TO_BIN(?, true), ?)", timestamp, ip, user, track, source) + "VALUES (UUID_TO_BIN(?, true), ?, ?, UUID_TO_BIN(?, true), UUID_TO_BIN(?, true), ?)", newUUID(), timestamp, ip, user, track, source) return err } diff --git a/internal/goscrobble/server.go b/internal/goscrobble/server.go index c0bc1c9a..a4729fd5 100644 --- a/internal/goscrobble/server.go +++ b/internal/goscrobble/server.go @@ -37,25 +37,28 @@ func HandleRequests(port string) { v1.HandleFunc("/ingress/multiscrobbler", limitMiddleware(tokenMiddleware(handleIngress), lightLimiter)).Methods("POST") // JWT Auth - Own profile only (Uses uuid in JWT) - v1.HandleFunc("/user", limitMiddleware(jwtMiddleware(fetchUser), lightLimiter)).Methods("GET") + v1.HandleFunc("/user", limitMiddleware(jwtMiddleware(getUser), lightLimiter)).Methods("GET") v1.HandleFunc("/user", limitMiddleware(jwtMiddleware(patchUser), lightLimiter)).Methods("PATCH") v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(getSpotifyClientID), lightLimiter)).Methods("GET") v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(deleteSpotifyLink), lightLimiter)).Methods("DELETE") - v1.HandleFunc("/user/{uuid}/scrobbles", jwtMiddleware(fetchScrobbleResponse)).Methods("GET") + v1.HandleFunc("/user/{uuid}/scrobbles", jwtMiddleware(getScrobbles)).Methods("GET") // Config auth - v1.HandleFunc("/config", limitMiddleware(adminMiddleware(fetchConfig), standardLimiter)).Methods("GET") + v1.HandleFunc("/config", limitMiddleware(adminMiddleware(getConfig), standardLimiter)).Methods("GET") v1.HandleFunc("/config", limitMiddleware(adminMiddleware(postConfig), standardLimiter)).Methods("POST") // No Auth v1.HandleFunc("/stats", limitMiddleware(handleStats, lightLimiter)).Methods("GET") - v1.HandleFunc("/profile/{username}", limitMiddleware(fetchProfile, lightLimiter)).Methods("GET") + v1.HandleFunc("/profile/{username}", limitMiddleware(getProfile, lightLimiter)).Methods("GET") + v1.HandleFunc("/artist/{uuid}", limitMiddleware(getArtist, lightLimiter)).Methods("GET") + v1.HandleFunc("/album/{uuid}", limitMiddleware(getAlbum, lightLimiter)).Methods("GET") + v1.HandleFunc("/track/{uuid}", limitMiddleware(getTrack, lightLimiter)).Methods("GET") v1.HandleFunc("/register", limitMiddleware(handleRegister, heavyLimiter)).Methods("POST") v1.HandleFunc("/login", limitMiddleware(handleLogin, standardLimiter)).Methods("POST") v1.HandleFunc("/sendreset", limitMiddleware(handleSendReset, heavyLimiter)).Methods("POST") v1.HandleFunc("/resetpassword", limitMiddleware(handleResetPassword, heavyLimiter)).Methods("POST") - v1.HandleFunc("/serverinfo", fetchServerInfo).Methods("GET") + v1.HandleFunc("/serverinfo", getServerInfo).Methods("GET") // Redirect from Spotify Oauth v1.HandleFunc("/link/spotify", limitMiddleware(postSpotifyReponse, lightLimiter)) @@ -289,10 +292,10 @@ func handleIngress(w http.ResponseWriter, r *http.Request, userUuid string) { return } -// fetchUser - Return personal userprofile -func fetchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) { +// getUser - Return personal userprofile +func getUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) { // We don't this var most of the time - userFull, err := getUser(jwtUser) + userFull, err := getUserByUUID(jwtUser) if err != nil { throwOkError(w, "Failed to fetch user information") return @@ -322,7 +325,7 @@ func fetchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser s // patchUser - Update specific values func patchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) { - userFull, err := getUser(jwtUser) + userFull, err := getUserByUUID(jwtUser) if err != nil { throwOkError(w, "Failed to fetch user information") return @@ -346,9 +349,9 @@ func patchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser s throwOkMessage(w, "User updated successfully") } -// fetchScrobbles - Return an array of scrobbles -func fetchScrobbleResponse(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) { - resp, err := fetchScrobblesForUser(reqUser, 100, 1) +// getScrobbles - Return an array of scrobbles +func getScrobbles(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) { + resp, err := getScrobblesForUser(reqUser, 100, 1) if err != nil { throwOkError(w, "Failed to fetch scrobbles") return @@ -360,8 +363,8 @@ func fetchScrobbleResponse(w http.ResponseWriter, r *http.Request, jwtUser strin w.Write(json) } -// fetchScrobbles - Return an array of scrobbles -func fetchConfig(w http.ResponseWriter, r *http.Request, jwtUser string) { +// getConfig - Return an array of scrobbles +func getConfig(w http.ResponseWriter, r *http.Request, jwtUser string) { config, err := getAllConfigs() if err != nil { throwOkError(w, "Failed to fetch scrobbles") @@ -373,7 +376,7 @@ func fetchConfig(w http.ResponseWriter, r *http.Request, jwtUser string) { w.Write(json) } -// fetchScrobbles - Return an array of scrobbles +// postConfig - Return an array of scrobbles func postConfig(w http.ResponseWriter, r *http.Request, jwtUser string) { bodyJson, err := decodeJson(r.Body) if err != nil { @@ -394,8 +397,8 @@ func postConfig(w http.ResponseWriter, r *http.Request, jwtUser string) { throwOkMessage(w, "Config updated successfully") } -// fetchProfile - Returns public user profile data -func fetchProfile(w http.ResponseWriter, r *http.Request) { +// getProfile - Returns public user profile data +func getProfile(w http.ResponseWriter, r *http.Request) { var username string for k, v := range mux.Vars(r) { if k == "username" { @@ -414,7 +417,7 @@ func fetchProfile(w http.ResponseWriter, r *http.Request) { return } - resp, err := getProfile(user) + resp, err := getProfileForUser(user) if err != nil { throwOkError(w, err.Error()) return @@ -425,6 +428,81 @@ func fetchProfile(w http.ResponseWriter, r *http.Request) { w.Write(json) } +// getArtist - Returns artist data +func getArtist(w http.ResponseWriter, r *http.Request) { + var uuid string + for k, v := range mux.Vars(r) { + if k == "uuid" { + uuid = v + } + } + + if uuid == "" { + throwOkError(w, "Invalid UUID") + return + } + + artist, err := getArtistByUUID(uuid) + if err != nil { + throwOkError(w, err.Error()) + return + } + + json, _ := json.Marshal(&artist) + w.WriteHeader(http.StatusOK) + w.Write(json) +} + +// getAlbum - Returns album data +func getAlbum(w http.ResponseWriter, r *http.Request) { + var uuid string + for k, v := range mux.Vars(r) { + if k == "uuid" { + uuid = v + } + } + + if uuid == "" { + throwOkError(w, "Invalid UUID") + return + } + + album, err := getAlbumByUUID(uuid) + if err != nil { + throwOkError(w, err.Error()) + return + } + + json, _ := json.Marshal(&album) + w.WriteHeader(http.StatusOK) + w.Write(json) +} + +// getTrack - Returns track data +func getTrack(w http.ResponseWriter, r *http.Request) { + var uuid string + for k, v := range mux.Vars(r) { + if k == "uuid" { + uuid = v + } + } + + if uuid == "" { + throwOkError(w, "Invalid UUID") + return + } + + track, err := getTrackByUUID(uuid) + if err != nil { + throwOkError(w, err.Error()) + return + } + + json, _ := json.Marshal(&track) + w.WriteHeader(http.StatusOK) + w.Write(json) +} + // postSpotifyResponse - Oauth Response from Spotify func postSpotifyReponse(w http.ResponseWriter, r *http.Request) { err := connectSpotifyResponse(r) @@ -466,7 +544,7 @@ func deleteSpotifyLink(w http.ResponseWriter, r *http.Request, u string, v strin throwOkMessage(w, "Spotify account successfully unlinked") } -func fetchServerInfo(w http.ResponseWriter, r *http.Request) { +func getServerInfo(w http.ResponseWriter, r *http.Request) { cachedRegistrationEnabled := getRedisVal("REGISTRATION_ENABLED") if cachedRegistrationEnabled == "" { registrationEnabled, err := getConfigValue("REGISTRATION_ENABLED") @@ -478,7 +556,7 @@ func fetchServerInfo(w http.ResponseWriter, r *http.Request) { } info := ServerInfo{ - Version: "0.0.18", + Version: "0.0.19", RegistrationEnabled: cachedRegistrationEnabled, } diff --git a/internal/goscrobble/server_middleware.go b/internal/goscrobble/server_middleware.go index df4f5800..9fea0031 100644 --- a/internal/goscrobble/server_middleware.go +++ b/internal/goscrobble/server_middleware.go @@ -77,7 +77,7 @@ func adminMiddleware(next func(http.ResponseWriter, *http.Request, string)) http return } - user, err := getUser(claims.Subject) + user, err := getUserByUUID(claims.Subject) if err != nil { throwUnauthorized(w, err.Error()) return diff --git a/internal/goscrobble/stats.go b/internal/goscrobble/stats.go index a4e3a287..2e4dd237 100644 --- a/internal/goscrobble/stats.go +++ b/internal/goscrobble/stats.go @@ -34,7 +34,7 @@ func getStats() (StatsRequest, error) { } } else { // If not cached, pull data then return - statsReq, err = fetchStats() + statsReq, err = getAllStats() if err != nil { log.Printf("Error fetching stats: %+v", err) return statsReq, errors.New("Error fetching stats") @@ -46,10 +46,10 @@ func getStats() (StatsRequest, error) { // goFetchStats - Async call func goFetchStats() { - _, _ = fetchStats() + _, _ = getAllStats() } -func fetchStats() (StatsRequest, error) { +func getAllStats() (StatsRequest, error) { statsReq := StatsRequest{} var err error diff --git a/internal/goscrobble/track.go b/internal/goscrobble/track.go index 1b7ce44b..a2d9d439 100644 --- a/internal/goscrobble/track.go +++ b/internal/goscrobble/track.go @@ -3,19 +3,18 @@ package goscrobble import ( "database/sql" "errors" - "fmt" "log" "strings" ) type Track struct { - Uuid string `json:"uuid"` - Name string `json:"name"` - Length int `json:"length"` - Desc sql.NullString `json:"desc"` - Img sql.NullString `json:"img"` - MusicBrainzID string `json:"mbid"` - SpotifyID string `json:"spotify_id"` + UUID string `json:"uuid"` + Name string `json:"name"` + Length int `json:"length"` + Desc string `json:"desc"` + Img string `json:"img"` + MusicBrainzID string `json:"mbid"` + SpotifyID string `json:"spotify_id"` } // insertTrack - This will return if it exists or create it based on MBID > Name @@ -24,35 +23,26 @@ func insertTrack(name string, legnth int, mbid string, spotifyId string, album s // Try locate our track if mbid != "" { - track = fetchTrack("mbid", mbid, tx) - fmt.Printf("Fetech mbid: %s", mbid) + track = getTrackByCol("mbid", mbid, tx) } else if spotifyId != "" { - track = fetchTrack("spotify_id", spotifyId, tx) - fmt.Printf("Fetech spotify: %s", spotifyId) + track = getTrackByCol("spotify_id", spotifyId, tx) } // If it didn't match above, lookup by name - if track.Uuid == "" { - // TODO: add artist check here too - track = fetchTrackWithArtists(name, artists, album, tx) + if track.UUID == "" { + track = getTrackWithArtists(name, artists, album, tx) } // If we can't find it. Lets add it! - if track.Uuid == "" { - err := insertNewTrack(name, legnth, mbid, spotifyId, tx) + if track.UUID == "" { + err := insertNewTrack(&track, name, legnth, mbid, spotifyId, tx) + if err != nil { return track, errors.New("Failed to insert track") } - // Fetch the recently inserted track to get the UUID - if mbid != "" { - track = fetchTrack("mbid", mbid, tx) - } else if spotifyId != "" { - track = fetchTrack("spotify_id", spotifyId, tx) - } - - if track.Uuid == "" { - track = fetchTrackWithArtists(name, artists, album, tx) + if track.UUID == "" { + return track, errors.New("Unable to fetch track!") } err = track.linkTrack(album, artists, tx) @@ -61,10 +51,7 @@ func insertTrack(name string, legnth int, mbid string, spotifyId string, album s } } - if track.Uuid == "" { - return track, errors.New("Unable to fetch track!") - } - + // Updates these values if we match earlier! if track.MusicBrainzID != mbid { track.MusicBrainzID = mbid track.updateTrack("mbid", mbid, tx) @@ -78,11 +65,11 @@ func insertTrack(name string, legnth int, mbid string, spotifyId string, album s return track, nil } -func fetchTrack(col string, val string, tx *sql.Tx) Track { +func getTrackByCol(col string, val string, tx *sql.Tx) Track { var track Track err := tx.QueryRow( - "SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `tracks` WHERE `"+col+"` = ? LIMIT 1", - val).Scan(&track.Uuid, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID) + "SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid` FROM `tracks` WHERE `"+col+"` = ? LIMIT 1", + val).Scan(&track.UUID, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID) if err != nil { if err != sql.ErrNoRows { @@ -93,16 +80,16 @@ func fetchTrack(col string, val string, tx *sql.Tx) Track { return track } -func fetchTrackWithArtists(name string, artists []string, album string, tx *sql.Tx) Track { +func getTrackWithArtists(name string, artists []string, album string, tx *sql.Tx) Track { var track Track artistString := strings.Join(artists, "','") err := tx.QueryRow( - "SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `tracks` "+ + "SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `mbid` FROM `tracks` "+ "LEFT JOIN `track_artist` ON `tracks`.`uuid` = `track_artist`.`track` "+ "LEFT JOIN `track_album` ON `tracks`.`uuid` = `track_album`.`track` "+ "WHERE `name` = ? AND BIN_TO_UUID(`track_artist`.`artist`, true) IN ('"+artistString+"') "+ "AND BIN_TO_UUID(`track_album`.`album`,true) = ? LIMIT 1", - name, album).Scan(&track.Uuid, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID) + name, album).Scan(&track.UUID, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID) if err != nil { if err != sql.ErrNoRows { @@ -113,9 +100,15 @@ func fetchTrackWithArtists(name string, artists []string, album string, tx *sql. return track } -func insertNewTrack(name string, length int, mbid string, spotifyId string, tx *sql.Tx) error { +func insertNewTrack(track *Track, name string, length int, mbid string, spotifyId string, tx *sql.Tx) error { + track.UUID = newUUID() + track.Name = name + track.Length = length + track.MusicBrainzID = mbid + track.SpotifyID = spotifyId + _, err := tx.Exec("INSERT INTO `tracks` (`uuid`, `name`, `length`, `mbid`, `spotify_id`) "+ - "VALUES (UUID_TO_BIN(UUID(), true),?,?,?,?)", name, length, mbid, spotifyId) + "VALUES (UUID_TO_BIN(?, true),?,?,?,?)", track.UUID, track.Name, track.Length, track.MusicBrainzID, track.SpotifyID) return err } @@ -126,24 +119,26 @@ func (track *Track) linkTrack(album string, artists []string, tx *sql.Tx) error return err } err = track.linkTrackToArtists(artists, tx) + if err != nil { return err } + return nil } -func (track Track) linkTrackToAlbum(albumUuid string, tx *sql.Tx) error { +func (track *Track) linkTrackToAlbum(albumUuid string, tx *sql.Tx) error { _, err := tx.Exec("INSERT INTO `track_album` (`track`, `album`) "+ - "VALUES (UUID_TO_BIN(?, true), UUID_TO_BIN(?, true))", track.Uuid, albumUuid) + "VALUES (UUID_TO_BIN(?, true), UUID_TO_BIN(?, true))", track.UUID, albumUuid) return err } -func (track Track) linkTrackToArtists(artists []string, tx *sql.Tx) error { +func (track *Track) linkTrackToArtists(artists []string, tx *sql.Tx) error { var err error for _, artist := range artists { _, err = tx.Exec("INSERT INTO `track_artist` (`track`, `artist`) "+ - "VALUES (UUID_TO_BIN(?, true),UUID_TO_BIN(?, true))", track.Uuid, artist) + "VALUES (UUID_TO_BIN(?, true),UUID_TO_BIN(?, true))", track.UUID, artist) if err != nil { return err } @@ -153,7 +148,19 @@ func (track Track) linkTrackToArtists(artists []string, tx *sql.Tx) error { } func (track *Track) updateTrack(col string, val string, tx *sql.Tx) error { - _, err := tx.Exec("UPDATE `tracks` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, track.Uuid) + _, err := tx.Exec("UPDATE `tracks` SET `"+col+"` = ? WHERE `uuid` = UUID_TO_BIN(?,true)", val, track.UUID) return err } + +func getTrackByUUID(uuid string) (Track, error) { + var track Track + err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `name`, IFNULL(`desc`,''), IFNULL(`img`,''), `length`, `mbid`, `spotify_id` FROM `tracks` WHERE `uuid` = UUID_TO_BIN(?, true)", + uuid).Scan(&track.UUID, &track.Name, &track.Desc, &track.Img, &track.Length, &track.MusicBrainzID, &track.SpotifyID) + + if err != nil { + return track, errors.New("Invalid UUID") + } + + return track, nil +} diff --git a/internal/goscrobble/user.go b/internal/goscrobble/user.go index 5c7ec814..e35605f1 100644 --- a/internal/goscrobble/user.go +++ b/internal/goscrobble/user.go @@ -211,7 +211,7 @@ func userAlreadyExists(req *RegisterRequest) bool { return count > 0 } -func getUser(uuid string) (User, error) { +func getUserByUUID(uuid string) (User, error) { var user User err := db.QueryRow("SELECT BIN_TO_UUID(`uuid`, true), `created_at`, `created_ip`, `modified_at`, `modified_ip`, `username`, `email`, `password`, `verified`, `admin`, `timezone`, `token` FROM `users` WHERE `uuid` = UUID_TO_BIN(?, true) AND `active` = 1", uuid).Scan(&user.UUID, &user.CreatedAt, &user.CreatedIp, &user.ModifiedAt, &user.ModifiedIP, &user.Username, &user.Email, &user.Password, &user.Verified, &user.Admin, &user.Timezone, &user.Token) diff --git a/internal/goscrobble/utils.go b/internal/goscrobble/utils.go index 54e050ac..e9949fc1 100644 --- a/internal/goscrobble/utils.go +++ b/internal/goscrobble/utils.go @@ -12,6 +12,8 @@ import ( "regexp" "strings" "time" + + "github.com/google/uuid" ) var emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") @@ -147,7 +149,6 @@ func filterSlice(s []string) []string { result = append(result, item) } - fmt.Printf("RESTULS: %+v", result) return result } @@ -160,3 +161,7 @@ func getMd5(val string) string { hash := md5.Sum([]byte(val)) return hex.EncodeToString(hash[:]) } + +func newUUID() string { + return uuid.New().String() +} diff --git a/web/src/Api/index.js b/web/src/Api/index.js index e2cd6455..22753ad8 100644 --- a/web/src/Api/index.js +++ b/web/src/Api/index.js @@ -11,6 +11,9 @@ function getHeaders() { if (user.exp < unixtime) { // TODO: Handle expiry nicer toast.warning("Session expired. Please log in again") + // localStorage.removeItem('user'); + // window.location.reload(); + return {}; } return { Authorization: 'Bearer ' + user.jwt }; @@ -252,3 +255,30 @@ export const getServerInfo = () => { return handleErrorResp(error) }); } + +export const getArtist = (uuid) => { + return axios.get(process.env.REACT_APP_API_URL + "artist/" + uuid).then( + (data) => { + return data.data; + }).catch((error) => { + return handleErrorResp(error) + }); +}; + +export const getAlbum = (uuid) => { + return axios.get(process.env.REACT_APP_API_URL + "album/" + uuid).then( + (data) => { + return data.data; + }).catch((error) => { + return handleErrorResp(error) + }); +}; + +export const getTrack = (uuid) => { + return axios.get(process.env.REACT_APP_API_URL + "track/" + uuid).then( + (data) => { + return data.data; + }).catch((error) => { + return handleErrorResp(error) + }); +}; diff --git a/web/src/Components/Navigation.js b/web/src/Components/Navigation.js index e625b218..0d266d15 100644 --- a/web/src/Components/Navigation.js +++ b/web/src/Components/Navigation.js @@ -13,7 +13,7 @@ const menuItems = [ const loggedInMenuItems = [ 'Dashboard', - 'About', + 'Docs', ] const isMobile = () => { diff --git a/web/src/Pages/About.css b/web/src/Pages/About.css index e69de29b..8b137891 100644 --- a/web/src/Pages/About.css +++ b/web/src/Pages/About.css @@ -0,0 +1 @@ + diff --git a/web/src/Pages/Album.js b/web/src/Pages/Album.js index 5a937210..1de56645 100644 --- a/web/src/Pages/Album.js +++ b/web/src/Pages/Album.js @@ -2,31 +2,30 @@ import React, { useState, useEffect } from 'react'; import '../App.css'; import './Album.css'; import ScaleLoader from 'react-spinners/ScaleLoader'; -import ScrobbleTable from '../Components/ScrobbleTable' +import { getAlbum } from '../Api/index' const Album = (route) => { const [loading, setLoading] = useState(true); - const [profile, setProfile] = useState({}); + const [album, setAlbum] = useState({}); - let album = false; + let albumUUID = false; if (route && route.match && route.match.params && route.match.params.uuid) { - album = route.match.params.uuid; + albumUUID = route.match.params.uuid; } else { - album = false; + albumUUID = false; } useEffect(() => { - if (!album) { + if (!albumUUID) { return false; } - // getProfile(username) - // .then(data => { - // setProfile(data); - // console.log(data) - // setLoading(false); - // }) - }, [album]) + getAlbum(albumUUID) + .then(data => { + setAlbum(data); + setLoading(false); + }) + }, [albumUUID]) if (loading) { return ( @@ -36,7 +35,7 @@ const Album = (route) => { ) } - if (!album || !album) { + if (!albumUUID || !album) { return (
Unable to fetch user @@ -47,10 +46,11 @@ const Album = (route) => { return (

- {album} + {album.name}

- Album + MusicBrainzId: {album.mbid}
+ SpotifyID: {album.spotify_id}
); diff --git a/web/src/Pages/Artist.js b/web/src/Pages/Artist.js index f8cd60a1..1d54eb53 100644 --- a/web/src/Pages/Artist.js +++ b/web/src/Pages/Artist.js @@ -2,31 +2,30 @@ import React, { useState, useEffect } from 'react'; import '../App.css'; import './Artist.css'; import ScaleLoader from 'react-spinners/ScaleLoader'; -import ScrobbleTable from '../Components/ScrobbleTable' +import { getArtist } from '../Api/index' const Artist = (route) => { const [loading, setLoading] = useState(true); - const [profile, setProfile] = useState({}); + const [artist, setArtist] = useState({}); - let artist = false; + let artistUUID = false; if (route && route.match && route.match.params && route.match.params.uuid) { - artist = route.match.params.uuid; + artistUUID = route.match.params.uuid; } else { - artist = false; + artistUUID = false; } useEffect(() => { - if (!artist) { + if (!artistUUID) { return false; } - // getProfile(username) - // .then(data => { - // setProfile(data); - // console.log(data) - // setLoading(false); - // }) - }, [artist]) + getArtist(artistUUID) + .then(data => { + setArtist(data); + setLoading(false); + }) + }, [artistUUID]) if (loading) { return ( @@ -36,7 +35,7 @@ const Artist = (route) => { ) } - if (!artist || !artist) { + if (!artistUUID || !artist) { return (
Unable to fetch user @@ -47,10 +46,11 @@ const Artist = (route) => { return (

- {artist} + {artist.name}

- Artist + MusicBrainzId: {artist.mbid}
+ SpotifyID: {artist.spotify_id}
); diff --git a/web/src/Pages/Docs.css b/web/src/Pages/Docs.css new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/web/src/Pages/Docs.css @@ -0,0 +1 @@ + diff --git a/web/src/Pages/Docs.js b/web/src/Pages/Docs.js new file mode 100644 index 00000000..b55b30fb --- /dev/null +++ b/web/src/Pages/Docs.js @@ -0,0 +1,25 @@ +import '../App.css'; +import './Docs.css'; + +const Docs = () => { + return ( +
+

+ Documentation +

+

+ Go-Scrobble is an open source music scorbbling service written in Go and React.
+ Used to track your listening history and build a profile to discover new music. +

+ gitlab.com/idanoo/go-scrobble + +
+ ); +} + +export default Docs; diff --git a/web/src/Pages/Track.js b/web/src/Pages/Track.js index c992cb4e..1e46b613 100644 --- a/web/src/Pages/Track.js +++ b/web/src/Pages/Track.js @@ -2,31 +2,30 @@ import React, { useState, useEffect } from 'react'; import '../App.css'; import './Track.css'; import ScaleLoader from 'react-spinners/ScaleLoader'; -import ScrobbleTable from '../Components/ScrobbleTable' +import { getTrack } from '../Api/index' const Track = (route) => { const [loading, setLoading] = useState(true); - const [profile, setProfile] = useState({}); + const [track, setTrack] = useState({}); - let artist = false; + let trackUUID = false; if (route && route.match && route.match.params && route.match.params.uuid) { - artist = route.match.params.uuid; + trackUUID = route.match.params.uuid; } else { - artist = false; + trackUUID = false; } useEffect(() => { - if (!artist) { + if (!trackUUID) { return false; } - // getProfile(username) - // .then(data => { - // setProfile(data); - // console.log(data) - // setLoading(false); - // }) - }, [artist]) + getTrack(trackUUID) + .then(data => { + setTrack(data); + setLoading(false); + }) + }, [trackUUID]) if (loading) { return ( @@ -36,7 +35,7 @@ const Track = (route) => { ) } - if (!artist || !artist) { + if (!trackUUID || !track) { return (
Unable to fetch user @@ -44,13 +43,21 @@ const Track = (route) => { ) } + let length = "0"; + if (track.length !== '') { + length = new Date(track.length * 1000).toISOString().substr(11, 8) + } + + return (

- {artist} + {track.name}

- Artist + MusicBrainzId: {track.mbid}
+ SpotifyID: {track.spotify_id}
+ Track Length: {length}
); diff --git a/web/src/Pages/User.js b/web/src/Pages/User.js index 8a35dda3..973b0995 100644 --- a/web/src/Pages/User.js +++ b/web/src/Pages/User.js @@ -8,7 +8,7 @@ import { getUser, patchUser } from '../Api/index' import { Button } from 'reactstrap'; import { confirmAlert } from 'react-confirm-alert'; import 'react-confirm-alert/src/react-confirm-alert.css'; -import { spotifyConnectionRequest, spotifyDisonnectionRequest, resetScrobbleToken } from '../Api/index' +import { spotifyConnectionRequest, spotifyDisonnectionRequest } from '../Api/index' import TimezoneSelect from 'react-timezone-select' const User = () => {