A decentralized music tracking and discovery platform built on AT Protocol 🎵
listenbrainz spotify atproto lastfm musicbrainz scrobbling

Add getFeedGenerators endpoint

Query feeds with a left join to users, limit results by params.size, and
present data as FeedGeneratorsView

Changed files
+58
apps
api
src
xrpc
app
rocksky
+56
apps/api/src/xrpc/app/rocksky/feed/getFeedGenerators.ts
···
··· 1 + import { Server } from "lexicon"; 2 + import { Context } from "context"; 3 + import { Effect, pipe } from "effect"; 4 + import type { FeedGeneratorsView } from "lexicon/types/app/rocksky/feed/defs"; 5 + import type { QueryParams } from "lexicon/types/app/rocksky/feed/getFeedGenerators"; 6 + import tables from "schema"; 7 + import { SelectFeed } from "schema/feeds"; 8 + import { eq } from "drizzle-orm"; 9 + import { SelectUser } from "schema/users"; 10 + 11 + export default function (server: Server, ctx: Context) { 12 + const getFeedGenerators = (params) => 13 + pipe({ params, ctx }, retrieve, Effect.flatMap(presentation)); 14 + server.app.rocksky.feed.getFeedGenerators({ 15 + handler: async ({ params }) => { 16 + const result = await Effect.runPromise(getFeedGenerators(params)); 17 + return { 18 + encoding: "application/json", 19 + body: result, 20 + }; 21 + }, 22 + }); 23 + } 24 + 25 + const retrieve = ({ params, ctx }: { params: QueryParams; ctx: Context }) => { 26 + return Effect.tryPromise({ 27 + try: () => 28 + ctx.db 29 + .select() 30 + .from(tables.feeds) 31 + .leftJoin(tables.users, eq(tables.feeds.userId, tables.users.id)) 32 + .limit(params.size || 100) 33 + .execute(), 34 + catch: (error) => Effect.fail(error), 35 + }); 36 + }; 37 + 38 + const presentation = ( 39 + data: { users: SelectUser; feeds: SelectFeed }[], 40 + ): Effect.Effect<FeedGeneratorsView, never> => { 41 + return Effect.sync(() => ({ 42 + feeds: data.map(({ users, feeds }) => ({ 43 + id: feeds.id, 44 + name: feeds.displayName, 45 + description: feeds.description, 46 + avatar: feeds.avatar, 47 + uri: feeds.uri, 48 + creator: { 49 + id: users.id, 50 + did: users.did, 51 + handle: users.handle, 52 + displayName: users.displayName, 53 + }, 54 + })), 55 + })); 56 + };
+2
apps/api/src/xrpc/index.ts
··· 72 import spotifyPrevious from "./app/rocksky/spotify/previous"; 73 import spotifySeek from "./app/rocksky/spotify/seek"; 74 import getStats from "./app/rocksky/stats/getStats"; 75 76 export default function (server: Server, ctx: Context) { 77 // app.rocksky ··· 147 insertFiles(server, ctx); 148 removePlaylist(server, ctx); 149 startPlaylist(server, ctx); 150 151 return server; 152 }
··· 72 import spotifyPrevious from "./app/rocksky/spotify/previous"; 73 import spotifySeek from "./app/rocksky/spotify/seek"; 74 import getStats from "./app/rocksky/stats/getStats"; 75 + import getFeedGenerators from "./app/rocksky/feed/getFeedGenerators"; 76 77 export default function (server: Server, ctx: Context) { 78 // app.rocksky ··· 148 insertFiles(server, ctx); 149 removePlaylist(server, ctx); 150 startPlaylist(server, ctx); 151 + getFeedGenerators(server, ctx); 152 153 return server; 154 }