A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app
spotify atproto lastfm musicbrainz scrobbling listenbrainz
98
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add top tracks table and date range params

Render top tracks as a responsive table in the embed page, using v4
Link tracks and artists to rocksky; show album art with fallback UI
Update API call to include startDate/endDate using getLastDays(7)

+50
+46
apps/embed/src/embeds/TopTracksEmbedPage.tsx
··· 1 + import { v4 } from "uuid"; 1 2 import Header from "../components/Header"; 2 3 import type { Profile } from "../types/profile"; 3 4 import type { Track } from "../types/track"; ··· 12 13 <div className="p-[15px]"> 13 14 <Header profile={props.profile} /> 14 15 <h2 className="m-[0px]">Top Tracks</h2> 16 + 17 + <div className="w-full overflow-x-auto"> 18 + <table className="table-borderless table"> 19 + <tbody> 20 + {props.tracks.map((track, index) => ( 21 + <tr key={v4()}> 22 + <td> 23 + <div className="flex flex-row items-center"> 24 + <div className="mr-[20px] min-w-[30px]">{index + 1}</div> 25 + <a 26 + href={`https://rocksky.app/${track.uri?.split("at://")[1]?.replace("app.rocksky.", "")}`} 27 + target="_blank" 28 + className="flex flex-row items-center no-underline text-inherit" 29 + > 30 + {track.albumArt && ( 31 + <img 32 + className="max-w-[60px] max-h-[60px] mr-[20px] rounded-[5px]" 33 + src={track.albumArt!} 34 + /> 35 + )} 36 + {!track.albumArt && ( 37 + <div className="w-[60px] h-[60px] bg-[var(--color-avatar-background)] flex items-center justify-center mr-[20px]"> 38 + <div className="h-[30px] w-[30px]"></div> 39 + </div> 40 + )} 41 + <div> 42 + <div>{track.title}</div> 43 + <a 44 + href={`https://rocksky.app/${track.artistUri.split("at://")[1]?.replace("app.rocksky.", "")}`} 45 + target="_blank" 46 + className="no-underline text-inherit" 47 + > 48 + <div className="font-rockford-light opacity-60"> 49 + {track.albumArtist} 50 + </div> 51 + </a> 52 + </div> 53 + </a> 54 + </div> 55 + </td> 56 + </tr> 57 + ))} 58 + </tbody> 59 + </table> 60 + </div> 15 61 </div> 16 62 ); 17 63 }
+4
apps/embed/src/xrpc/getTopTracks.ts
··· 1 1 import { ROCKSKY_API_URL } from "../consts"; 2 + import getLastDays from "../lib/getLastDays"; 2 3 import type { Track } from "../types/track"; 3 4 4 5 export default async function getTopAlbums(handle: string) { 6 + const [start, end] = getLastDays(7); 5 7 const url = new URL( 6 8 `${ROCKSKY_API_URL}/xrpc/app.rocksky.actor.getActorSongs`, 7 9 ); 8 10 url.searchParams.append("did", handle); 11 + url.searchParams.append("startDate", start.toISOString()); 12 + url.searchParams.append("endDate", end.toISOString()); 9 13 url.searchParams.append("limit", "20"); 10 14 11 15 const res = await fetch(url);