A decentralized music tracking and discovery platform built on AT Protocol 🎵

[web] start using rocksky xrpc api

+93 -58
+4 -4
apps/web/src/api/charts.ts
··· 7 7 8 8 export const getSongChart = async (uri: string) => { 9 9 const response = await axios.get( 10 - `${API_URL}/public/scrobbleschart?songuri=${uri}` 10 + `${API_URL}/xrpc/app.rocksky.charts.getScrobblesChart?songuri=${uri}` 11 11 ); 12 12 if (response.status !== 200) { 13 13 return []; ··· 17 17 18 18 export const getArtistChart = async (uri: string) => { 19 19 const response = await axios.get( 20 - `${API_URL}/public/scrobbleschart?artisturi=${uri}` 20 + `${API_URL}/xrpc/app.rocksky.charts.getScrobblesChart?artisturi=${uri}` 21 21 ); 22 22 if (response.status !== 200) { 23 23 return []; ··· 27 27 28 28 export const getAlbumChart = async (uri: string) => { 29 29 const response = await axios.get( 30 - `${API_URL}/public/scrobbleschart?albumuri=${uri}` 30 + `${API_URL}/xrpc/app.rocksky.charts.getScrobblesChart?albumuri=${uri}` 31 31 ); 32 32 if (response.status !== 200) { 33 33 return []; ··· 37 37 38 38 export const getProfileChart = async (did: string) => { 39 39 const response = await axios.get( 40 - `${API_URL}/public/scrobbleschart?did=${did}` 40 + `${API_URL}/xrpc/app.rocksky.charts.getScrobblesChart?did=${did}` 41 41 ); 42 42 if (response.status !== 200) { 43 43 return [];
+6
apps/web/src/api/index.ts
··· 1 + import axios from "axios"; 2 + import { API_URL } from "../consts"; 3 + 4 + export const client = axios.create({ 5 + baseURL: API_URL, 6 + });
+6 -2
apps/web/src/api/profile.ts
··· 8 8 }; 9 9 10 10 export const getProfileStatsByDid = async (did: string) => { 11 - const response = await axios.get(`${API_URL}/users/${did}/stats`); 11 + const response = await axios.get( 12 + `${API_URL}/xrpc/app.rocksky.stats.getStats`, 13 + { params: { did } } 14 + ); 12 15 return response.data; 13 16 }; 14 17 ··· 18 21 size = 10 19 22 ): Promise<Scrobble[]> => { 20 23 const response = await axios.get<Scrobble[]>( 21 - `${API_URL}/users/${did}/scrobbles?size=${size}&offset=${offset}` 24 + `${API_URL}/users/${did}/scrobbles`, 25 + { params: { size, offset } } 22 26 ); 23 27 return response.data; 24 28 };
+36 -22
apps/web/src/hooks/useChart.tsx
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 - import axios from "axios"; 3 2 import useSWR from "swr"; 4 - import { getArtistChart, getSongChart } from "../api/charts"; 3 + import { client } from "../api"; 4 + import { 5 + getAlbumChart, 6 + getArtistChart, 7 + getProfileChart, 8 + getSongChart, 9 + } from "../api/charts"; 5 10 import { API_URL } from "../consts"; 6 11 7 12 export const useScrobblesChartQuery = () => 8 13 useQuery({ 9 14 queryKey: ["scrobblesChart"], 10 - queryFn: () => 11 - fetch(`${API_URL}/public/scrobbleschart`, { 12 - method: "GET", 13 - }).then((res) => res.json()), 15 + queryFn: () => client.get("/xrpc/app.rocksky.charts.getScrobblesChart"), 16 + select: ({ data }) => data.scrobbles || [], 14 17 }); 15 18 16 19 export const useSongChartQuery = (uri: string) => 17 20 useQuery({ 18 21 queryKey: ["songChart", uri], 19 22 queryFn: () => getSongChart(uri), 23 + select: (data) => data.scrobbles || [], 20 24 }); 21 25 22 26 export const useArtistChartQuery = (uri: string) => 23 27 useQuery({ 24 28 queryKey: ["artistChart", uri], 25 29 queryFn: () => getArtistChart(uri), 30 + select: (data) => data.scrobbles || [], 26 31 }); 27 32 28 33 export const useAlbumChartQuery = (uri: string) => 29 34 useQuery({ 30 35 queryKey: ["albumChart", uri], 31 - queryFn: () => getArtistChart(uri), 36 + queryFn: () => getAlbumChart(uri), 37 + select: (data) => data.scrobbles || [], 32 38 }); 33 39 34 40 export const useProfileChartQuery = (did: string) => 35 41 useQuery({ 36 42 queryKey: ["profileChart", did], 37 - queryFn: () => getArtistChart(did), 43 + queryFn: () => getProfileChart(did), 44 + select: (data) => data.scrobbles || [], 38 45 }); 39 46 40 47 function useChart() { ··· 43 50 method: "GET", 44 51 }).then((res) => res.json()); 45 52 46 - const { data: scrobblesChart } = useSWR("/public/scrobbleschart", fetcher); 53 + const { data: scrobblesChart } = useSWR( 54 + "/xrpc/app.rocksky.charts.getScrobblesChart", 55 + fetcher 56 + ); 47 57 48 58 const getScrobblesChart = () => { 49 - return scrobblesChart || []; 59 + return scrobblesChart?.scrobbles || []; 50 60 }; 51 61 52 62 const getSongChart = async (uri: string) => { 53 - const response = await axios.get( 54 - `${API_URL}/public/scrobbleschart?songuri=${uri}` 63 + const response = await client.get( 64 + "/xrpc/app.rocksky.charts.getScrobblesChart", 65 + { params: { songuri: uri } } 55 66 ); 56 67 if (response.status !== 200) { 57 68 return []; 58 69 } 59 - return response.data; 70 + return response.data.scrobbles; 60 71 }; 61 72 62 73 const getArtistChart = async (uri: string) => { 63 - const response = await axios.get( 64 - `${API_URL}/public/scrobbleschart?artisturi=${uri}` 74 + const response = await client.get( 75 + "/xrpc/app.rocksky.charts.getScrobblesChart", 76 + { params: { artisturi: uri } } 65 77 ); 66 78 if (response.status !== 200) { 67 79 return []; 68 80 } 69 - return response.data; 81 + return response.data.scrobbles; 70 82 }; 71 83 72 84 const getAlbumChart = async (uri: string) => { 73 - const response = await axios.get( 74 - `${API_URL}/public/scrobbleschart?albumuri=${uri}` 85 + const response = await client.get( 86 + "/xrpc/app.rocksky.charts.getScrobblesChart", 87 + { params: { albumuri: uri } } 75 88 ); 76 89 if (response.status !== 200) { 77 90 return []; 78 91 } 79 - return response.data; 92 + return response.data.scrobbles; 80 93 }; 81 94 82 95 const getProfileChart = async (did: string) => { 83 - const response = await axios.get( 84 - `${API_URL}/public/scrobbleschart?did=${did}` 96 + const response = await client.get( 97 + "/xrpc/app.rocksky.charts.getScrobblesChart", 98 + { params: { did } } 85 99 ); 86 100 if (response.status !== 200) { 87 101 return []; 88 102 } 89 - return response.data; 103 + return response.data.scrobbles; 90 104 }; 91 105 92 106 return {
+6 -5
apps/web/src/hooks/useFeed.tsx
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 + import { client } from "../api"; 2 3 import { getFeedByUri } from "../api/feed"; 3 - import { API_URL } from "../consts"; 4 4 5 - export const useFeedQuery = (size = 114) => 5 + export const useFeedQuery = (limit = 114) => 6 6 useQuery({ 7 7 queryKey: ["feed"], 8 8 queryFn: () => 9 - fetch(`${API_URL}/public/scrobbles?size=${size}`, { 10 - method: "GET", 11 - }).then((res) => res.json()), 9 + client.get("/xrpc/app.rocksky.scrobble.getScrobbles", { 10 + params: { limit }, 11 + }), 12 12 refetchInterval: 5000, 13 + select: (res) => res.data.scrobbles || [], 13 14 }); 14 15 15 16 export const useFeedByUriQuery = (uri: string) =>
+12 -10
apps/web/src/hooks/useNowPlaying.tsx
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 - import { API_URL } from "../consts"; 2 + import { client } from "../api"; 3 3 4 4 export type NowPlayings = { 5 5 id: string; 6 6 title: string; 7 7 artist: string; 8 - album_art: string; 9 - artist_uri?: string; 8 + albumArt: string; 9 + artistUri?: string; 10 10 uri: string; 11 11 avatar: string; 12 12 handle: string; 13 13 did: string; 14 - created_at: string; 15 - track_id: string; 16 - track_uri: string; 14 + createdAt: string; 15 + trackId: string; 16 + trackUri: string; 17 17 }[]; 18 18 19 19 export const useNowPlayingsQuery = () => 20 - useQuery<NowPlayings>({ 20 + useQuery({ 21 21 queryKey: ["now-playings"], 22 22 queryFn: () => 23 - fetch(`${API_URL}/now-playings?size=7`, { 24 - method: "GET", 25 - }).then((res) => res.json()), 23 + client.get<{ nowPlayings: NowPlayings }>( 24 + "/xrpc/app.rocksky.feed.getNowPlayings", 25 + { params: { size: 7 } } 26 + ), 26 27 refetchInterval: 5000, 28 + select: (res) => res.data.nowPlayings || [], 27 29 });
+15 -15
apps/web/src/pages/home/nowplayings/NowPlayings.tsx
··· 94 94 id: string; 95 95 title: string; 96 96 artist: string; 97 - album_art: string; 98 - artist_uri?: string; 97 + albumArt: string; 98 + artistUri?: string; 99 99 uri: string; 100 100 avatar: string; 101 101 handle: string; 102 102 did: string; 103 - created_at: string; 104 - track_id: string; 105 - track_uri: string; 103 + createdAt: string; 104 + trackId: string; 105 + trackUri: string; 106 106 } | null>(null); 107 107 const [currentIndex, setCurrentIndex] = useState(0); 108 108 const [progress, setProgress] = useState(0); ··· 211 211 </div> 212 212 </Link> 213 213 <span className="ml-[10px] text-[15px] text-[var(--color-text-muted)]"> 214 - {dayjs.utc(currentlyPlaying?.created_at).local().fromNow()} 214 + {dayjs.utc(currentlyPlaying?.createdAt).local().fromNow()} 215 215 </span> 216 216 </div> 217 217 </ModalHeader> ··· 225 225 )} 226 226 </div> 227 227 <div className="flex flex-col items-center flex-1"> 228 - {currentlyPlaying?.track_uri && ( 228 + {currentlyPlaying?.trackUri && ( 229 229 <Link 230 - to={`/${currentlyPlaying?.track_uri.split("at://")[1]}`} 230 + to={`/${currentlyPlaying?.trackUri.split("at://")[1]}`} 231 231 > 232 232 <Cover 233 - src={currentlyPlaying?.album_art} 233 + src={currentlyPlaying?.albumArt} 234 234 key={currentlyPlaying?.id} 235 235 /> 236 236 </Link> 237 237 )} 238 - {currentlyPlaying?.track_uri && ( 238 + {currentlyPlaying?.trackUri && ( 239 239 <Link 240 - to={`/${currentlyPlaying?.track_uri.split("at://")[1]}`} 240 + to={`/${currentlyPlaying?.trackUri.split("at://")[1]}`} 241 241 > 242 242 <TrackTitle>{currentlyPlaying?.title}</TrackTitle> 243 243 </Link> 244 244 )} 245 - {!currentlyPlaying?.track_uri && ( 245 + {!currentlyPlaying?.trackUri && ( 246 246 <Cover 247 - src={currentlyPlaying?.album_art} 247 + src={currentlyPlaying?.albumArt} 248 248 key={currentlyPlaying?.id} 249 249 /> 250 250 )} ··· 261 261 </div> 262 262 </div> 263 263 264 - {!currentlyPlaying?.track_uri && ( 264 + {!currentlyPlaying?.trackUri && ( 265 265 <TrackTitle>{currentlyPlaying?.title}</TrackTitle> 266 266 )} 267 - <Link to={`/${currentlyPlaying?.artist_uri?.split("at://")[1]}`}> 267 + <Link to={`/${currentlyPlaying?.artistUri?.split("at://")[1]}`}> 268 268 <TrackArtist>{currentlyPlaying?.artist}</TrackArtist> 269 269 </Link> 270 270 </ModalBody>
+8
turbo.json
··· 14 14 "./dist/**" 15 15 ] 16 16 }, 17 + "build:prod": { 18 + "dependsOn": [ 19 + "^build:prod" 20 + ], 21 + "outputs": [ 22 + "./dist/**" 23 + ] 24 + }, 17 25 "dev": { 18 26 "persistent": true, 19 27 "cache": false