mirror of
https://github.com/idanoo/GoScrobble.git
synced 2024-11-25 01:45:15 +00:00
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!
This commit is contained in:
parent
1c865a6784
commit
99f9e7cfb3
@ -3,7 +3,7 @@ stages:
|
|||||||
- bundle
|
- bundle
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
VERSION: 0.0.18
|
VERSION: 0.0.19
|
||||||
|
|
||||||
build-go:
|
build-go:
|
||||||
image: golang:1.16.2
|
image: golang:1.16.2
|
||||||
|
@ -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
|
# 0.0.18
|
||||||
- Add MBID/Spotify Autolinking if track exists
|
- Add MBID/Spotify Autolinking if track exists
|
||||||
- Add Genre table + .go files
|
- Add Genre table + .go files
|
||||||
|
1
go.mod
1
go.mod
@ -15,6 +15,7 @@ require (
|
|||||||
github.com/gogo/protobuf v1.3.1 // indirect
|
github.com/gogo/protobuf v1.3.1 // indirect
|
||||||
github.com/golang-migrate/migrate v3.5.4+incompatible
|
github.com/golang-migrate/migrate v3.5.4+incompatible
|
||||||
github.com/golang/protobuf v1.4.3 // indirect
|
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/gorilla/mux v1.8.0
|
||||||
github.com/joho/godotenv v1.3.0
|
github.com/joho/godotenv v1.3.0
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
2
go.sum
2
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 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
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.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 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
@ -4,8 +4,8 @@ After=network.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=www-data
|
User=root
|
||||||
ExecStart=/opt/goscrobble/goscrobble
|
ExecStart=/bin/bash -c 'cd /root/go-scrobble && ./goscrobble'
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
@ -3,15 +3,14 @@ package goscrobble
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Album struct {
|
type Album struct {
|
||||||
Uuid string `json:"uuid"`
|
UUID string `json:"uuid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Desc sql.NullString `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Img sql.NullString `json:"img"`
|
Img string `json:"img"`
|
||||||
MusicBrainzID string `json:"mbid"`
|
MusicBrainzID string `json:"mbid"`
|
||||||
SpotifyID string `json:"spotify_id"`
|
SpotifyID string `json:"spotify_id"`
|
||||||
}
|
}
|
||||||
@ -22,32 +21,25 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, t
|
|||||||
|
|
||||||
// Try locate our album
|
// Try locate our album
|
||||||
if mbid != "" {
|
if mbid != "" {
|
||||||
album = fetchAlbum("mbid", mbid, tx)
|
album = getAlbumByCol("mbid", mbid, tx)
|
||||||
} else if spotifyId != "" {
|
} 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 it didn't match above, lookup by name
|
||||||
if album.Uuid == "" {
|
if album.UUID == "" {
|
||||||
album = fetchAlbum("name", name, tx)
|
album = getAlbumByCol("name", name, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can't find it. Lets add it!
|
// If we can't find it. Lets add it!
|
||||||
if album.Uuid == "" {
|
if album.UUID == "" {
|
||||||
err := insertNewAlbum(name, mbid, spotifyId, tx)
|
err := insertNewAlbum(&album, name, mbid, spotifyId, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return album, errors.New("Failed to insert album")
|
return album, errors.New("Failed to insert album")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the recently inserted album to get the UUID
|
if album.UUID == "" {
|
||||||
if mbid != "" {
|
return album, errors.New("Failed to fetch album")
|
||||||
album = fetchAlbum("mbid", mbid, tx)
|
|
||||||
} else if spotifyId != "" {
|
|
||||||
album = fetchAlbum("spotify_id", spotifyId, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if album.Uuid == "" {
|
|
||||||
album = fetchAlbum("name", name, tx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try linkem up
|
// Try linkem up
|
||||||
@ -57,10 +49,7 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if album.Uuid == "" {
|
// Updates these values if we match earlier!
|
||||||
return album, errors.New("Unable to fetch album!")
|
|
||||||
}
|
|
||||||
|
|
||||||
if album.MusicBrainzID != mbid {
|
if album.MusicBrainzID != mbid {
|
||||||
album.MusicBrainzID = mbid
|
album.MusicBrainzID = mbid
|
||||||
album.updateAlbum("mbid", mbid, tx)
|
album.updateAlbum("mbid", mbid, tx)
|
||||||
@ -74,11 +63,11 @@ func insertAlbum(name string, mbid string, spotifyId string, artists []string, t
|
|||||||
return album, nil
|
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
|
var album Album
|
||||||
err := tx.QueryRow(
|
err := tx.QueryRow(
|
||||||
"SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `albums` WHERE `"+col+"` = ?",
|
"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)
|
val).Scan(&album.UUID, &album.Name, &album.Desc, &album.Img, &album.MusicBrainzID, &album.SpotifyID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
@ -89,9 +78,14 @@ func fetchAlbum(col string, val string, tx *sql.Tx) Album {
|
|||||||
return 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`) "+
|
_, 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
|
return err
|
||||||
}
|
}
|
||||||
@ -100,9 +94,8 @@ func (album *Album) linkAlbumToArtists(artists []string, tx *sql.Tx) error {
|
|||||||
var err error
|
var err error
|
||||||
for _, artist := range artists {
|
for _, artist := range artists {
|
||||||
_, err = tx.Exec("INSERT INTO `album_artist` (`album`, `artist`) "+
|
_, 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 {
|
if err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return 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 {
|
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
|
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
|
||||||
|
}
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Artist struct {
|
type Artist struct {
|
||||||
Uuid string `json:"uuid"`
|
UUID string `json:"uuid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Desc sql.NullString `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Img sql.NullString `json:"img"`
|
Img string `json:"img"`
|
||||||
MusicBrainzID string `json:"mbid"`
|
MusicBrainzID string `json:"mbid"`
|
||||||
SpotifyID string `json:"spotify_id"`
|
SpotifyID string `json:"spotify_id"`
|
||||||
}
|
}
|
||||||
@ -21,58 +21,52 @@ func insertArtist(name string, mbid string, spotifyId string, tx *sql.Tx) (Artis
|
|||||||
|
|
||||||
// Try locate our artist
|
// Try locate our artist
|
||||||
if mbid != "" {
|
if mbid != "" {
|
||||||
artist = fetchArtist("mbid", mbid, tx)
|
artist = getArtistByCol("mbid", mbid, tx)
|
||||||
} else if spotifyId != "" {
|
} 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 it didn't match above, lookup by name
|
||||||
if artist.Uuid == "" {
|
if artist.UUID == "" {
|
||||||
artist = fetchArtist("name", name, tx)
|
artist = getArtistByCol("name", name, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can't find it. Lets add it!
|
// If we can't find it. Lets add it!
|
||||||
if artist.Uuid == "" {
|
if artist.UUID == "" {
|
||||||
err := insertNewArtist(name, mbid, spotifyId, tx)
|
err := insertNewArtist(&artist, name, mbid, spotifyId, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error inserting artist: %+v", err)
|
log.Printf("Error inserting artist: %+v", err)
|
||||||
return artist, errors.New("Failed to insert artist")
|
return artist, errors.New("Failed to insert artist")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the recently inserted artist to get the UUID
|
if artist.UUID == "" {
|
||||||
if mbid != "" {
|
|
||||||
artist = fetchArtist("mbid", mbid, tx)
|
|
||||||
} else if spotifyId != "" {
|
|
||||||
artist = fetchArtist("spotify_id", spotifyId, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if artist.Uuid == "" {
|
|
||||||
artist = fetchArtist("name", name, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if artist.Uuid == "" {
|
|
||||||
return artist, errors.New("Unable to fetch artist!")
|
return artist, errors.New("Unable to fetch artist!")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates these values if we match earlier!M
|
||||||
|
if artist.MusicBrainzID == "" {
|
||||||
if artist.MusicBrainzID != mbid {
|
if artist.MusicBrainzID != mbid {
|
||||||
artist.MusicBrainzID = mbid
|
artist.MusicBrainzID = mbid
|
||||||
artist.updateArtist("mbid", mbid, tx)
|
artist.updateArtist("mbid", mbid, tx)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if artist.SpotifyID == "" {
|
||||||
if artist.SpotifyID != spotifyId {
|
if artist.SpotifyID != spotifyId {
|
||||||
artist.SpotifyID = spotifyId
|
artist.SpotifyID = spotifyId
|
||||||
artist.updateArtist("spotify_id", spotifyId, tx)
|
artist.updateArtist("spotify_id", spotifyId, tx)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return artist, nil
|
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
|
var artist Artist
|
||||||
err := tx.QueryRow(
|
err := tx.QueryRow(
|
||||||
"SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `artists` WHERE `"+col+"` = ?",
|
"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)
|
val).Scan(&artist.UUID, &artist.Name, &artist.Desc, &artist.Img, &artist.MusicBrainzID, &artist.SpotifyID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
@ -83,15 +77,32 @@ func fetchArtist(col string, val string, tx *sql.Tx) Artist {
|
|||||||
return 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`) "+
|
_, 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (artist *Artist) updateArtist(col string, val string, tx *sql.Tx) error {
|
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
|
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
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ type Genre struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGenre(uuid string) Genre {
|
func getGenreByUUID(uuid string) Genre {
|
||||||
var genre Genre
|
var genre Genre
|
||||||
err := db.QueryRow(
|
err := db.QueryRow(
|
||||||
"SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `artists` WHERE `uuid` = UUID_TO_BIN(?,true)",
|
"SELECT BIN_TO_UUID(`uuid`, true), `name` FROM `artists` WHERE `uuid` = UUID_TO_BIN(?,true)",
|
||||||
|
@ -3,7 +3,6 @@ package goscrobble
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
@ -80,7 +79,7 @@ func ParseJellyfinInput(userUUID string, jf JellyfinRequest, ip net.IP, tx *sql.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert album if not exist
|
// Insert album if not exist
|
||||||
artists := []string{artist.Uuid}
|
artists := []string{artist.UUID}
|
||||||
album, err := insertAlbum(jf.Album, jf.ProviderMusicbrainzalbum, "", artists, tx)
|
album, err := insertAlbum(jf.Album, jf.ProviderMusicbrainzalbum, "", artists, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
@ -89,7 +88,7 @@ func ParseJellyfinInput(userUUID string, jf JellyfinRequest, ip net.IP, tx *sql.
|
|||||||
|
|
||||||
// Insert track if not exist
|
// Insert track if not exist
|
||||||
length := timestampToSeconds(jf.RunTime)
|
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 {
|
if err != nil {
|
||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map track")
|
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
|
// Insert scrobble if not exist
|
||||||
timestamp := time.Now()
|
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 {
|
if err != nil {
|
||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map track")
|
return errors.New("Failed to map track")
|
||||||
|
@ -37,7 +37,7 @@ func ParseMultiScrobblerInput(userUUID string, data MultiScrobblerRequest, ip ne
|
|||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map artist: " + artist.Name)
|
return errors.New("Failed to map artist: " + artist.Name)
|
||||||
}
|
}
|
||||||
artists = append(artists, artist.Uuid)
|
artists = append(artists, artist.UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert album if not exist
|
// Insert album if not exist
|
||||||
@ -48,14 +48,14 @@ func ParseMultiScrobblerInput(userUUID string, data MultiScrobblerRequest, ip ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert track if not exist
|
// 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 {
|
if err != nil {
|
||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map track")
|
return errors.New("Failed to map track")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert scrobble if not exist
|
// 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 {
|
if err != nil {
|
||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map track")
|
return errors.New("Failed to map track")
|
||||||
|
@ -61,7 +61,6 @@ func connectSpotifyResponse(r *http.Request) error {
|
|||||||
auth := getSpotifyAuthHandler()
|
auth := getSpotifyAuthHandler()
|
||||||
token, err := auth.Token(userUuid, r)
|
token, err := auth.Token(userUuid, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%+v", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +73,6 @@ func connectSpotifyResponse(r *http.Request) error {
|
|||||||
time := time.Now().UTC().Add(-(time.Duration(30) * time.Minute))
|
time := time.Now().UTC().Add(-(time.Duration(30) * time.Minute))
|
||||||
err = insertOauthToken(userUuid, "spotify", token.AccessToken, token.RefreshToken, token.Expiry, spotifyUser.DisplayName, time)
|
err = insertOauthToken(userUuid, "spotify", token.AccessToken, token.RefreshToken, token.Expiry, spotifyUser.DisplayName, time)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%+v", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +151,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client
|
|||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map artist: " + artist.Name)
|
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)
|
// Get full track data (album / track info)
|
||||||
@ -171,7 +169,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client
|
|||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map album: " + artist.Name)
|
return errors.New("Failed to map album: " + artist.Name)
|
||||||
}
|
}
|
||||||
albumartists = append(albumartists, albumartist.Uuid)
|
albumartists = append(albumartists, albumartist.UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert album if not exist
|
// Insert album if not exist
|
||||||
@ -183,7 +181,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client
|
|||||||
|
|
||||||
// Insert track if not exist
|
// Insert track if not exist
|
||||||
length := int(fulltrack.Duration / 1000)
|
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 {
|
if err != nil {
|
||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map track")
|
return errors.New("Failed to map track")
|
||||||
@ -191,7 +189,7 @@ func ParseSpotifyInput(userUUID string, data spotify.RecentlyPlayedItem, client
|
|||||||
|
|
||||||
// Insert scrobble if not exist
|
// Insert scrobble if not exist
|
||||||
ip := net.ParseIP("0.0.0.0")
|
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 {
|
if err != nil {
|
||||||
log.Printf("%+v", err)
|
log.Printf("%+v", err)
|
||||||
return errors.New("Failed to map track")
|
return errors.New("Failed to map track")
|
||||||
|
@ -6,12 +6,12 @@ type ProfileResponse struct {
|
|||||||
Scrobbles []ScrobbleResponseItem `json:"scrobbles"`
|
Scrobbles []ScrobbleResponseItem `json:"scrobbles"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProfile(user User) (ProfileResponse, error) {
|
func getProfileForUser(user User) (ProfileResponse, error) {
|
||||||
resp := ProfileResponse{
|
resp := ProfileResponse{
|
||||||
UUID: user.UUID,
|
UUID: user.UUID,
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
}
|
}
|
||||||
scrobbleReq, err := fetchScrobblesForUser(user.UUID, 10, 1)
|
scrobbleReq, err := getScrobblesForUser(user.UUID, 10, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ func insertScrobble(user string, track string, source string, timestamp time.Tim
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse, error) {
|
func getScrobblesForUser(userUuid string, limit int, page int) (ScrobbleResponse, error) {
|
||||||
scrobbleReq := ScrobbleResponse{}
|
scrobbleReq := ScrobbleResponse{}
|
||||||
var count int
|
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 {
|
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`) "+
|
_, 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
|
return err
|
||||||
}
|
}
|
||||||
|
@ -37,25 +37,28 @@ func HandleRequests(port string) {
|
|||||||
v1.HandleFunc("/ingress/multiscrobbler", limitMiddleware(tokenMiddleware(handleIngress), lightLimiter)).Methods("POST")
|
v1.HandleFunc("/ingress/multiscrobbler", limitMiddleware(tokenMiddleware(handleIngress), lightLimiter)).Methods("POST")
|
||||||
|
|
||||||
// JWT Auth - Own profile only (Uses uuid in JWT)
|
// 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", limitMiddleware(jwtMiddleware(patchUser), lightLimiter)).Methods("PATCH")
|
||||||
v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(getSpotifyClientID), lightLimiter)).Methods("GET")
|
v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(getSpotifyClientID), lightLimiter)).Methods("GET")
|
||||||
v1.HandleFunc("/user/spotify", limitMiddleware(jwtMiddleware(deleteSpotifyLink), lightLimiter)).Methods("DELETE")
|
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
|
// 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")
|
v1.HandleFunc("/config", limitMiddleware(adminMiddleware(postConfig), standardLimiter)).Methods("POST")
|
||||||
|
|
||||||
// No Auth
|
// No Auth
|
||||||
v1.HandleFunc("/stats", limitMiddleware(handleStats, lightLimiter)).Methods("GET")
|
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("/register", limitMiddleware(handleRegister, heavyLimiter)).Methods("POST")
|
||||||
v1.HandleFunc("/login", limitMiddleware(handleLogin, standardLimiter)).Methods("POST")
|
v1.HandleFunc("/login", limitMiddleware(handleLogin, standardLimiter)).Methods("POST")
|
||||||
v1.HandleFunc("/sendreset", limitMiddleware(handleSendReset, heavyLimiter)).Methods("POST")
|
v1.HandleFunc("/sendreset", limitMiddleware(handleSendReset, heavyLimiter)).Methods("POST")
|
||||||
v1.HandleFunc("/resetpassword", limitMiddleware(handleResetPassword, 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
|
// Redirect from Spotify Oauth
|
||||||
v1.HandleFunc("/link/spotify", limitMiddleware(postSpotifyReponse, lightLimiter))
|
v1.HandleFunc("/link/spotify", limitMiddleware(postSpotifyReponse, lightLimiter))
|
||||||
@ -289,10 +292,10 @@ func handleIngress(w http.ResponseWriter, r *http.Request, userUuid string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchUser - Return personal userprofile
|
// getUser - Return personal userprofile
|
||||||
func fetchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
func getUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
||||||
// We don't this var most of the time
|
// We don't this var most of the time
|
||||||
userFull, err := getUser(jwtUser)
|
userFull, err := getUserByUUID(jwtUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwOkError(w, "Failed to fetch user information")
|
throwOkError(w, "Failed to fetch user information")
|
||||||
return
|
return
|
||||||
@ -322,7 +325,7 @@ func fetchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser s
|
|||||||
|
|
||||||
// patchUser - Update specific values
|
// patchUser - Update specific values
|
||||||
func patchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
func patchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
||||||
userFull, err := getUser(jwtUser)
|
userFull, err := getUserByUUID(jwtUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwOkError(w, "Failed to fetch user information")
|
throwOkError(w, "Failed to fetch user information")
|
||||||
return
|
return
|
||||||
@ -346,9 +349,9 @@ func patchUser(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser s
|
|||||||
throwOkMessage(w, "User updated successfully")
|
throwOkMessage(w, "User updated successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchScrobbles - Return an array of scrobbles
|
// getScrobbles - Return an array of scrobbles
|
||||||
func fetchScrobbleResponse(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
func getScrobbles(w http.ResponseWriter, r *http.Request, jwtUser string, reqUser string) {
|
||||||
resp, err := fetchScrobblesForUser(reqUser, 100, 1)
|
resp, err := getScrobblesForUser(reqUser, 100, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwOkError(w, "Failed to fetch scrobbles")
|
throwOkError(w, "Failed to fetch scrobbles")
|
||||||
return
|
return
|
||||||
@ -360,8 +363,8 @@ func fetchScrobbleResponse(w http.ResponseWriter, r *http.Request, jwtUser strin
|
|||||||
w.Write(json)
|
w.Write(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchScrobbles - Return an array of scrobbles
|
// getConfig - Return an array of scrobbles
|
||||||
func fetchConfig(w http.ResponseWriter, r *http.Request, jwtUser string) {
|
func getConfig(w http.ResponseWriter, r *http.Request, jwtUser string) {
|
||||||
config, err := getAllConfigs()
|
config, err := getAllConfigs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwOkError(w, "Failed to fetch scrobbles")
|
throwOkError(w, "Failed to fetch scrobbles")
|
||||||
@ -373,7 +376,7 @@ func fetchConfig(w http.ResponseWriter, r *http.Request, jwtUser string) {
|
|||||||
w.Write(json)
|
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) {
|
func postConfig(w http.ResponseWriter, r *http.Request, jwtUser string) {
|
||||||
bodyJson, err := decodeJson(r.Body)
|
bodyJson, err := decodeJson(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -394,8 +397,8 @@ func postConfig(w http.ResponseWriter, r *http.Request, jwtUser string) {
|
|||||||
throwOkMessage(w, "Config updated successfully")
|
throwOkMessage(w, "Config updated successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchProfile - Returns public user profile data
|
// getProfile - Returns public user profile data
|
||||||
func fetchProfile(w http.ResponseWriter, r *http.Request) {
|
func getProfile(w http.ResponseWriter, r *http.Request) {
|
||||||
var username string
|
var username string
|
||||||
for k, v := range mux.Vars(r) {
|
for k, v := range mux.Vars(r) {
|
||||||
if k == "username" {
|
if k == "username" {
|
||||||
@ -414,7 +417,7 @@ func fetchProfile(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := getProfile(user)
|
resp, err := getProfileForUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwOkError(w, err.Error())
|
throwOkError(w, err.Error())
|
||||||
return
|
return
|
||||||
@ -425,6 +428,81 @@ func fetchProfile(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(json)
|
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
|
// postSpotifyResponse - Oauth Response from Spotify
|
||||||
func postSpotifyReponse(w http.ResponseWriter, r *http.Request) {
|
func postSpotifyReponse(w http.ResponseWriter, r *http.Request) {
|
||||||
err := connectSpotifyResponse(r)
|
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")
|
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")
|
cachedRegistrationEnabled := getRedisVal("REGISTRATION_ENABLED")
|
||||||
if cachedRegistrationEnabled == "" {
|
if cachedRegistrationEnabled == "" {
|
||||||
registrationEnabled, err := getConfigValue("REGISTRATION_ENABLED")
|
registrationEnabled, err := getConfigValue("REGISTRATION_ENABLED")
|
||||||
@ -478,7 +556,7 @@ func fetchServerInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info := ServerInfo{
|
info := ServerInfo{
|
||||||
Version: "0.0.18",
|
Version: "0.0.19",
|
||||||
RegistrationEnabled: cachedRegistrationEnabled,
|
RegistrationEnabled: cachedRegistrationEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ func adminMiddleware(next func(http.ResponseWriter, *http.Request, string)) http
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := getUser(claims.Subject)
|
user, err := getUserByUUID(claims.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwUnauthorized(w, err.Error())
|
throwUnauthorized(w, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -34,7 +34,7 @@ func getStats() (StatsRequest, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If not cached, pull data then return
|
// If not cached, pull data then return
|
||||||
statsReq, err = fetchStats()
|
statsReq, err = getAllStats()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error fetching stats: %+v", err)
|
log.Printf("Error fetching stats: %+v", err)
|
||||||
return statsReq, errors.New("Error fetching stats")
|
return statsReq, errors.New("Error fetching stats")
|
||||||
@ -46,10 +46,10 @@ func getStats() (StatsRequest, error) {
|
|||||||
|
|
||||||
// goFetchStats - Async call
|
// goFetchStats - Async call
|
||||||
func goFetchStats() {
|
func goFetchStats() {
|
||||||
_, _ = fetchStats()
|
_, _ = getAllStats()
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchStats() (StatsRequest, error) {
|
func getAllStats() (StatsRequest, error) {
|
||||||
statsReq := StatsRequest{}
|
statsReq := StatsRequest{}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -3,17 +3,16 @@ package goscrobble
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Track struct {
|
type Track struct {
|
||||||
Uuid string `json:"uuid"`
|
UUID string `json:"uuid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Length int `json:"length"`
|
Length int `json:"length"`
|
||||||
Desc sql.NullString `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Img sql.NullString `json:"img"`
|
Img string `json:"img"`
|
||||||
MusicBrainzID string `json:"mbid"`
|
MusicBrainzID string `json:"mbid"`
|
||||||
SpotifyID string `json:"spotify_id"`
|
SpotifyID string `json:"spotify_id"`
|
||||||
}
|
}
|
||||||
@ -24,35 +23,26 @@ func insertTrack(name string, legnth int, mbid string, spotifyId string, album s
|
|||||||
|
|
||||||
// Try locate our track
|
// Try locate our track
|
||||||
if mbid != "" {
|
if mbid != "" {
|
||||||
track = fetchTrack("mbid", mbid, tx)
|
track = getTrackByCol("mbid", mbid, tx)
|
||||||
fmt.Printf("Fetech mbid: %s", mbid)
|
|
||||||
} else if spotifyId != "" {
|
} else if spotifyId != "" {
|
||||||
track = fetchTrack("spotify_id", spotifyId, tx)
|
track = getTrackByCol("spotify_id", spotifyId, tx)
|
||||||
fmt.Printf("Fetech spotify: %s", spotifyId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it didn't match above, lookup by name
|
// If it didn't match above, lookup by name
|
||||||
if track.Uuid == "" {
|
if track.UUID == "" {
|
||||||
// TODO: add artist check here too
|
track = getTrackWithArtists(name, artists, album, tx)
|
||||||
track = fetchTrackWithArtists(name, artists, album, tx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can't find it. Lets add it!
|
// If we can't find it. Lets add it!
|
||||||
if track.Uuid == "" {
|
if track.UUID == "" {
|
||||||
err := insertNewTrack(name, legnth, mbid, spotifyId, tx)
|
err := insertNewTrack(&track, name, legnth, mbid, spotifyId, tx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return track, errors.New("Failed to insert track")
|
return track, errors.New("Failed to insert track")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the recently inserted track to get the UUID
|
if track.UUID == "" {
|
||||||
if mbid != "" {
|
return track, errors.New("Unable to fetch track!")
|
||||||
track = fetchTrack("mbid", mbid, tx)
|
|
||||||
} else if spotifyId != "" {
|
|
||||||
track = fetchTrack("spotify_id", spotifyId, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if track.Uuid == "" {
|
|
||||||
track = fetchTrackWithArtists(name, artists, album, tx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = track.linkTrack(album, artists, tx)
|
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 == "" {
|
// Updates these values if we match earlier!
|
||||||
return track, errors.New("Unable to fetch track!")
|
|
||||||
}
|
|
||||||
|
|
||||||
if track.MusicBrainzID != mbid {
|
if track.MusicBrainzID != mbid {
|
||||||
track.MusicBrainzID = mbid
|
track.MusicBrainzID = mbid
|
||||||
track.updateTrack("mbid", mbid, tx)
|
track.updateTrack("mbid", mbid, tx)
|
||||||
@ -78,11 +65,11 @@ func insertTrack(name string, legnth int, mbid string, spotifyId string, album s
|
|||||||
return track, nil
|
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
|
var track Track
|
||||||
err := tx.QueryRow(
|
err := tx.QueryRow(
|
||||||
"SELECT BIN_TO_UUID(`uuid`, true), `name`, `desc`, `img`, `mbid` FROM `tracks` WHERE `"+col+"` = ? LIMIT 1",
|
"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)
|
val).Scan(&track.UUID, &track.Name, &track.Desc, &track.Img, &track.MusicBrainzID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
@ -93,16 +80,16 @@ func fetchTrack(col string, val string, tx *sql.Tx) Track {
|
|||||||
return 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
|
var track Track
|
||||||
artistString := strings.Join(artists, "','")
|
artistString := strings.Join(artists, "','")
|
||||||
err := tx.QueryRow(
|
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_artist` ON `tracks`.`uuid` = `track_artist`.`track` "+
|
||||||
"LEFT JOIN `track_album` ON `tracks`.`uuid` = `track_album`.`track` "+
|
"LEFT JOIN `track_album` ON `tracks`.`uuid` = `track_album`.`track` "+
|
||||||
"WHERE `name` = ? AND BIN_TO_UUID(`track_artist`.`artist`, true) IN ('"+artistString+"') "+
|
"WHERE `name` = ? AND BIN_TO_UUID(`track_artist`.`artist`, true) IN ('"+artistString+"') "+
|
||||||
"AND BIN_TO_UUID(`track_album`.`album`,true) = ? LIMIT 1",
|
"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 != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
@ -113,9 +100,15 @@ func fetchTrackWithArtists(name string, artists []string, album string, tx *sql.
|
|||||||
return track
|
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`) "+
|
_, 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
|
return err
|
||||||
}
|
}
|
||||||
@ -126,24 +119,26 @@ func (track *Track) linkTrack(album string, artists []string, tx *sql.Tx) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = track.linkTrackToArtists(artists, tx)
|
err = track.linkTrackToArtists(artists, tx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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`) "+
|
_, 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
|
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
|
var err error
|
||||||
for _, artist := range artists {
|
for _, artist := range artists {
|
||||||
_, err = tx.Exec("INSERT INTO `track_artist` (`track`, `artist`) "+
|
_, 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 {
|
if err != nil {
|
||||||
return err
|
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 {
|
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
|
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
|
||||||
|
}
|
||||||
|
@ -211,7 +211,7 @@ func userAlreadyExists(req *RegisterRequest) bool {
|
|||||||
return count > 0
|
return count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUser(uuid string) (User, error) {
|
func getUserByUUID(uuid string) (User, error) {
|
||||||
var user User
|
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",
|
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)
|
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)
|
||||||
|
@ -12,6 +12,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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])?)*$")
|
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)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("RESTULS: %+v", result)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,3 +161,7 @@ func getMd5(val string) string {
|
|||||||
hash := md5.Sum([]byte(val))
|
hash := md5.Sum([]byte(val))
|
||||||
return hex.EncodeToString(hash[:])
|
return hex.EncodeToString(hash[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newUUID() string {
|
||||||
|
return uuid.New().String()
|
||||||
|
}
|
||||||
|
@ -11,6 +11,9 @@ function getHeaders() {
|
|||||||
if (user.exp < unixtime) {
|
if (user.exp < unixtime) {
|
||||||
// TODO: Handle expiry nicer
|
// TODO: Handle expiry nicer
|
||||||
toast.warning("Session expired. Please log in again")
|
toast.warning("Session expired. Please log in again")
|
||||||
|
// localStorage.removeItem('user');
|
||||||
|
// window.location.reload();
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { Authorization: 'Bearer ' + user.jwt };
|
return { Authorization: 'Bearer ' + user.jwt };
|
||||||
@ -252,3 +255,30 @@ export const getServerInfo = () => {
|
|||||||
return handleErrorResp(error)
|
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)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -13,7 +13,7 @@ const menuItems = [
|
|||||||
|
|
||||||
const loggedInMenuItems = [
|
const loggedInMenuItems = [
|
||||||
'Dashboard',
|
'Dashboard',
|
||||||
'About',
|
'Docs',
|
||||||
]
|
]
|
||||||
|
|
||||||
const isMobile = () => {
|
const isMobile = () => {
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -2,31 +2,30 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import '../App.css';
|
import '../App.css';
|
||||||
import './Album.css';
|
import './Album.css';
|
||||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||||
import ScrobbleTable from '../Components/ScrobbleTable'
|
import { getAlbum } from '../Api/index'
|
||||||
|
|
||||||
const Album = (route) => {
|
const Album = (route) => {
|
||||||
const [loading, setLoading] = useState(true);
|
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) {
|
if (route && route.match && route.match.params && route.match.params.uuid) {
|
||||||
album = route.match.params.uuid;
|
albumUUID = route.match.params.uuid;
|
||||||
} else {
|
} else {
|
||||||
album = false;
|
albumUUID = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!album) {
|
if (!albumUUID) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// getProfile(username)
|
getAlbum(albumUUID)
|
||||||
// .then(data => {
|
.then(data => {
|
||||||
// setProfile(data);
|
setAlbum(data);
|
||||||
// console.log(data)
|
setLoading(false);
|
||||||
// setLoading(false);
|
})
|
||||||
// })
|
}, [albumUUID])
|
||||||
}, [album])
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@ -36,7 +35,7 @@ const Album = (route) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!album || !album) {
|
if (!albumUUID || !album) {
|
||||||
return (
|
return (
|
||||||
<div className="pageWrapper">
|
<div className="pageWrapper">
|
||||||
Unable to fetch user
|
Unable to fetch user
|
||||||
@ -47,10 +46,11 @@ const Album = (route) => {
|
|||||||
return (
|
return (
|
||||||
<div className="pageWrapper">
|
<div className="pageWrapper">
|
||||||
<h1>
|
<h1>
|
||||||
{album}
|
{album.name}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="pageBody">
|
<div className="pageBody">
|
||||||
Album
|
MusicBrainzId: {album.mbid}<br/>
|
||||||
|
SpotifyID: {album.spotify_id}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,31 +2,30 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import '../App.css';
|
import '../App.css';
|
||||||
import './Artist.css';
|
import './Artist.css';
|
||||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||||
import ScrobbleTable from '../Components/ScrobbleTable'
|
import { getArtist } from '../Api/index'
|
||||||
|
|
||||||
const Artist = (route) => {
|
const Artist = (route) => {
|
||||||
const [loading, setLoading] = useState(true);
|
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) {
|
if (route && route.match && route.match.params && route.match.params.uuid) {
|
||||||
artist = route.match.params.uuid;
|
artistUUID = route.match.params.uuid;
|
||||||
} else {
|
} else {
|
||||||
artist = false;
|
artistUUID = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!artist) {
|
if (!artistUUID) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// getProfile(username)
|
getArtist(artistUUID)
|
||||||
// .then(data => {
|
.then(data => {
|
||||||
// setProfile(data);
|
setArtist(data);
|
||||||
// console.log(data)
|
setLoading(false);
|
||||||
// setLoading(false);
|
})
|
||||||
// })
|
}, [artistUUID])
|
||||||
}, [artist])
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@ -36,7 +35,7 @@ const Artist = (route) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!artist || !artist) {
|
if (!artistUUID || !artist) {
|
||||||
return (
|
return (
|
||||||
<div className="pageWrapper">
|
<div className="pageWrapper">
|
||||||
Unable to fetch user
|
Unable to fetch user
|
||||||
@ -47,10 +46,11 @@ const Artist = (route) => {
|
|||||||
return (
|
return (
|
||||||
<div className="pageWrapper">
|
<div className="pageWrapper">
|
||||||
<h1>
|
<h1>
|
||||||
{artist}
|
{artist.name}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="pageBody">
|
<div className="pageBody">
|
||||||
Artist
|
MusicBrainzId: {artist.mbid}<br/>
|
||||||
|
SpotifyID: {artist.spotify_id}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
1
web/src/Pages/Docs.css
Normal file
1
web/src/Pages/Docs.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
25
web/src/Pages/Docs.js
Normal file
25
web/src/Pages/Docs.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import '../App.css';
|
||||||
|
import './Docs.css';
|
||||||
|
|
||||||
|
const Docs = () => {
|
||||||
|
return (
|
||||||
|
<div className="pageWrapper">
|
||||||
|
<h1>
|
||||||
|
Documentation
|
||||||
|
</h1>
|
||||||
|
<p className="aboutBody">
|
||||||
|
Go-Scrobble is an open source music scorbbling service written in Go and React.<br/>
|
||||||
|
Used to track your listening history and build a profile to discover new music.
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
className="pageBody"
|
||||||
|
href="https://gitlab.com/idanoo/go-scrobble"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>gitlab.com/idanoo/go-scrobble
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Docs;
|
@ -2,31 +2,30 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import '../App.css';
|
import '../App.css';
|
||||||
import './Track.css';
|
import './Track.css';
|
||||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||||
import ScrobbleTable from '../Components/ScrobbleTable'
|
import { getTrack } from '../Api/index'
|
||||||
|
|
||||||
const Track = (route) => {
|
const Track = (route) => {
|
||||||
const [loading, setLoading] = useState(true);
|
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) {
|
if (route && route.match && route.match.params && route.match.params.uuid) {
|
||||||
artist = route.match.params.uuid;
|
trackUUID = route.match.params.uuid;
|
||||||
} else {
|
} else {
|
||||||
artist = false;
|
trackUUID = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!artist) {
|
if (!trackUUID) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// getProfile(username)
|
getTrack(trackUUID)
|
||||||
// .then(data => {
|
.then(data => {
|
||||||
// setProfile(data);
|
setTrack(data);
|
||||||
// console.log(data)
|
setLoading(false);
|
||||||
// setLoading(false);
|
})
|
||||||
// })
|
}, [trackUUID])
|
||||||
}, [artist])
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@ -36,7 +35,7 @@ const Track = (route) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!artist || !artist) {
|
if (!trackUUID || !track) {
|
||||||
return (
|
return (
|
||||||
<div className="pageWrapper">
|
<div className="pageWrapper">
|
||||||
Unable to fetch user
|
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 (
|
return (
|
||||||
<div className="pageWrapper">
|
<div className="pageWrapper">
|
||||||
<h1>
|
<h1>
|
||||||
{artist}
|
{track.name}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="pageBody">
|
<div className="pageBody">
|
||||||
Artist
|
MusicBrainzId: {track.mbid}<br/>
|
||||||
|
SpotifyID: {track.spotify_id}<br/>
|
||||||
|
Track Length: {length}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -8,7 +8,7 @@ import { getUser, patchUser } from '../Api/index'
|
|||||||
import { Button } from 'reactstrap';
|
import { Button } from 'reactstrap';
|
||||||
import { confirmAlert } from 'react-confirm-alert';
|
import { confirmAlert } from 'react-confirm-alert';
|
||||||
import 'react-confirm-alert/src/react-confirm-alert.css';
|
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'
|
import TimezoneSelect from 'react-timezone-select'
|
||||||
|
|
||||||
const User = () => {
|
const User = () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user