A decentralized music tracking and discovery platform built on AT Protocol 馃幍
rocksky.app
spotify
atproto
lastfm
musicbrainz
scrobbling
listenbrainz
1import { client } from ".";
2
3export const getScrobbleByUri = async (uri: string) => {
4 if (uri.includes("app.rocksky.song")) {
5 return null;
6 }
7 const response = await client.get("/xrpc/app.rocksky.scrobble.getScrobble", {
8 params: { uri },
9 });
10
11 if (response.status !== 200) {
12 return null;
13 }
14
15 return {
16 id: response.data?.id,
17 title: response.data?.title,
18 artist: response.data?.artist,
19 albumArtist: response.data?.albumArtist,
20 album: response.data?.album,
21 cover: response.data?.cover,
22 tags: response.data?.tags,
23 artistUri: response.data?.artistUri,
24 albumUri: response.data?.albumUri,
25 listeners: response.data?.listeners || 1,
26 scrobbles: response.data?.scrobbles || 1,
27 lyrics: response.data?.lyrics,
28 spotifyLink: response.data?.spotifyLink,
29 composer: response.data?.composer,
30 uri: response.data?.uri,
31 artists: response.data?.artists,
32 };
33};
34
35export const getFeedGenerators = async () => {
36 const response = await client.get<{
37 feeds: {
38 id: string;
39 name: string;
40 uri: string;
41 description: string;
42 did: string;
43 avatar?: string;
44 creator: {
45 avatar?: string;
46 displayName: string;
47 handle: string;
48 did: string;
49 id: string;
50 };
51 }[];
52 }>("/xrpc/app.rocksky.feed.getFeedGenerators");
53 if (response.status !== 200) {
54 return null;
55 }
56 return response.data;
57};
58
59export const getFeed = async (uri: string, limit?: number, cursor?: string) => {
60 const response = await client.get<{
61 feed: {
62 scrobble: {
63 title: string;
64 artist: string;
65 albumArtist: string;
66 album: string;
67 trackNumber: number;
68 duration: number;
69 mbId: string | null;
70 youtubeLink: string | null;
71 spotifyLink: string | null;
72 appleMusicLink: string | null;
73 tidalLink: string | null;
74 sha256: string;
75 discNumber: number;
76 composer: string | null;
77 genre: string | null;
78 label: string | null;
79 copyrightMessage: string | null;
80 uri: string;
81 albumUri: string;
82 artistUri: string;
83 trackUri: string;
84 xataVersion: number;
85 cover: string;
86 date: string;
87 user: string;
88 userDisplayName: string;
89 userAvatar: string;
90 tags: string[];
91 likesCount: number;
92 liked: boolean;
93 id: string;
94 };
95 }[];
96 cursor?: string;
97 }>("/xrpc/app.rocksky.feed.getFeed", {
98 params: {
99 feed: uri,
100 limit,
101 cursor,
102 },
103 headers: {
104 Authorization: localStorage.getItem("token")
105 ? `Bearer ${localStorage.getItem("token")}`
106 : undefined,
107 },
108 });
109
110 if (response.status !== 200) {
111 return { songs: [], cursor: undefined };
112 }
113
114 return {
115 songs: response.data.feed.map(({ scrobble }) => scrobble),
116 cursor: response.data.cursor,
117 };
118};
119
120export const getScrobbles = async (
121 did: string,
122 following: boolean = false,
123 offset: number = 0,
124 limit: number = 50,
125) => {
126 const response = await client.get<{
127 scrobbles: {
128 title: string;
129 artist: string;
130 albumArtist: string;
131 album: string;
132 trackNumber: number;
133 duration: number;
134 mbId: string | null;
135 youtubeLink: string | null;
136 spotifyLink: string | null;
137 appleMusicLink: string | null;
138 tidalLink: string | null;
139 sha256: string;
140 discNumber: number;
141 composer: string | null;
142 genre: string | null;
143 label: string | null;
144 copyrightMessage: string | null;
145 uri: string;
146 albumUri: string;
147 artistUri: string;
148 trackUri: string;
149 xataVersion: number;
150 cover: string;
151 date: string;
152 user: string;
153 userDisplayName: string;
154 userAvatar: string;
155 tags: string[];
156 likesCount: number;
157 liked: boolean;
158 id: string;
159 }[];
160 }>("/xrpc/app.rocksky.scrobble.getScrobbles", {
161 params: {
162 did,
163 following,
164 offset,
165 limit,
166 },
167 headers: {
168 Authorization: localStorage.getItem("token")
169 ? `Bearer ${localStorage.getItem("token")}`
170 : undefined,
171 },
172 });
173
174 if (response.status !== 200) {
175 return { scrobbles: [] };
176 }
177
178 return {
179 scrobbles: response.data.scrobbles,
180 };
181};