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

[web] migrate into rocksky xrpc api

+197 -229
+1
apps/api/src/context.ts
··· 26 26 export const ctx = { 27 27 oauthClient: await createClient(db), 28 28 resolver: createBidirectionalResolver(baseIdResolver), 29 + baseIdResolver, 29 30 kv: new Map<string, string>(), 30 31 client, 31 32 db: drizzle.db,
+5 -2
apps/api/src/xrpc/app/rocksky/actor/getProfile.ts
··· 62 62 return Effect.tryPromise({ 63 63 try: async () => { 64 64 if (!params.did?.startsWith("did:plc:") && !!params.did) { 65 + const handle = await ctx.baseIdResolver.handle.resolve(params.did); 65 66 return fetch( 66 67 `https://dns.google/resolve?name=_atproto.${params.did}&type=TXT` 67 68 ) 68 69 .then((res) => res.json()) 69 70 .then( 70 71 (data) => 71 - _.get(data, "Answer.0.data", "").replace(/"/g, "").split("=")[1] 72 + _.get(data, "Answer.0.data", handle) 73 + .replace(/"/g, "") 74 + .split("=")[1] 72 75 ) 73 76 .then((did) => ({ 74 77 did, ··· 98 101 return Effect.tryPromise({ 99 102 try: async () => { 100 103 if (params.did) { 101 - return fetch(`https://plc.directory/${did}`) 104 + return fetch(`https://plc.directory/${params.did}`) 102 105 .then((res) => res.json()) 103 106 .then((data) => ({ 104 107 did,
+21 -17
apps/web/src/api/feed.ts
··· 1 - import axios from "axios"; 2 - import { API_URL } from "../consts"; 1 + import { client } from "."; 3 2 4 3 export const getFeed = () => { 5 4 return []; 6 5 }; 7 6 8 7 export const getFeedByUri = async (uri: string) => { 9 - const response = await axios.get(`${API_URL}/users/${uri}`); 8 + if (uri.includes("app.rocksky.song")) { 9 + return null; 10 + } 11 + const response = await client.get("/xrpc/app.rocksky.scrobble.getScrobble", { 12 + params: { uri }, 13 + }); 10 14 11 15 if (response.status !== 200) { 12 16 return null; 13 17 } 14 18 15 19 return { 16 - id: response.data.track_id?.xata_id, 17 - title: response.data.track_id?.title, 18 - artist: response.data.track_id?.artist, 19 - albumArtist: response.data.track_id?.album_artist, 20 - album: response.data.track_id?.album, 21 - cover: response.data.track_id?.album_art, 20 + id: response.data?.id, 21 + title: response.data?.title, 22 + artist: response.data?.artist, 23 + albumArtist: response.data?.albumArtist, 24 + album: response.data?.album, 25 + cover: response.data?.cover, 22 26 tags: [], 23 - artistUri: response.data.track_id?.artist_uri, 24 - albumUri: response.data.track_id?.album_uri, 25 - listeners: response.data.listeners || 1, 26 - scrobbles: response.data.scrobbles || 1, 27 - lyrics: response.data.track_id?.lyrics, 28 - spotifyLink: response.data.track_id?.spotify_link, 29 - composer: response.data.track_id?.composer, 30 - uri: response.data.track_id?.uri, 27 + artistUri: response.data?.artistUri, 28 + albumUri: response.data?.albumUri, 29 + listeners: response.data?.listeners || 1, 30 + scrobbles: response.data?.scrobbles || 1, 31 + lyrics: response.data?.lyrics, 32 + spotifyLink: response.data?.spotifyLink, 33 + composer: response.data?.composer, 34 + uri: response.data?.uri, 31 35 }; 32 36 };
+50 -50
apps/web/src/api/library.ts
··· 1 - import axios from "axios"; 2 - import { API_URL } from "../consts"; 1 + import { client } from "."; 3 2 4 3 export const getSongByUri = async (uri: string) => { 5 - const response = await axios.get(`${API_URL}/users/${uri}`); 4 + const response = await client.get("/xrpc/app.rocksky.song.getSong", { 5 + params: { uri }, 6 + }); 6 7 return { 7 8 id: response.data?.id, 8 9 title: response.data?.title, 9 10 artist: response.data?.artist, 10 - albumArtist: response.data?.album_artist, 11 + albumArtist: response.data?.albumArtist, 11 12 album: response.data?.album, 12 - cover: response.data?.album_art, 13 + cover: response.data?.albumArt, 13 14 tags: [], 14 - artistUri: response.data?.artist_uri, 15 - albumUri: response.data?.album_uri, 16 - listeners: response.data?.listeners || 1, 17 - scrobbles: response.data?.scrobbles || 1, 15 + artistUri: response.data?.artistUri, 16 + albumUri: response.data?.albumUri, 17 + listeners: response.data?.uniqueListeners || 1, 18 + scrobbles: response.data?.playCount || 1, 18 19 lyrics: response.data?.lyrics, 19 - spotifyLink: response.data?.spotify_link, 20 + spotifyLink: response.data?.spotifyLink, 20 21 composer: response.data?.composer, 21 22 uri: response.data?.uri, 22 23 }; ··· 30 31 id: string; 31 32 title: string; 32 33 artist: string; 33 - album_artist: string; 34 - album_art: string; 34 + albumArtist: string; 35 + albumArt: string; 35 36 uri: string; 36 - play_count: number; 37 - album_uri?: string; 38 - artist_uri?: string; 37 + playCount: number; 38 + albumUri?: string; 39 + artistUri?: string; 39 40 }[] 40 41 > => { 41 - const response = await axios.get( 42 - `${API_URL}/users/${uri}/tracks?size=${limit}` 42 + const response = await client.get( 43 + "/xrpc/app.rocksky.artist.getArtistTracks", 44 + { params: { uri, limit } } 43 45 ); 44 - return response.data; 46 + return response.data.tracks; 45 47 }; 46 48 47 49 export const getArtistAlbums = async ( ··· 52 54 id: string; 53 55 title: string; 54 56 artist: string; 55 - album_art: string; 56 - artist_uri: string; 57 + albumArt: string; 58 + artistUri: string; 57 59 uri: string; 58 60 }[] 59 61 > => { 60 - const response = await axios.get( 61 - `${API_URL}/users/${uri}/albums?size=${limit}` 62 + const response = await client.get( 63 + "/xrpc/app.rocksky.artist.getArtistAlbums", 64 + { params: { uri, limit } } 62 65 ); 63 - return response.data; 66 + return response.data.albums; 64 67 }; 65 68 66 69 export const getArtists = async (did: string, offset = 0, limit = 30) => { 67 - const response = await axios.get( 68 - `${API_URL}/users/${did}/artists?size=${limit}&offset=${offset}` 69 - ); 70 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 71 - return response.data.map((x: any) => ({ ...x, scrobbles: x.play_count })); 70 + const response = await client.get("/xrpc/app.rocksky.actor.getActorArtists", { 71 + params: { did, limit, offset }, 72 + }); 73 + return response.data; 72 74 }; 73 75 74 76 export const getAlbums = async (did: string, offset = 0, limit = 12) => { 75 - const response = await axios.get( 76 - `${API_URL}/users/${did}/albums?size=${limit}&offset=${offset}` 77 - ); 78 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 79 - return response.data.map((x: any) => ({ 80 - ...x, 81 - scrobbles: x.play_count, 82 - })); 77 + const response = await client.get("/xrpc/app.rocksky.actor.getActorAlbums", { 78 + params: { did, limit, offset }, 79 + }); 80 + return response.data; 83 81 }; 84 82 85 83 export const getTracks = async (did: string, offset = 0, limit = 20) => { 86 - const response = await axios.get( 87 - `${API_URL}/users/${did}/tracks?size=${limit}&offset=${offset}` 88 - ); 89 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 90 - return response.data.map((x: any) => ({ ...x, scrobbles: x.play_count })); 84 + const response = await client.get("/xrpc/app.rocksky.actor.getActorSongs", { 85 + params: { did, limit, offset }, 86 + }); 87 + return response.data; 91 88 }; 92 89 93 90 export const getLovedTracks = async (did: string, offset = 0, limit = 20) => { 94 - const response = await axios.get( 95 - `${API_URL}/users/${did}/likes?size=${limit}&offset=${offset}` 91 + const response = await client.get( 92 + "/xrpc/app.rocksky.actor.getActorLovedSongs", 93 + { 94 + params: { did, limit, offset }, 95 + } 96 96 ); 97 - return response.data; 97 + return response.data.tracks; 98 98 }; 99 99 100 100 export const getAlbum = async (did: string, rkey: string) => { 101 - const response = await axios.get( 102 - `${API_URL}/users/${did}/app.rocksky.album/${rkey}` 103 - ); 101 + const response = await client.get("/xrpc/app.rocksky.album.getAlbum", { 102 + params: { uri: `at://${did}/app.rocksky.album/${rkey}` }, 103 + }); 104 104 return response.data; 105 105 }; 106 106 107 107 export const getArtist = async (did: string, rkey: string) => { 108 - const response = await axios.get( 109 - `${API_URL}/users/${did}/app.rocksky.artist/${rkey}` 110 - ); 108 + const response = await client.get("/xrpc/app.rocksky.artist.getArtist", { 109 + params: { uri: `at://${did}/app.rocksky.artist/${rkey}` }, 110 + }); 111 111 return response.data; 112 112 };
+13 -7
apps/web/src/api/playlists.ts
··· 1 - import axios from "axios"; 2 - import { API_URL } from "../consts"; 1 + import { client } from "."; 3 2 4 3 export const getPlaylists = async ( 5 4 did: string ··· 16 15 trackCount: number; 17 16 }[] 18 17 > => { 19 - const response = await axios.get(`${API_URL}/users/${did}/playlists`); 20 - return response.data; 18 + const response = await client.get( 19 + "/xrpc/app.rocksky.actor.getActorPlaylists", 20 + { 21 + params: { did }, 22 + } 23 + ); 24 + return response.data.playlists; 21 25 }; 22 26 23 27 export const getPlaylist = async ( ··· 56 60 discNumber: number; 57 61 }[]; 58 62 }> => { 59 - const response = await axios.get( 60 - `${API_URL}/users/${did}/app.rocksky.playlist/${rkey}` 61 - ); 63 + const response = await client.get("/xrpc/app.rocksky.playlist.getPlaylist", { 64 + params: { 65 + uri: `at://${did}/app.rocksky.playlist/${rkey}`, 66 + }, 67 + }); 62 68 return response.data; 63 69 };
+2 -2
apps/web/src/components/Handle/Handle.tsx
··· 39 39 ...profiles, 40 40 [did]: { 41 41 avatar: profile.data.avatar, 42 - displayName: profile.data.display_name, 42 + displayName: profile.data.displayName, 43 43 handle: profile.data.handle, 44 44 spotifyConnected: profile.data.spotifyConnected, 45 - createdAt: profile.data.xata_createdat, 45 + createdAt: profile.data.createdAt, 46 46 did, 47 47 }, 48 48 }));
+18
apps/web/src/hooks/useLibrary.tsx
··· 37 37 queryKey: ["artists", did, offset, limit], 38 38 queryFn: () => getArtists(did, offset, limit), 39 39 enabled: !!did, 40 + select: (data) => 41 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 42 + data?.artists.map((x: any) => ({ 43 + ...x, 44 + scrobbles: x.playCount, 45 + })), 40 46 }); 41 47 42 48 export const useAlbumsQuery = (did: string, offset = 0, limit = 12) => ··· 44 50 queryKey: ["albums", did, offset, limit], 45 51 queryFn: () => getAlbums(did, offset, limit), 46 52 enabled: !!did, 53 + select: (data) => 54 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 55 + data?.albums.map((x: any) => ({ 56 + ...x, 57 + scrobbles: x.playCount, 58 + })), 47 59 }); 48 60 49 61 export const useTracksQuery = (did: string, offset = 0, limit = 20) => ··· 51 63 queryKey: ["tracks", did, offset, limit], 52 64 queryFn: () => getTracks(did, offset, limit), 53 65 enabled: !!did, 66 + select: (data) => 67 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 68 + data?.tracks.map((x: any) => ({ 69 + ...x, 70 + scrobbles: x.playCount, 71 + })), 54 72 }); 55 73 56 74 export const useLovedTracksQuery = (did: string, offset = 0, limit = 20) =>
+13 -11
apps/web/src/hooks/useProfile.tsx
··· 43 43 44 44 const fetchProfile = async () => { 45 45 try { 46 - const response = await fetch(`${API_URL}/profile`, { 47 - headers: { 48 - Authorization: `Bearer ${token}`, 49 - }, 50 - }).then((res) => res.text()); 46 + const response = await fetch( 47 + `${API_URL}/xrpc/app.rocksky.actor.getProfile`, 48 + { 49 + headers: { 50 + Authorization: `Bearer ${token}`, 51 + }, 52 + } 53 + ).then((res) => res.text()); 51 54 setData(response); 52 55 setError(null); 53 56 } catch (e) { ··· 62 65 if (data !== "Unauthorized" && data !== "Internal Server Error" && data) { 63 66 const profile = JSON.parse(data); 64 67 setProfile({ 65 - avatar: `https://cdn.bsky.app/img/avatar/plain/${localStorage.getItem( 66 - "did" 67 - )}/${profile.avatar.ref["$link"]}@jpeg`, 68 + avatar: profile.avatar, 68 69 displayName: profile.displayName, 69 70 handle: profile.handle, 70 71 spotifyUser: { 71 - isBeta: profile.spotifyUser?.is_beta_user, 72 + isBeta: profile.spotifyUser?.isBetaUser, 72 73 }, 73 74 spotifyConnected: profile.spotifyConnected, 74 75 did: profile.did, 75 76 googledriveUser: { 76 - isBeta: profile.googledrive?.is_beta_user, 77 + isBeta: profile.googledrive?.isBetaUser, 77 78 }, 78 79 dropboxUser: { 79 - isBeta: profile.dropbox?.is_beta_user, 80 + isBeta: profile.dropbox?.isBetaUser, 80 81 }, 81 82 }); 82 83 } 83 84 84 85 if ( 85 86 !data || 87 + Object.keys(data).length === 0 || 86 88 data === "Unauthorized" || 87 89 data === "Internal Server Error" || 88 90 (error && localStorage.getItem("token"))
+18 -44
apps/web/src/pages/album/Album.tsx
··· 66 66 artistUri?: string; 67 67 label?: string; 68 68 tracks: { 69 - xata_id: string; 70 - track_number: number; 69 + id: string; 70 + trackNumber: number; 71 71 album: string; 72 - album_art: string; 73 - album_artist: string; 72 + albumArt: string; 73 + albumArtist: string; 74 74 title: string; 75 75 artist: string; 76 - xata_created: string; 76 + createdAt: string; 77 77 uri: string; 78 - album_uri: string; 79 - artist_uri: string; 78 + albumUri: string; 79 + artistUri: string; 80 80 duration: number; 81 - disc_number: number; 81 + discNumber: number; 82 82 }[]; 83 83 } | null>(null); 84 84 const uri = `${did}/app.rocksky.album/${rkey}`; ··· 87 87 if (!isLoading && !isError) { 88 88 setAlbum({ 89 89 id: data.id, 90 - albumArt: data.album_art, 91 - artistUri: data.artist_uri, 90 + albumArt: data.albumArt, 91 + artistUri: data.artistUri, 92 92 artist: data.artist, 93 93 title: data.title, 94 94 year: data.year, 95 95 uri: data.uri, 96 - listeners: data.listeners, 97 - scrobbles: data.scrobbles, 96 + listeners: data.uniqueListeners, 97 + scrobbles: data.playCount, 98 98 tracks: data.tracks, 99 - releaseDate: data.release_date 100 - ? dayjs(data.release_date).format("MMMM D, YYYY") 99 + releaseDate: data.releaseDate 100 + ? dayjs(data.releaseDate).format("MMMM D, YYYY") 101 101 : data.year?.toString(), 102 - label: data.tracks[0].copyright_message || data.tracks[0].label, 102 + label: data.tracks[0].copyrightMessage || data.tracks[0].label, 103 103 }); 104 104 // eslint-disable-next-line @typescript-eslint/no-explicit-any 105 - setDisc(Math.max(...data.tracks.map((track: any) => track.disc_number))); 105 + setDisc(Math.max(...data.tracks.map((track: any) => track.discNumber))); 106 106 } 107 107 }, [data, isLoading, isError]); 108 108 ··· 199 199 <div className="mt-[20px]"> 200 200 {disc < 2 && ( 201 201 <TableBuilder 202 - data={album?.tracks.map((x) => ({ 203 - id: x.xata_id, 204 - trackNumber: x.track_number, 205 - albumArt: x.album_art, 206 - title: x.title, 207 - artist: x.artist, 208 - uri: x.uri, 209 - albumUri: album?.uri, 210 - artistUri: x.artist_uri, 211 - albumArtist: x.album_artist, 212 - duration: x.duration, 213 - discNumber: x.disc_number, 214 - }))} 202 + data={album?.tracks} 215 203 emptyMessage="You haven't listened to any music yet." 216 204 divider="clean" 217 205 overrides={{ ··· 317 305 Volume {i + 1} 318 306 </LabelLarge> 319 307 <TableBuilder 320 - data={album?.tracks 321 - .filter((x) => x.disc_number == i + 1) 322 - .map((x) => ({ 323 - id: x.xata_id, 324 - trackNumber: x.track_number, 325 - albumArt: x.album_art, 326 - title: x.title, 327 - artist: x.artist, 328 - uri: x.uri, 329 - albumUri: album?.uri, 330 - artistUri: x.artist_uri, 331 - albumArtist: x.album_artist, 332 - duration: x.duration, 333 - discNumber: x.disc_number, 334 - }))} 308 + data={album?.tracks.filter((x) => x.discNumber == i + 1)} 335 309 emptyMessage="You haven't listened to any music yet." 336 310 divider="clean" 337 311 overrides={{
+7 -7
apps/web/src/pages/artist/Albums/Albums.tsx
··· 24 24 id: string; 25 25 title: string; 26 26 artist: string; 27 - album_art: string; 28 - artist_uri: string; 27 + albumArt: string; 28 + artistUri: string; 29 29 uri: string; 30 30 }[]; 31 31 } ··· 47 47 <FlexGridItem {...itemProps} key={album.id}> 48 48 {album.uri && ( 49 49 <Link to={`/${album.uri.split("at://")[1]}`}> 50 - <SongCover cover={album.album_art} size={230} /> 50 + <SongCover cover={album.albumArt} size={230} /> 51 51 </Link> 52 52 )} 53 - {!album.uri && <SongCover cover={album.album_art} size={230} />} 53 + {!album.uri && <SongCover cover={album.albumArt} size={230} />} 54 54 {album.uri && ( 55 55 <Link to={`/${album.uri.split("at://")[1]}`}> 56 56 <LabelMedium className="!text-[var(--color-text)]"> ··· 59 59 </Link> 60 60 )} 61 61 {!album.uri && <LabelMedium>{album.title}</LabelMedium>} 62 - {album.artist_uri && ( 63 - <Link to={`/${album.artist_uri.split("at://")[1]}`}> 62 + {album.artistUri && ( 63 + <Link to={`/${album.artistUri.split("at://")[1]}`}> 64 64 <LabelSmall className="!text-[var(--color-text-muted)]"> 65 65 {album.artist} 66 66 </LabelSmall> 67 67 </Link> 68 68 )} 69 - {!album.artist_uri && ( 69 + {!album.artistUri && ( 70 70 <LabelSmall className="!text-[var(--color-text-muted)]"> 71 71 {album.artist} 72 72 </LabelSmall>
+10 -23
apps/web/src/pages/artist/Artist.tsx
··· 28 28 const Artist = () => { 29 29 const { did, rkey } = useParams<{ did: string; rkey: string }>(); 30 30 31 - const uri = `${did}/app.rocksky.artist/${rkey}`; 31 + const uri = `at://${did}/app.rocksky.artist/${rkey}`; 32 32 const artistResult = useArtistQuery(did!, rkey!); 33 33 const artistTracksResult = useArtistTracksQuery(uri); 34 34 const artistAlbumsResult = useArtistAlbumsQuery(uri); ··· 53 53 id: string; 54 54 title: string; 55 55 artist: string; 56 - album_art: string; 57 - artist_uri: string; 56 + albumArt: string; 57 + artistUri: string; 58 58 uri: string; 59 59 }[] 60 60 >([]); ··· 72 72 id: artistResult.data.id, 73 73 name: artistResult.data.name, 74 74 born: artistResult.data.born, 75 - bornIn: artistResult.data.born_in, 75 + bornIn: artistResult.data.bornIn, 76 76 died: artistResult.data.died, 77 - listeners: artistResult.data.listeners, 78 - scrobbles: artistResult.data.scrobbles, 77 + listeners: artistResult.data.uniqueListeners, 78 + scrobbles: artistResult.data.playCount, 79 79 picture: artistResult.data.picture, 80 80 tags: artistResult.data.tags, 81 81 uri: artistResult.data.uri, 82 - spotifyLink: artistResult.data.spotify_link, 82 + spotifyLink: artistResult.data.spotifyLink, 83 83 }); 84 84 // eslint-disable-next-line react-hooks/exhaustive-deps 85 85 }, [artistResult.data, artistResult.isLoading, artistResult.isError, did]); ··· 94 94 } 95 95 96 96 setTopTracks( 97 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 98 - artistTracksResult.data.map((track: any) => ({ 97 + artistTracksResult.data.map((track) => ({ 99 98 ...track, 100 - albumArt: track.album_art, 101 - albumArtist: track.album_artist, 102 - albumUri: track.album_uri, 103 - artistUri: track.artist_uri, 99 + scrobbles: track.playCount || 1, 104 100 })) 105 101 ); 106 102 }, [ ··· 119 115 return; 120 116 } 121 117 122 - setTopAlbums( 123 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 124 - artistAlbumsResult.data.map((album: any) => ({ 125 - ...album, 126 - albumArt: album.album_art, 127 - albumArtist: album.album_artist, 128 - albumUri: album.album_uri, 129 - artistUri: album.artist_uri, 130 - })) 131 - ); 118 + setTopAlbums(artistAlbumsResult.data); 132 119 }, [ 133 120 artistAlbumsResult.data, 134 121 artistAlbumsResult.isLoading,
+4 -4
apps/web/src/pages/profile/Profile.tsx
··· 53 53 54 54 setUser({ 55 55 avatar: profile.data.avatar, 56 - displayName: profile.data.display_name, 56 + displayName: profile.data.displayName, 57 57 handle: profile.data.handle, 58 58 spotifyUser: { 59 - isBeta: profile.data.spotifyUser?.is_beta_user, 59 + isBeta: profile.data.spotifyUser?.isBetaUser, 60 60 }, 61 61 spotifyConnected: profile.data.spotifyConnected, 62 62 did: profile.data.did, ··· 66 66 ...profiles, 67 67 [did]: { 68 68 avatar: profile.data.avatar, 69 - displayName: profile.data.display_name, 69 + displayName: profile.data.displayName, 70 70 handle: profile.data.handle, 71 71 spotifyConnected: profile.data.spotifyConnected, 72 - createdAt: profile.data.xata_createdat, 72 + createdAt: profile.data.createdat, 73 73 did, 74 74 }, 75 75 }));
+2 -2
apps/web/src/pages/profile/library/albums/Albums.tsx
··· 82 82 id: x.id, 83 83 title: x.title, 84 84 artist: x.artist, 85 - albumArt: x.album_art, 86 - artistUri: x.artist_uri, 85 + albumArt: x.albumArt, 86 + artistUri: x.artistUri, 87 87 uri: x.uri, 88 88 scrobbles: x.scrobbles, 89 89 }))
+3 -7
apps/web/src/pages/profile/lovedtracks/LovedTracks.tsx
··· 67 67 68 68 setLovedTracks( 69 69 // eslint-disable-next-line @typescript-eslint/no-explicit-any 70 - lovedTracksResult.data.records.map((item: any) => ({ 71 - ...item.track_id, 72 - albumArt: item.track_id.album_art, 73 - albumArtist: item.track_id.album_artist, 74 - albumUri: item.track_id.album_uri, 75 - artistUri: item.track_id.artist_uri, 76 - date: item.xata_createdat, 70 + lovedTracksResult.data.map((item: any) => ({ 71 + ...item, 72 + date: item.createdAt, 77 73 })) 78 74 ); 79 75 // eslint-disable-next-line react-hooks/exhaustive-deps
+4 -4
apps/web/src/pages/profile/overview/topalbums/TopAlbums.tsx
··· 76 76 topAlbums.map((album: any) => ( 77 77 <FlexGridItem {...itemProps} key={album.id}> 78 78 <Link to={`/${album.uri?.split("at://")[1]}`}> 79 - <SongCover cover={album.album_art} size={230} /> 79 + <SongCover cover={album.albumArt} size={230} /> 80 80 </Link> 81 81 <Link to={`/${album.uri?.split("at://")[1]}`}> 82 82 <LabelMedium className="!text-[var(--color-text)]"> 83 83 {album.title} 84 84 </LabelMedium> 85 85 </Link> 86 - {album.artist_uri && ( 87 - <Link to={`/${album.artist_uri.split("at://")[1]}`}> 86 + {album.artistUri && ( 87 + <Link to={`/${album.artistUri.split("at://")[1]}`}> 88 88 <LabelSmall className="!text-[var(--color-text-muted)]"> 89 89 {album.artist} 90 90 </LabelSmall> 91 91 </Link> 92 92 )} 93 - {!album.artist_uri && ( 93 + {!album.artistUri && ( 94 94 <LabelSmall className="!text-[var(--color-text-muted)]"> 95 95 {album.artist} 96 96 </LabelSmall>
+1 -10
apps/web/src/pages/profile/overview/toptracks/TopTracks.tsx
··· 88 88 return; 89 89 } 90 90 91 - setTopTracks( 92 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 93 - tracksResult.data.map((track: any) => ({ 94 - ...track, 95 - albumArt: track.album_art, 96 - albumArtist: track.album_artist, 97 - albumUri: track.album_uri, 98 - artistUri: track.artist_uri, 99 - })) 100 - ); 91 + setTopTracks(tracksResult.data); 101 92 // eslint-disable-next-line react-hooks/exhaustive-deps 102 93 }, [tracksResult.data, tracksResult.isLoading, tracksResult.isError, did]); 103 94
+7 -7
apps/web/src/pages/song/PopularAlbums/PopularAlbums.tsx
··· 24 24 id: string; 25 25 title: string; 26 26 artist: string; 27 - album_art: string; 28 - artist_uri: string; 27 + albumArt: string; 28 + artistUri: string; 29 29 uri: string; 30 30 }[]; 31 31 artist: string; ··· 51 51 <FlexGridItem {...itemProps} key={album.id}> 52 52 {album.uri && ( 53 53 <Link to={`/${album.uri.split("at://")[1]}`}> 54 - <SongCover cover={album.album_art} size={230} /> 54 + <SongCover cover={album.albumArt} size={230} /> 55 55 </Link> 56 56 )} 57 - {!album.uri && <SongCover cover={album.album_art} size={230} />} 57 + {!album.uri && <SongCover cover={album.albumArt} size={230} />} 58 58 {album.uri && ( 59 59 <Link to={`/${album.uri.split("at://")[1]}`}> 60 60 <LabelMedium className="!text-[var(--color-text)]"> ··· 63 63 </Link> 64 64 )} 65 65 {!album.uri && <LabelMedium>{album.title}</LabelMedium>} 66 - {album.artist_uri && ( 67 - <Link to={`/${album.artist_uri.split("at://")[1]}`}> 66 + {album.artistUri && ( 67 + <Link to={`/${album.artistUri.split("at://")[1]}`}> 68 68 <LabelSmall className="!text-[var(--color-text-muted)]"> 69 69 {album.artist} 70 70 </LabelSmall> 71 71 </Link> 72 72 )} 73 - {!album.artist_uri && ( 73 + {!album.artistUri && ( 74 74 <LabelSmall className="!text-[var(--color-text-muted)]"> 75 75 {album.artist} 76 76 </LabelSmall>
+18 -32
apps/web/src/pages/song/Song.tsx
··· 56 56 const Song = () => { 57 57 const { did, rkey } = useParams<{ did: string; rkey: string }>(); 58 58 59 - let uri = `${did}/app.rocksky.scrobble/${rkey}`; 59 + let uri = `at://${did}/app.rocksky.scrobble/${rkey}`; 60 60 61 61 if (window.location.pathname.includes("app.rocksky.song")) { 62 - uri = `${did}/app.rocksky.song/${rkey}`; 62 + uri = `at://${did}/app.rocksky.song/${rkey}`; 63 63 } 64 64 if (window.location.pathname.includes("app.rocksky.scrobble")) { 65 - uri = `${did}/app.rocksky.scrobble/${rkey}`; 65 + uri = `at://${did}/app.rocksky.scrobble/${rkey}`; 66 66 } 67 67 68 68 const scrobbleResult = useFeedByUriQuery(uri); 69 69 const songResult = useSongByUriQuery(uri); 70 70 71 71 const artistTracksResult = useArtistTracksQuery( 72 - songResult.data?.artistUri?.split("at://")[1] || 73 - scrobbleResult.data?.artistUri?.split("at://")[1], 72 + songResult.data?.artistUri || scrobbleResult.data?.artistUri, 74 73 5 75 74 ); 76 75 const artistAlbumResult = useArtistAlbumsQuery( 77 - songResult.data?.artistUri?.split("at://")[1] || 78 - scrobbleResult.data?.artistUri?.split("at://")[1], 76 + songResult.data?.artistUri || scrobbleResult.data?.artistUri, 79 77 10 80 78 ); 81 79 ··· 100 98 id: string; 101 99 title: string; 102 100 artist: string; 103 - album_art: string; 104 - artist_uri: string; 101 + albumArt: string; 102 + artistUri: string; 105 103 uri: string; 106 104 }[] 107 105 >([]); ··· 162 160 id: x.id, 163 161 title: x.title, 164 162 artist: x.artist, 165 - albumArtist: x.album_artist, 166 - albumArt: x.album_art, 163 + albumArtist: x.albumArtist, 164 + albumArt: x.albumArt, 167 165 uri: x.uri, 168 - scrobbles: x.play_count, 169 - albumUri: x.album_uri, 170 - artistUri: x.artist_uri, 166 + artistUri: x.artistUri, 167 + scrobbles: x.playCount, 171 168 })) 172 169 ); 173 170 // eslint-disable-next-line react-hooks/exhaustive-deps ··· 182 179 return; 183 180 } 184 181 185 - setTopAlbums( 186 - artistAlbumResult.data.map((x) => ({ 187 - id: x.id, 188 - title: x.title, 189 - artist: x.artist, 190 - album_art: x.album_art, 191 - artist_uri: x.artist_uri!, 192 - uri: x.uri, 193 - })) 194 - ); 182 + setTopAlbums(artistAlbumResult.data); 195 183 // eslint-disable-next-line react-hooks/exhaustive-deps 196 184 }, [artistAlbumResult.data, artistAlbumResult.isLoading]); 197 185 ··· 315 303 </div> 316 304 </Group> 317 305 318 - { 319 - // eslint-disable-next-line @typescript-eslint/no-explicit-any 320 - song?.tags.map((tag: any) => ( 321 - <Tag closeable={false} kind={KIND.purple}> 322 - {tag} 323 - </Tag> 324 - )) 325 - } 306 + {// eslint-disable-next-line @typescript-eslint/no-explicit-any 307 + song?.tags.map((tag: any) => ( 308 + <Tag closeable={false} kind={KIND.purple}> 309 + {tag} 310 + </Tag> 311 + ))} 326 312 327 313 {song?.lyrics && ( 328 314 <>