@rocksky/sdk 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -5
- package/dist/agent.d.ts +5 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/client.d.ts +146 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3904 -3575
- package/package.json +1 -1
- package/src/agent.ts +46 -0
- package/src/client.ts +339 -14
- package/src/index.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rocksky/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "TypeScript SDK for Rocksky — built on atcute: AppView reads, AT Protocol PDS writes (scrobble, like, follow, shout), a local dedup index, and Jetstream real-time sync.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/src/agent.ts
CHANGED
|
@@ -153,6 +153,52 @@ export class Agent {
|
|
|
153
153
|
return uri;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/** Scrobble from just a title + artist (album optional, plus optional
|
|
157
|
+
* `mbId`/`isrc` anchors): resolve full metadata via `matchSong`, then write.
|
|
158
|
+
* Matching uses the public AppView unless `appview` is given; an empty match
|
|
159
|
+
* falls back to a minimal record. */
|
|
160
|
+
async scrobbleMatch(
|
|
161
|
+
title: string,
|
|
162
|
+
artist: string,
|
|
163
|
+
album?: string,
|
|
164
|
+
mbId?: string,
|
|
165
|
+
isrc?: string,
|
|
166
|
+
appview?: string,
|
|
167
|
+
): Promise<string> {
|
|
168
|
+
const { RockskyClient } = await import("./client.js");
|
|
169
|
+
const m = (await new RockskyClient(appview).matchSong(title, artist, mbId, isrc)) as Record<
|
|
170
|
+
string,
|
|
171
|
+
unknown
|
|
172
|
+
> | null;
|
|
173
|
+
const s = (k: string): string | undefined => (m && typeof m[k] === "string" ? (m[k] as string) : undefined);
|
|
174
|
+
const n = (k: string): number | undefined => (m && typeof m[k] === "number" ? (m[k] as number) : undefined);
|
|
175
|
+
const rec: ScrobbleInput =
|
|
176
|
+
m && m.title
|
|
177
|
+
? {
|
|
178
|
+
title: s("title")!,
|
|
179
|
+
artist: s("artist")!,
|
|
180
|
+
albumArtist: s("albumArtist") ?? artist,
|
|
181
|
+
album: album ?? s("album") ?? "",
|
|
182
|
+
albumArtUrl: s("albumArt"),
|
|
183
|
+
duration: n("duration") ?? 0,
|
|
184
|
+
trackNumber: n("trackNumber"),
|
|
185
|
+
discNumber: n("discNumber"),
|
|
186
|
+
year: n("year"),
|
|
187
|
+
releaseDate: s("releaseDate"),
|
|
188
|
+
genre: s("genre"),
|
|
189
|
+
composer: s("composer"),
|
|
190
|
+
label: s("label"),
|
|
191
|
+
mbid: s("mbId"),
|
|
192
|
+
isrc: s("isrc"),
|
|
193
|
+
spotifyLink: s("spotifyLink"),
|
|
194
|
+
youtubeLink: s("youtubeLink"),
|
|
195
|
+
tidalLink: s("tidalLink"),
|
|
196
|
+
appleMusicLink: s("appleMusicLink"),
|
|
197
|
+
}
|
|
198
|
+
: { title, artist, album: album ?? "", albumArtist: artist, duration: 0 };
|
|
199
|
+
return this.scrobble(rec);
|
|
200
|
+
}
|
|
201
|
+
|
|
156
202
|
/** Create a canonical track record (app.rocksky.song). */
|
|
157
203
|
async createSong(rec: SongInput): Promise<string> {
|
|
158
204
|
const record = { ...rec, createdAt: rec.createdAt || nowISO() };
|
package/src/client.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Client, simpleFetchHandler } from "@atcute/client";
|
|
|
2
2
|
|
|
3
3
|
import { RockskyError } from "./errors.js";
|
|
4
4
|
import type {
|
|
5
|
+
ActorProfileViewBasic,
|
|
5
6
|
ActorProfileViewDetailed,
|
|
6
7
|
AlbumViewBasic,
|
|
7
8
|
ArtistViewBasic,
|
|
@@ -9,14 +10,48 @@ import type {
|
|
|
9
10
|
GetActorAlbumsOutput,
|
|
10
11
|
GetActorArtistsOutput,
|
|
11
12
|
GetActorScrobblesOutput,
|
|
12
|
-
GetActorSongsOutput,
|
|
13
|
-
GetTopArtistsOutput,
|
|
14
|
-
GetTopTracksOutput,
|
|
15
13
|
ScrobbleViewBasic,
|
|
16
14
|
SongViewBasic,
|
|
17
15
|
StatsGlobalStatsView,
|
|
18
16
|
} from "./generated/types.js";
|
|
19
17
|
|
|
18
|
+
/**
|
|
19
|
+
* A typed date window for the `top*` charts. Build one with the {@link Interval}
|
|
20
|
+
* factories; `range` bounds are RFC-3339 datetimes.
|
|
21
|
+
*/
|
|
22
|
+
export interface DateInterval {
|
|
23
|
+
startDate?: string;
|
|
24
|
+
endDate?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function since(days = 0, months = 0, years = 0): DateInterval {
|
|
28
|
+
const now = new Date();
|
|
29
|
+
const start = new Date(now);
|
|
30
|
+
start.setUTCFullYear(start.getUTCFullYear() - years);
|
|
31
|
+
start.setUTCMonth(start.getUTCMonth() - months);
|
|
32
|
+
start.setUTCDate(start.getUTCDate() - days);
|
|
33
|
+
return { startDate: start.toISOString(), endDate: now.toISOString() };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Factories for {@link DateInterval} windows used by the `top*Interval` charts. */
|
|
37
|
+
export const Interval = {
|
|
38
|
+
/** No bounds — the all-time chart. */
|
|
39
|
+
allTime: (): DateInterval => ({}),
|
|
40
|
+
/** The last `n` days ending now. */
|
|
41
|
+
lastDays: (n: number): DateInterval => since(n),
|
|
42
|
+
/** The last `n` weeks ending now. */
|
|
43
|
+
lastWeeks: (n: number): DateInterval => since(7 * n),
|
|
44
|
+
/** The last `n` months ending now. */
|
|
45
|
+
lastMonths: (n: number): DateInterval => since(0, n),
|
|
46
|
+
/** The last `n` years ending now. */
|
|
47
|
+
lastYears: (n: number): DateInterval => since(0, 0, n),
|
|
48
|
+
/** An explicit closed `[start, end]` window. */
|
|
49
|
+
range: (start: Date, end: Date): DateInterval => ({
|
|
50
|
+
startDate: start.toISOString(),
|
|
51
|
+
endDate: end.toISOString(),
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
|
|
20
55
|
/** The default public Rocksky AppView base URL. */
|
|
21
56
|
export const DEFAULT_APPVIEW = "https://api.rocksky.app";
|
|
22
57
|
|
|
@@ -24,9 +59,23 @@ export const DEFAULT_APPVIEW = "https://api.rocksky.app";
|
|
|
24
59
|
export class RockskyClient {
|
|
25
60
|
private rpc: Client;
|
|
26
61
|
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Build a read client against an AppView base URL (defaults to
|
|
64
|
+
* {@link DEFAULT_APPVIEW}). Pass `token` to send it as
|
|
65
|
+
* `Authorization: Bearer <token>` on every read — needed only for auth-gated
|
|
66
|
+
* queries.
|
|
67
|
+
*/
|
|
68
|
+
constructor(appview: string = DEFAULT_APPVIEW, token?: string) {
|
|
69
|
+
let handler = simpleFetchHandler({ service: appview });
|
|
70
|
+
if (token) {
|
|
71
|
+
const inner = handler;
|
|
72
|
+
handler = ((pathname: string, init?: RequestInit) =>
|
|
73
|
+
inner(pathname, {
|
|
74
|
+
...init,
|
|
75
|
+
headers: { ...(init?.headers as Record<string, string>), authorization: `Bearer ${token}` },
|
|
76
|
+
})) as typeof handler;
|
|
77
|
+
}
|
|
78
|
+
this.rpc = new Client({ handler });
|
|
30
79
|
}
|
|
31
80
|
|
|
32
81
|
private async query<T>(nsid: string, params: Record<string, unknown>): Promise<T> {
|
|
@@ -54,14 +103,29 @@ export class RockskyClient {
|
|
|
54
103
|
return out.scrobbles ?? [];
|
|
55
104
|
}
|
|
56
105
|
|
|
106
|
+
/** Call any AppView read query by nsid; returns the raw JSON response. Every
|
|
107
|
+
* method here is sugar over this — use it for queries without a wrapper. */
|
|
108
|
+
get(nsid: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
109
|
+
return this.query(nsid, params);
|
|
110
|
+
}
|
|
111
|
+
|
|
57
112
|
/** An actor's most-played songs. */
|
|
58
113
|
async songs(actor: string, limit = 50, offset = 0): Promise<SongViewBasic[]> {
|
|
59
|
-
const out = await this.query<
|
|
114
|
+
const out = await this.query<{ tracks?: SongViewBasic[] }>("app.rocksky.actor.getActorSongs", {
|
|
60
115
|
did: actor,
|
|
61
116
|
limit,
|
|
62
117
|
offset,
|
|
63
118
|
});
|
|
64
|
-
return out.
|
|
119
|
+
return out.tracks ?? [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** An actor's loved (liked) songs. */
|
|
123
|
+
async lovedSongs(actor: string, limit = 50, offset = 0): Promise<SongViewBasic[]> {
|
|
124
|
+
const out = await this.query<{ tracks?: SongViewBasic[] }>(
|
|
125
|
+
"app.rocksky.actor.getActorLovedSongs",
|
|
126
|
+
{ did: actor, limit, offset },
|
|
127
|
+
);
|
|
128
|
+
return out.tracks ?? [];
|
|
65
129
|
}
|
|
66
130
|
|
|
67
131
|
/** An actor's most-played albums. */
|
|
@@ -84,18 +148,134 @@ export class RockskyClient {
|
|
|
84
148
|
return out.artists ?? [];
|
|
85
149
|
}
|
|
86
150
|
|
|
87
|
-
/** The platform-wide top tracks chart. */
|
|
88
|
-
|
|
89
|
-
|
|
151
|
+
/** The platform-wide top tracks chart (all-time). */
|
|
152
|
+
topTracks(limit = 50, offset = 0): Promise<SongViewBasic[]> {
|
|
153
|
+
return this.topTracksInterval(limit, offset, Interval.allTime());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The platform-wide top artists chart (all-time). */
|
|
157
|
+
topArtists(limit = 50, offset = 0): Promise<ArtistViewBasic[]> {
|
|
158
|
+
return this.topArtistsInterval(limit, offset, Interval.allTime());
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** The top tracks chart over a typed {@link DateInterval}. */
|
|
162
|
+
async topTracksInterval(limit: number, offset: number, interval: DateInterval): Promise<SongViewBasic[]> {
|
|
163
|
+
const out = await this.query<{ tracks?: SongViewBasic[] }>("app.rocksky.charts.getTopTracks", {
|
|
164
|
+
limit,
|
|
165
|
+
offset,
|
|
166
|
+
...interval,
|
|
167
|
+
});
|
|
90
168
|
return out.tracks ?? [];
|
|
91
169
|
}
|
|
92
170
|
|
|
93
|
-
/** The
|
|
94
|
-
async
|
|
95
|
-
const out = await this.query<
|
|
171
|
+
/** The top artists chart over a typed {@link DateInterval}. */
|
|
172
|
+
async topArtistsInterval(limit: number, offset: number, interval: DateInterval): Promise<ArtistViewBasic[]> {
|
|
173
|
+
const out = await this.query<{ artists?: ArtistViewBasic[] }>("app.rocksky.charts.getTopArtists", {
|
|
174
|
+
limit,
|
|
175
|
+
offset,
|
|
176
|
+
...interval,
|
|
177
|
+
});
|
|
96
178
|
return out.artists ?? [];
|
|
97
179
|
}
|
|
98
180
|
|
|
181
|
+
/** The album catalog, optionally filtered by `genre`. */
|
|
182
|
+
async catalogAlbums(limit = 50, offset = 0, genre?: string): Promise<AlbumViewBasic[]> {
|
|
183
|
+
const out = await this.query<{ albums?: AlbumViewBasic[] }>("app.rocksky.album.getAlbums", {
|
|
184
|
+
limit,
|
|
185
|
+
offset,
|
|
186
|
+
genre,
|
|
187
|
+
});
|
|
188
|
+
return out.albums ?? [];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** The artist catalog, optionally filtered by `genre`. */
|
|
192
|
+
async catalogArtists(limit = 50, offset = 0, genre?: string): Promise<ArtistViewBasic[]> {
|
|
193
|
+
const out = await this.query<{ artists?: ArtistViewBasic[] }>("app.rocksky.artist.getArtists", {
|
|
194
|
+
limit,
|
|
195
|
+
offset,
|
|
196
|
+
genre,
|
|
197
|
+
});
|
|
198
|
+
return out.artists ?? [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** The song catalog, optionally filtered by `genre`. */
|
|
202
|
+
async catalogSongs(limit = 50, offset = 0, genre?: string): Promise<SongViewBasic[]> {
|
|
203
|
+
const out = await this.query<{ tracks?: SongViewBasic[] }>("app.rocksky.song.getSongs", {
|
|
204
|
+
limit,
|
|
205
|
+
offset,
|
|
206
|
+
genre,
|
|
207
|
+
});
|
|
208
|
+
return out.tracks ?? [];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** An album's tracklist by album at:// URI. */
|
|
212
|
+
async albumTracks(uri: string): Promise<SongViewBasic[]> {
|
|
213
|
+
const out = await this.query<{ tracks?: SongViewBasic[] }>("app.rocksky.album.getAlbumTracks", { uri });
|
|
214
|
+
return out.tracks ?? [];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** An artist's albums by artist at:// URI. */
|
|
218
|
+
async artistAlbums(uri: string): Promise<AlbumViewBasic[]> {
|
|
219
|
+
const out = await this.query<{ albums?: AlbumViewBasic[] }>("app.rocksky.artist.getArtistAlbums", { uri });
|
|
220
|
+
return out.albums ?? [];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** An artist's top tracks by artist at:// URI. */
|
|
224
|
+
async artistTracks(uri: string, limit = 50, offset = 0): Promise<SongViewBasic[]> {
|
|
225
|
+
const out = await this.query<{ tracks?: SongViewBasic[] }>("app.rocksky.artist.getArtistTracks", {
|
|
226
|
+
uri,
|
|
227
|
+
limit,
|
|
228
|
+
offset,
|
|
229
|
+
});
|
|
230
|
+
return out.tracks ?? [];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** A social/global scrobbles feed. Pass `did` to scope to an actor and
|
|
234
|
+
* `following = true` for their follow graph. */
|
|
235
|
+
async scrobbleFeed(did?: string, following = false, limit = 50, offset = 0): Promise<ScrobbleViewBasic[]> {
|
|
236
|
+
const out = await this.query<{ scrobbles?: ScrobbleViewBasic[] }>("app.rocksky.scrobble.getScrobbles", {
|
|
237
|
+
did,
|
|
238
|
+
following,
|
|
239
|
+
limit,
|
|
240
|
+
offset,
|
|
241
|
+
});
|
|
242
|
+
return out.scrobbles ?? [];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** A single scrobble by its at:// URI. */
|
|
246
|
+
scrobble(uri: string): Promise<ScrobbleViewBasic> {
|
|
247
|
+
return this.query("app.rocksky.scrobble.getScrobble", { uri });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** The accounts `actor` follows. */
|
|
251
|
+
async follows(actor: string, limit = 50, cursor?: string): Promise<ActorProfileViewBasic[]> {
|
|
252
|
+
const out = await this.query<{ follows?: ActorProfileViewBasic[] }>("app.rocksky.graph.getFollows", {
|
|
253
|
+
actor,
|
|
254
|
+
limit,
|
|
255
|
+
cursor,
|
|
256
|
+
});
|
|
257
|
+
return out.follows ?? [];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** The accounts that follow `actor`. */
|
|
261
|
+
async followers(actor: string, limit = 50, cursor?: string): Promise<ActorProfileViewBasic[]> {
|
|
262
|
+
const out = await this.query<{ followers?: ActorProfileViewBasic[] }>("app.rocksky.graph.getFollowers", {
|
|
263
|
+
actor,
|
|
264
|
+
limit,
|
|
265
|
+
cursor,
|
|
266
|
+
});
|
|
267
|
+
return out.followers ?? [];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** Followers of `actor` that the viewer also follows. */
|
|
271
|
+
async knownFollowers(actor: string, limit = 50, cursor?: string): Promise<ActorProfileViewBasic[]> {
|
|
272
|
+
const out = await this.query<{ followers?: ActorProfileViewBasic[] }>(
|
|
273
|
+
"app.rocksky.graph.getKnownFollowers",
|
|
274
|
+
{ actor, limit, cursor },
|
|
275
|
+
);
|
|
276
|
+
return out.followers ?? [];
|
|
277
|
+
}
|
|
278
|
+
|
|
99
279
|
/** Full-text search across songs, albums, artists, playlists, actors. */
|
|
100
280
|
search(query: string): Promise<FeedSearchResultsView> {
|
|
101
281
|
return this.query("app.rocksky.feed.search", { query });
|
|
@@ -105,4 +285,149 @@ export class RockskyClient {
|
|
|
105
285
|
globalStats(): Promise<StatsGlobalStatsView> {
|
|
106
286
|
return this.query("app.rocksky.stats.getGlobalStats", {});
|
|
107
287
|
}
|
|
288
|
+
|
|
289
|
+
// ---- raw-JSON long tail: bespoke shapes returned as `unknown` ----------
|
|
290
|
+
|
|
291
|
+
/** A feed by its at:// URI (paginate via `cursor`). */
|
|
292
|
+
feed(feed: string, limit = 50, cursor?: string): Promise<unknown> {
|
|
293
|
+
return this.query("app.rocksky.feed.getFeed", { feed, limit, cursor });
|
|
294
|
+
}
|
|
295
|
+
/** A single album with its tracklist. */
|
|
296
|
+
album(uri: string): Promise<unknown> {
|
|
297
|
+
return this.query("app.rocksky.album.getAlbum", { uri });
|
|
298
|
+
}
|
|
299
|
+
/** A single artist with detail. */
|
|
300
|
+
artist(uri: string): Promise<unknown> {
|
|
301
|
+
return this.query("app.rocksky.artist.getArtist", { uri });
|
|
302
|
+
}
|
|
303
|
+
/** Resolve full canonical metadata for a bare title + artist
|
|
304
|
+
* (`app.rocksky.song.matchSong`); optionally anchor with `mbId` / `isrc`. */
|
|
305
|
+
matchSong(title: string, artist: string, mbId?: string, isrc?: string): Promise<unknown> {
|
|
306
|
+
return this.query("app.rocksky.song.matchSong", { title, artist, mbId, isrc });
|
|
307
|
+
}
|
|
308
|
+
/** A single song by at:// `uri` (or by `mbid` / `isrc` / `spotifyId`). */
|
|
309
|
+
song(opts: { uri?: string; mbid?: string; isrc?: string; spotifyId?: string }): Promise<unknown> {
|
|
310
|
+
return this.query("app.rocksky.song.getSong", opts);
|
|
311
|
+
}
|
|
312
|
+
/** An actor's playlists. */
|
|
313
|
+
actorPlaylists(actor: string, limit = 50, offset = 0): Promise<unknown> {
|
|
314
|
+
return this.query("app.rocksky.actor.getActorPlaylists", { did: actor, limit, offset });
|
|
315
|
+
}
|
|
316
|
+
/** Actors with similar taste to `actor`. */
|
|
317
|
+
neighbours(actor: string): Promise<unknown> {
|
|
318
|
+
return this.query("app.rocksky.actor.getActorNeighbours", { did: actor });
|
|
319
|
+
}
|
|
320
|
+
/** Music compatibility between the viewer and `actor` (auth). */
|
|
321
|
+
compatibility(actor: string): Promise<unknown> {
|
|
322
|
+
return this.query("app.rocksky.actor.getActorCompatibility", { did: actor });
|
|
323
|
+
}
|
|
324
|
+
/** An artist's all-time listeners. */
|
|
325
|
+
artistListeners(uri: string, limit = 50, offset = 0): Promise<unknown> {
|
|
326
|
+
return this.query("app.rocksky.artist.getArtistListeners", { uri, limit, offset });
|
|
327
|
+
}
|
|
328
|
+
/** An artist's recent listeners. */
|
|
329
|
+
artistRecentListeners(uri: string, limit = 50, offset = 0): Promise<unknown> {
|
|
330
|
+
return this.query("app.rocksky.artist.getArtistRecentListeners", { uri, limit, offset });
|
|
331
|
+
}
|
|
332
|
+
/** A song's recent listeners. */
|
|
333
|
+
songRecentListeners(uri: string, limit = 50, offset = 0): Promise<unknown> {
|
|
334
|
+
return this.query("app.rocksky.song.getSongRecentListeners", { uri, limit, offset });
|
|
335
|
+
}
|
|
336
|
+
/** A scrobble time-series chart. Scope with any of `did` / `artisturi` /
|
|
337
|
+
* `albumuri` / `songuri` / `genre` and bound with `from` / `to`. */
|
|
338
|
+
scrobblesChart(opts: {
|
|
339
|
+
did?: string;
|
|
340
|
+
artisturi?: string;
|
|
341
|
+
albumuri?: string;
|
|
342
|
+
songuri?: string;
|
|
343
|
+
genre?: string;
|
|
344
|
+
from?: string;
|
|
345
|
+
to?: string;
|
|
346
|
+
}): Promise<unknown> {
|
|
347
|
+
return this.query("app.rocksky.charts.getScrobblesChart", opts);
|
|
348
|
+
}
|
|
349
|
+
/** List the available feed generators. */
|
|
350
|
+
feedGenerators(size?: number): Promise<unknown> {
|
|
351
|
+
return this.query("app.rocksky.feed.getFeedGenerators", { size });
|
|
352
|
+
}
|
|
353
|
+
/** A single feed generator's record. */
|
|
354
|
+
feedGenerator(feed: string): Promise<unknown> {
|
|
355
|
+
return this.query("app.rocksky.feed.getFeedGenerator", { feed });
|
|
356
|
+
}
|
|
357
|
+
/** The stories row. */
|
|
358
|
+
stories(size?: number, feed?: string, following?: boolean): Promise<unknown> {
|
|
359
|
+
return this.query("app.rocksky.feed.getStories", { size, feed, following });
|
|
360
|
+
}
|
|
361
|
+
/** Track recommendations for `actor`. */
|
|
362
|
+
recommendations(actor: string, limit?: number): Promise<unknown> {
|
|
363
|
+
return this.query("app.rocksky.feed.getRecommendations", { did: actor, limit });
|
|
364
|
+
}
|
|
365
|
+
/** Artist recommendations for `actor`. */
|
|
366
|
+
artistRecommendations(actor: string, limit?: number): Promise<unknown> {
|
|
367
|
+
return this.query("app.rocksky.feed.getArtistRecommendations", { did: actor, limit });
|
|
368
|
+
}
|
|
369
|
+
/** Album recommendations for `actor`. */
|
|
370
|
+
albumRecommendations(actor: string, limit?: number): Promise<unknown> {
|
|
371
|
+
return this.query("app.rocksky.feed.getAlbumRecommendations", { did: actor, limit });
|
|
372
|
+
}
|
|
373
|
+
/** An actor's aggregate stats. */
|
|
374
|
+
stats(actor: string): Promise<unknown> {
|
|
375
|
+
return this.query("app.rocksky.stats.getStats", { did: actor });
|
|
376
|
+
}
|
|
377
|
+
/** An actor's year-in-review. */
|
|
378
|
+
wrapped(actor: string, year?: number): Promise<unknown> {
|
|
379
|
+
return this.query("app.rocksky.stats.getWrapped", { did: actor, year });
|
|
380
|
+
}
|
|
381
|
+
/** The viewer's configured scrobble mirror sources (auth). */
|
|
382
|
+
mirrorSources(): Promise<unknown> {
|
|
383
|
+
return this.query("app.rocksky.mirror.getMirrorSources", {});
|
|
384
|
+
}
|
|
385
|
+
/** What `actor` is playing now. */
|
|
386
|
+
currentlyPlaying(playerId?: string, actor?: string): Promise<unknown> {
|
|
387
|
+
return this.query("app.rocksky.player.getCurrentlyPlaying", { playerId, actor });
|
|
388
|
+
}
|
|
389
|
+
/** A player's playback queue. */
|
|
390
|
+
playbackQueue(playerId: string): Promise<unknown> {
|
|
391
|
+
return this.query("app.rocksky.player.getPlaybackQueue", { playerId });
|
|
392
|
+
}
|
|
393
|
+
/** What `actor` is playing now on Spotify. */
|
|
394
|
+
spotifyCurrentlyPlaying(actor: string): Promise<unknown> {
|
|
395
|
+
return this.query("app.rocksky.spotify.getCurrentlyPlaying", { actor });
|
|
396
|
+
}
|
|
397
|
+
/** The playlist catalog. */
|
|
398
|
+
playlists(limit = 50, offset = 0): Promise<unknown> {
|
|
399
|
+
return this.query("app.rocksky.playlist.getPlaylists", { limit, offset });
|
|
400
|
+
}
|
|
401
|
+
/** A single playlist with its items. */
|
|
402
|
+
playlist(uri: string): Promise<unknown> {
|
|
403
|
+
return this.query("app.rocksky.playlist.getPlaylist", { uri });
|
|
404
|
+
}
|
|
405
|
+
/** Shouts on an album. */
|
|
406
|
+
albumShouts(uri: string, limit = 50, offset = 0): Promise<unknown> {
|
|
407
|
+
return this.query("app.rocksky.shout.getAlbumShouts", { uri, limit, offset });
|
|
408
|
+
}
|
|
409
|
+
/** Shouts on an artist. */
|
|
410
|
+
artistShouts(uri: string, limit = 50, offset = 0): Promise<unknown> {
|
|
411
|
+
return this.query("app.rocksky.shout.getArtistShouts", { uri, limit, offset });
|
|
412
|
+
}
|
|
413
|
+
/** Shouts on a profile. */
|
|
414
|
+
profileShouts(actor: string, limit = 50, offset = 0): Promise<unknown> {
|
|
415
|
+
return this.query("app.rocksky.shout.getProfileShouts", { did: actor, limit, offset });
|
|
416
|
+
}
|
|
417
|
+
/** Shouts on a track. */
|
|
418
|
+
trackShouts(uri: string): Promise<unknown> {
|
|
419
|
+
return this.query("app.rocksky.shout.getTrackShouts", { uri });
|
|
420
|
+
}
|
|
421
|
+
/** Replies to a shout. */
|
|
422
|
+
shoutReplies(uri: string, limit = 50, offset = 0): Promise<unknown> {
|
|
423
|
+
return this.query("app.rocksky.shout.getShoutReplies", { uri, limit, offset });
|
|
424
|
+
}
|
|
425
|
+
/** An actor's Rockbox EQ / audio settings. */
|
|
426
|
+
audioSettings(actor: string): Promise<unknown> {
|
|
427
|
+
return this.query("app.rocksky.rockbox.getAudioSettings", { did: actor });
|
|
428
|
+
}
|
|
429
|
+
/** The viewer's API keys (auth). */
|
|
430
|
+
apikeys(limit = 50, offset = 0): Promise<unknown> {
|
|
431
|
+
return this.query("app.rocksky.apikey.getApikeys", { limit, offset });
|
|
432
|
+
}
|
|
108
433
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* ({@link Agent.syncRepo}) and kept live off the Jetstream firehose
|
|
9
9
|
* ({@link Agent.hydrateFromJetstream}).
|
|
10
10
|
*/
|
|
11
|
-
export { RockskyClient, DEFAULT_APPVIEW } from "./client.js";
|
|
11
|
+
export { RockskyClient, DEFAULT_APPVIEW, Interval } from "./client.js";
|
|
12
|
+
export type { DateInterval } from "./client.js";
|
|
12
13
|
export { Agent, type ScrobbleInput, type SongInput, type AlbumInput, type ArtistInput } from "./agent.js";
|
|
13
14
|
export { RockskyIndex, totalIndexed, type IndexStats } from "./dedup.js";
|
|
14
15
|
export { runJetstream, DEFAULT_JETSTREAM_SERVERS, type JetstreamOptions } from "./jetstream.js";
|