A decentralized music tracking and discovery platform built on AT Protocol 馃幍
at main 106 lines 2.8 kB view raw
1import { TID } from "@atproto/common"; 2import { consola } from "consola"; 3import chalk from "chalk"; 4import type { Context } from "context"; 5import { eq } from "drizzle-orm"; 6import * as Playlist from "lexicon/types/app/rocksky/playlist"; 7import { createAgent } from "lib/agent"; 8import { StringCodec } from "nats"; 9import tables from "schema"; 10 11export function onNewPlaylist(ctx: Context) { 12 const sc = StringCodec(); 13 const sub = ctx.nc.subscribe("rocksky.playlist"); 14 (async () => { 15 for await (const m of sub) { 16 const payload: { 17 id: string; 18 did: string; 19 } = JSON.parse(sc.decode(m.data)); 20 consola.info( 21 `New playlist: ${chalk.cyan(payload.did)} - ${chalk.greenBright(payload.id)}`, 22 ); 23 await putPlaylistRecord(ctx, payload); 24 } 25 })(); 26} 27 28async function putPlaylistRecord( 29 ctx: Context, 30 payload: { id: string; did: string }, 31) { 32 const agent = await createAgent(ctx.oauthClient, payload.did); 33 34 if (!agent) { 35 consola.error( 36 `Failed to create agent, skipping playlist: ${chalk.cyan(payload.id)} for ${chalk.greenBright(payload.did)}`, 37 ); 38 return; 39 } 40 41 const [playlist] = await ctx.db 42 .select() 43 .from(tables.playlists) 44 .where(eq(tables.playlists.id, payload.id)) 45 .execute(); 46 47 let rkey = TID.nextStr(); 48 49 if (playlist.uri) { 50 rkey = playlist.uri.split("/").pop(); 51 } 52 53 const record: { 54 $type: string; 55 name: string; 56 description?: string; 57 createdAt: string; 58 pictureUrl?: string; 59 spotifyLink?: string; 60 tidalLink?: string; 61 appleMusicLink?: string; 62 youtubeLink?: string; 63 } = { 64 $type: "app.rocksky.playlist", 65 name: playlist.name, 66 description: playlist.description, 67 createdAt: new Date().toISOString(), 68 pictureUrl: playlist.picture, 69 spotifyLink: playlist.spotifyLink, 70 }; 71 72 if (!Playlist.validateRecord(record)) { 73 consola.error(`Invalid record: ${chalk.redBright(JSON.stringify(record))}`); 74 return; 75 } 76 77 try { 78 const res = await agent.com.atproto.repo.putRecord({ 79 repo: agent.assertDid, 80 collection: "app.rocksky.playlist", 81 rkey, 82 record, 83 validate: false, 84 }); 85 const uri = res.data.uri; 86 consola.info(`Playlist record created: ${chalk.greenBright(uri)}`); 87 await ctx.db 88 .update(tables.playlists) 89 .set({ uri }) 90 .where(eq(tables.playlists.id, payload.id)) 91 .execute(); 92 } catch (e) { 93 consola.error(`Failed to put record: ${chalk.redBright(e.message)}`); 94 } 95 96 const [updatedPlaylist] = await ctx.db 97 .select() 98 .from(tables.playlists) 99 .where(eq(tables.playlists.id, payload.id)) 100 .execute(); 101 102 await ctx.meilisearch.post( 103 `indexes/playlists/documents?primaryKey=id`, 104 updatedPlaylist, 105 ); 106}