forked from
rocksky.app/rocksky
A decentralized music tracking and discovery platform built on AT Protocol 馃幍
1import type { Context } from "../context.ts";
2import { eq } from "drizzle-orm";
3import { Effect, Match, pipe } from "effect";
4import tables from "../schema/mod.ts";
5
6export default function (ctx: Context, did?: string) {
7 return Effect.runPromise(
8 pipe(
9 retrieve({
10 ctx,
11 params: {
12 did,
13 },
14 }),
15 Effect.flatMap(presentation),
16 Effect.retry({ times: 3 }),
17 Effect.timeout("120 seconds"),
18 Effect.catchAll((error) =>
19 Effect.fail(new Error(`Failed to retrieve scrobbles chart: ${error}`)),
20 ),
21 ),
22 );
23}
24
25export type Params = {
26 did?: string;
27 artisturi?: string;
28 albumuri?: string;
29 songuri?: string;
30};
31
32const retrieve = ({ params, ctx }: { params: Params; ctx: Context }) => {
33 return Effect.tryPromise({
34 try: () => {
35 const match = Match.type<Params>().pipe(
36 Match.when({ did: (did) => !!did }, ({ did }) =>
37 ctx.analytics.post("library.getScrobblesPerDay", {
38 user_did: did,
39 }),
40 ),
41 Match.when({ artisturi: (uri) => !!uri }, ({ artisturi }) =>
42 ctx.analytics.post("library.getArtistScrobbles", {
43 artist_id: artisturi,
44 }),
45 ),
46 Match.when({ albumuri: (uri) => !!uri }, ({ albumuri }) =>
47 ctx.analytics.post("library.getAlbumScrobbles", {
48 album_id: albumuri,
49 }),
50 ),
51 Match.when(
52 { songuri: (uri) => !!uri && uri.includes("app.rocksky.scrobble") },
53 ({ songuri }) =>
54 ctx.db
55 .select()
56 .from(tables.scrobbles)
57 .leftJoin(
58 tables.tracks,
59 eq(tables.scrobbles.trackId, tables.tracks.id),
60 )
61 .where(eq(tables.scrobbles.uri, songuri))
62 .execute()
63 .then(([row]) => row?.tracks?.uri)
64 .then((uri) =>
65 ctx.analytics.post("library.getTrackScrobbles", {
66 track_id: uri,
67 }),
68 ),
69 ),
70 Match.when(
71 { songuri: (uri) => !!uri && !uri.includes("app.rocksky.scrobble") },
72 ({ songuri }) =>
73 ctx.analytics.post("library.getTrackScrobbles", {
74 track_id: songuri,
75 }),
76 ),
77 Match.orElse(() =>
78 ctx.analytics.post("library.getScrobblesPerDay", {}),
79 ),
80 );
81
82 return match(params);
83 },
84 catch: (error) => new Error(`Failed to retrieve scrobbles chart: ${error}`),
85 });
86};
87
88interface ChartsView {
89 scrobbles: any;
90}
91
92const presentation = ({
93 data,
94}: {
95 data: any;
96}): Effect.Effect<ChartsView, never> => {
97 return Effect.sync(() => ({
98 scrobbles: data,
99 }));
100};