A decentralized music tracking and discovery platform built on AT Protocol 🎵

feat: add publishStatus function to create and publish actor status

+56
+56
apps/api/src/tealfm/index.ts
··· 1 1 import type { Agent } from "@atproto/api"; 2 2 import { TID } from "@atproto/common"; 3 3 import chalk from "chalk"; 4 + import type * as Status from "lexicon/types/fm/teal/alpha/actor/status"; 5 + import type { PlayView } from "lexicon/types/fm/teal/alpha/feed/defs"; 4 6 import * as Play from "lexicon/types/fm/teal/alpha/feed/play"; 5 7 import type { MusicbrainzTrack } from "types/track"; 6 8 ··· 76 78 }); 77 79 const uri = res.data.uri; 78 80 console.log(`tealfm Play record created at ${uri}`); 81 + 82 + await publishStatus(agent, track, duration); 79 83 } catch (error) { 80 84 console.error("Error publishing teal.fm record:", error); 85 + } 86 + } 87 + 88 + async function publishStatus( 89 + agent: Agent, 90 + track: MusicbrainzTrack, 91 + duration: number 92 + ) { 93 + const item: PlayView = { 94 + trackName: track.name, 95 + duration, 96 + playedTime: track.timestamp, 97 + artists: track.artist.map((artist) => ({ 98 + artistMbid: artist.mbid, 99 + artistName: artist.name, 100 + })), 101 + releaseMbid: track.releaseMBID, 102 + releaseName: track.album, 103 + recordingMbId: track.trackMBID, 104 + submissionClientAgent: SUBMISSION_CLIENT_AGENT, 105 + }; 106 + const nowSec = Math.floor(Date.now() / 1000); 107 + const expirySec = nowSec + 10 * 60; // 10 minutes from now 108 + const record: Status.Record = { 109 + $type: "fm.teal.alpha.actor.status", 110 + item, 111 + time: String(nowSec), 112 + expiry: String(expirySec), 113 + }; 114 + const swapRecord = await getStatusSwapRecord(agent); 115 + const res = await agent.com.atproto.repo.putRecord({ 116 + repo: agent.assertDid, 117 + collection: "fm.teal.alpha.actor.status", 118 + rkey: "self", 119 + record, 120 + swapRecord, 121 + }); 122 + console.log(`tealfm Status record published at ${res.data.uri}`); 123 + } 124 + 125 + async function getStatusSwapRecord(agent: Agent): Promise<string | undefined> { 126 + try { 127 + const res = await agent.com.atproto.repo.getRecord({ 128 + repo: agent.assertDid, 129 + collection: "fm.teal.alpha.actor.status", 130 + rkey: "self", 131 + }); 132 + return res.data.cid; 133 + } catch (err) { 134 + const status = err?.response?.status ?? err?.status; 135 + if (status === 400) return undefined; 136 + throw err; 81 137 } 82 138 } 83 139