mirror of
https://github.com/idanoo/GoScrobble.git
synced 2024-11-22 00:21:55 +00:00
0.0.23
- Get top tracks pulling correctly :)
This commit is contained in:
parent
3f3296e649
commit
07bce0ebc2
@ -3,7 +3,7 @@ stages:
|
|||||||
- bundle
|
- bundle
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
VERSION: 0.0.22
|
VERSION: 0.0.23
|
||||||
|
|
||||||
build-go:
|
build-go:
|
||||||
image: golang:1.16.2
|
image: golang:1.16.2
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# 0.0.23
|
||||||
|
- Get top tracks pulling correctly :)
|
||||||
|
|
||||||
# 0.0.22
|
# 0.0.22
|
||||||
- Rework navbar + user pages
|
- Rework navbar + user pages
|
||||||
|
|
||||||
|
@ -50,8 +50,11 @@ func HandleRequests(port string) {
|
|||||||
// 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(getProfile, lightLimiter)).Methods("GET")
|
v1.HandleFunc("/profile/{username}", limitMiddleware(getProfile, lightLimiter)).Methods("GET")
|
||||||
|
v1.HandleFunc("/artist/top/{uuid}", limitMiddleware(getArtists, lightLimiter)).Methods("GET")
|
||||||
v1.HandleFunc("/artist/{uuid}", limitMiddleware(getArtist, lightLimiter)).Methods("GET")
|
v1.HandleFunc("/artist/{uuid}", limitMiddleware(getArtist, lightLimiter)).Methods("GET")
|
||||||
|
v1.HandleFunc("/album/top/{uuid}", limitMiddleware(getArtists, lightLimiter)).Methods("GET")
|
||||||
v1.HandleFunc("/album/{uuid}", limitMiddleware(getAlbum, lightLimiter)).Methods("GET")
|
v1.HandleFunc("/album/{uuid}", limitMiddleware(getAlbum, lightLimiter)).Methods("GET")
|
||||||
|
v1.HandleFunc("/track/top/{uuid}", limitMiddleware(getTracks, lightLimiter)).Methods("GET")
|
||||||
v1.HandleFunc("/track/{uuid}", limitMiddleware(getTrack, 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")
|
||||||
@ -533,6 +536,81 @@ func getTrack(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(json)
|
w.Write(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getArtists - Returns artist data for a user
|
||||||
|
func getArtists(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAlbums - Returns album data for a user
|
||||||
|
func getAlbums(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTracks - Returns track data for a user
|
||||||
|
func getTracks(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 := getTopTracks(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)
|
||||||
@ -587,7 +665,7 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info := ServerInfo{
|
info := ServerInfo{
|
||||||
Version: "0.0.22",
|
Version: "0.0.23",
|
||||||
RegistrationEnabled: cachedRegistrationEnabled,
|
RegistrationEnabled: cachedRegistrationEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,16 @@ type Track struct {
|
|||||||
SpotifyID string `json:"spotify_id"`
|
SpotifyID string `json:"spotify_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TopTrack struct {
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Img string `json:"img"`
|
||||||
|
Plays int `json:"plays"`
|
||||||
|
}
|
||||||
|
type TopTracks struct {
|
||||||
|
Tracks map[int]TopTrack `json:"tracks"`
|
||||||
|
}
|
||||||
|
|
||||||
// insertTrack - This will return if it exists or create it based on MBID > Name
|
// insertTrack - This will return if it exists or create it based on MBID > Name
|
||||||
func insertTrack(name string, legnth int, mbid string, spotifyId string, album string, artists []string, tx *sql.Tx) (Track, error) {
|
func insertTrack(name string, legnth int, mbid string, spotifyId string, album string, artists []string, tx *sql.Tx) (Track, error) {
|
||||||
track := Track{}
|
track := Track{}
|
||||||
@ -164,3 +174,42 @@ func getTrackByUUID(uuid string) (Track, error) {
|
|||||||
|
|
||||||
return track, nil
|
return track, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTopTracks(userUuid string) (TopTracks, error) {
|
||||||
|
var topTracks TopTracks
|
||||||
|
|
||||||
|
rows, err := db.Query("SELECT BIN_TO_UUID(`tracks`.`uuid`, true), `tracks`.`name`, IFNULL(`artists`.`img`,''), count(*) "+
|
||||||
|
"FROM `scrobbles` "+
|
||||||
|
"JOIN `tracks` ON `tracks`.`uuid` = `scrobbles`.`track` "+
|
||||||
|
"JOIN track_artist ON track_artist.track = tracks.uuid "+
|
||||||
|
"JOIN artists ON track_artist.artist = artists.uuid "+
|
||||||
|
"WHERE `user` = UUID_TO_BIN(?, true) "+
|
||||||
|
"GROUP BY `scrobbles`.`track` "+
|
||||||
|
"ORDER BY count(*) DESC "+
|
||||||
|
"LIMIT 14",
|
||||||
|
userUuid)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to fetch top tracks: %+v", err)
|
||||||
|
return topTracks, errors.New("Failed to fetch top tracks")
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
i := 1
|
||||||
|
tempTracks := make(map[int]TopTrack)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var track TopTrack
|
||||||
|
err := rows.Scan(&track.UUID, &track.Name, &track.Img, &track.Plays)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to fetch track: %+v", err)
|
||||||
|
return topTracks, errors.New("Failed to fetch track")
|
||||||
|
}
|
||||||
|
|
||||||
|
tempTracks[i] = track
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
topTracks.Tracks = tempTracks
|
||||||
|
|
||||||
|
return topTracks, nil
|
||||||
|
}
|
||||||
|
@ -317,3 +317,12 @@ export const getTrack = (uuid) => {
|
|||||||
return handleErrorResp(error)
|
return handleErrorResp(error)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getTopTracks = (uuid) => {
|
||||||
|
return axios.get(process.env.REACT_APP_API_URL + "track/top/" + uuid).then(
|
||||||
|
(data) => {
|
||||||
|
return data.data;
|
||||||
|
}).catch((error) => {
|
||||||
|
return handleErrorResp(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -3,41 +3,121 @@ import './TopTable.css'
|
|||||||
import TopTableBox from './TopTableBox';
|
import TopTableBox from './TopTableBox';
|
||||||
|
|
||||||
const TopTable = (props) => {
|
const TopTable = (props) => {
|
||||||
|
if (!props.items || !props.items.tracks) {
|
||||||
|
return (
|
||||||
|
<span>No data.</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let tracks = props.items.tracks;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span>Top {props.type}</span>
|
<span>Top {props.type}s</span>
|
||||||
<div className="biggestWrapper">
|
<div className="biggestWrapper">
|
||||||
<div className="biggestBox">
|
<div className="biggestBox">
|
||||||
<TopTableBox
|
<TopTableBox
|
||||||
size={300}
|
size={300}
|
||||||
number="1"
|
number="1"
|
||||||
title="hot milk"
|
title={tracks[1].name}
|
||||||
uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316"
|
link={"/" + props.type + "/" + tracks[1].uuid}
|
||||||
img="https://i.scdn.co/image/a397625e38fb671f1baa81997b4c1fd2670fcb10"
|
img={tracks[1].img}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="biggestBox">
|
<div className="biggestBox">
|
||||||
<TopTableBox
|
<TopTableBox
|
||||||
size={150}
|
size={150}
|
||||||
number="2"
|
number="2"
|
||||||
title="Pendulum"
|
title={tracks[2].name}
|
||||||
uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316"
|
link={"/" + props.type + "/" + tracks[2].uuid}
|
||||||
img="https://i.scdn.co/image/0f476171f283207656e95e1005cea7040be475d7"
|
img={tracks[2].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={150}
|
||||||
|
number="3"
|
||||||
|
title={tracks[3].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[3].uuid}
|
||||||
|
img={tracks[3].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={150}
|
||||||
|
number="4"
|
||||||
|
title={tracks[4].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[4].uuid}
|
||||||
|
img={tracks[4].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={150}
|
||||||
|
number="5"
|
||||||
|
title={tracks[5].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[5].uuid}
|
||||||
|
img={tracks[5].img}
|
||||||
/>
|
/>
|
||||||
<TopTableBox size={150} number="3" title="Illenium" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
|
||||||
<TopTableBox size={150} number="4" title="As It is" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
|
||||||
<TopTableBox size={150} number="5" title="CHVRCHES" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="biggestBox">
|
<div className="biggestBox">
|
||||||
<TopTableBox size={100} number="6" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
<TopTableBox
|
||||||
<TopTableBox size={100} number="7" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
size={100}
|
||||||
<TopTableBox size={100} number="8" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
number="6"
|
||||||
<TopTableBox size={100} number="9" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
title={tracks[6].name}
|
||||||
<TopTableBox size={100} number="10" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
link={"/" + props.type + "/" + tracks[6].uuid}
|
||||||
<TopTableBox size={100} number="11" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
img={tracks[6].img}
|
||||||
<TopTableBox size={100} number="12" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
/>
|
||||||
<TopTableBox size={100} number="13" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
<TopTableBox
|
||||||
<TopTableBox size={100} number="14" title="tester" uuid="a2bcc230-f7be-4087-b49a-8c43d19ed316" />
|
size={100}
|
||||||
|
number="7"
|
||||||
|
title={tracks[7].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[7].uuid}
|
||||||
|
img={tracks[7].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={100}
|
||||||
|
number="8"
|
||||||
|
title={tracks[8].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[8].uuid}
|
||||||
|
img={tracks[8].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={100}
|
||||||
|
number="9"
|
||||||
|
title={tracks[9].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[9].uuid}
|
||||||
|
img={tracks[9].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={100}
|
||||||
|
number="10"
|
||||||
|
title={tracks[10].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[10].uuid}
|
||||||
|
img={tracks[10].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={100}
|
||||||
|
number="11"
|
||||||
|
title={tracks[11].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[11].uuid}
|
||||||
|
img={tracks[11].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={100}
|
||||||
|
number="12"
|
||||||
|
title={tracks[12].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[12].uuid}
|
||||||
|
img={tracks[12].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={100}
|
||||||
|
number="13"
|
||||||
|
title={tracks[13].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[13].uuid}
|
||||||
|
img={tracks[13].img}
|
||||||
|
/>
|
||||||
|
<TopTableBox
|
||||||
|
size={100}
|
||||||
|
number="14"
|
||||||
|
title={tracks[14].name}
|
||||||
|
link={"/" + props.type + "/" + tracks[14].uuid}
|
||||||
|
img={tracks[14].img}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,8 +11,9 @@ img {
|
|||||||
.topOverlay {
|
.topOverlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
padding: 0 5px 0 5px;
|
padding: 2px 5px 5px 5px;
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
line-height: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topText {
|
.topText {
|
||||||
|
@ -9,7 +9,7 @@ const TopTableBox = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={"/artist/"+props.uuid} float="left" >
|
<Link to={props.link} float="left" >
|
||||||
<div
|
<div
|
||||||
className="topTableBox"
|
className="topTableBox"
|
||||||
style={{
|
style={{
|
||||||
@ -20,8 +20,10 @@ const TopTableBox = (props) => {
|
|||||||
height: `${props.size}px`,
|
height: `${props.size}px`,
|
||||||
float: `left`,
|
float: `left`,
|
||||||
}} >
|
}} >
|
||||||
<div className="topOverlay">
|
<div className="topOverlay" style={{ maxWidth: `${props.size-'10'}px` }}>
|
||||||
<span className="topText">#{props.number} {props.title}</span>
|
<span className="topText" style={{
|
||||||
|
fontSize: `${props.size === 300 ? '11pt' : (props.size === 150 ? '8pt': '8pt' )}`
|
||||||
|
}}>#{props.number} {props.title}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -2,13 +2,14 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import '../App.css';
|
import '../App.css';
|
||||||
import './Profile.css';
|
import './Profile.css';
|
||||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||||
import { getProfile } from '../Api/index'
|
import { getProfile, getTopTracks } from '../Api/index'
|
||||||
import ScrobbleTable from '../Components/ScrobbleTable'
|
import ScrobbleTable from '../Components/ScrobbleTable'
|
||||||
import TopTable from '../Components/TopTable'
|
import TopTable from '../Components/TopTable'
|
||||||
|
|
||||||
const Profile = (route) => {
|
const Profile = (route) => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [profile, setProfile] = useState({});
|
const [profile, setProfile] = useState({});
|
||||||
|
const [topTracks, setTopTracks] = useState({})
|
||||||
|
|
||||||
let username = false;
|
let username = false;
|
||||||
if (route && route.match && route.match.params && route.match.params.uuid) {
|
if (route && route.match && route.match.params && route.match.params.uuid) {
|
||||||
@ -25,8 +26,17 @@ const Profile = (route) => {
|
|||||||
getProfile(username)
|
getProfile(username)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
setProfile(data);
|
setProfile(data);
|
||||||
|
|
||||||
|
// Fetch top tracks
|
||||||
|
getTopTracks(data.uuid)
|
||||||
|
.then(data => {
|
||||||
|
setTopTracks(data)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
|
|
||||||
}, [username])
|
}, [username])
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@ -51,7 +61,7 @@ const Profile = (route) => {
|
|||||||
{profile.username}'s Profile
|
{profile.username}'s Profile
|
||||||
</h1>
|
</h1>
|
||||||
<div className="pageBody">
|
<div className="pageBody">
|
||||||
<TopTable type="Artists" />
|
<TopTable type="track" items={topTracks} />
|
||||||
<br/>
|
<br/>
|
||||||
Last 10 scrobbles...<br/>
|
Last 10 scrobbles...<br/>
|
||||||
<ScrobbleTable data={profile.scrobbles}/>
|
<ScrobbleTable data={profile.scrobbles}/>
|
||||||
|
Loading…
Reference in New Issue
Block a user