Something went wrong. Try again.
A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app
spotify atproto lastfm musicbrainz scrobbling listenbrainz
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309import { z } from "zod";
export namespace WebScrobbler { /* -------------------------------- Connector -------------------------------- */
export const ConnectorSchema = z.object({ id: z.string(), js: z.string(), label: z.string(), matches: z.array(z.string()), });
/* ----------------------- IsRegrexEditedByUser ----------------------- */
export const IsRegrexEditedByUserSchema = z.object({ album: z.boolean(), albumArtist: z.boolean(), artist: z.boolean(), track: z.boolean(), });
/* ---------------------------------- Flags ---------------------------------- */
export const FlagsSchema = z.object({ finishedProcessing: z.boolean(), hasBlockedTag: z.boolean(), isAlbumFetched: z.boolean(), isCorrectedByUser: z.boolean(), isLovedInService: z.boolean().optional(), isMarkedAsPlaying: z.boolean(), isRegexEditedByUser: IsRegrexEditedByUserSchema, isReplaying: z.boolean(), isScrobbled: z.boolean(), isSkipped: z.boolean(), isValid: z.boolean(), });
/* -------------------------------- Metadata -------------------------------- */
export const MetadataSchema = z.object({ albumUrl: z.string().url().optional(), artistUrl: z.string().url().optional(), label: z.string(), startTimestamp: z.number().int().nonnegative(), trackUrl: z.string().url().optional(), userPlayCount: z.number().int().nonnegative().optional(), userloved: z.boolean().optional(), });
/* -------------------------------- NoRegex -------------------------------- */
export const NoRegexSchema = z.object({ album: z.string().optional(), albumArtist: z.string().optional(), artist: z.string(), duration: z.number().int().nonnegative().optional(), track: z.string(), });
/* ---------------------------------- Parsed --------------------------------- */
export const ParsedSchema = z.object({ album: z.string().optional(), albumArtist: z.string().optional(), artist: z.string(), currentTime: z.number().int().nonnegative().optional(), duration: z.number().int().nonnegative().optional(), isPlaying: z.boolean(), isPodcast: z.boolean(), originUrl: z.string().url().optional(), scrobblingDisallowedReason: z.string().optional(), track: z.string(), trackArt: z.string().url().optional(), uniqueID: z.string().optional(), });
/* ----------------------------------- Song ---------------------------------- */
export const SongSchema = z.object({ connector: ConnectorSchema, controllerTabId: z.number().int().nonnegative(), flags: FlagsSchema, metadata: MetadataSchema, noRegex: NoRegexSchema, parsed: ParsedSchema, });
/* -------------------------------- Processed -------------------------------- */
export const ProcessedSchema = z.object({ album: z.string(), albumArtist: z.string().optional(), artist: z.string(), duration: z.number().int().nonnegative(), track: z.string(), });
/* --------------------------------- Scrobble -------------------------------- */
export const ScrobbleSchema = z.object({ song: SongSchema, });
/* ------------------------------ ScrobbleRequest ----------------------------- */
export const ScrobbleRequestSchema = z.object({ data: ScrobbleSchema, eventName: z.string(), time: z.number().int().nonnegative(), });
export type Song = z.infer<typeof SongSchema>; export type Processed = z.infer<typeof ProcessedSchema>; export type Scrobble = z.infer<typeof ScrobbleSchema>; export type ScrobbleRequest = z.infer<typeof ScrobbleRequestSchema>; export type ScrobbleRequestData = z.infer< typeof ScrobbleRequestSchema >["data"];}
export namespace Lastfm { /* -------------------------------- Legacy API Schemas -------------------------------- */
export const LegacyNowPlayingRequestSchema = z.object({ s: z.string(), // session ID a: z.string(), // artist t: z.string(), // track b: z.string().optional(), // album l: z.string().optional(), // length in seconds n: z.string().optional(), // track number m: z.string().optional(), // MusicBrainz ID });
export const LegacySubmissionRequestSchema = z.object({ s: z.string(), // session ID "a[0]": z.string(), // artist "t[0]": z.string(), // track "i[0]": z.string(), // timestamp "o[0]": z.string().optional(), // source (P/R/E/L/U/B) "r[0]": z.string().optional(), // rating (L/B/S) "l[0]": z.string().optional(), // length in seconds "b[0]": z.string().optional(), // album "n[0]": z.string().optional(), // track number "m[0]": z.string().optional(), // MusicBrainz ID });
/* -------------------------------- Auth Request -------------------------------- */
export const AuthRequestSchema = z.object({ method: z.string(), api_key: z.string(), api_sig: z.string(), format: z.string().optional(), });
/* -------------------------------- Auth GetSession Request -------------------------------- */
export const AuthGetSessionRequestSchema = z.object({ method: z.literal("auth.getSession"), api_key: z.string(), token: z.string(), api_sig: z.string(), format: z.string().optional(), });
/* -------------------------------- Auth GetSession Response -------------------------------- */
export const AuthGetSessionResponseSchema = z.object({ session: z.object({ name: z.string(), key: z.string(), subscriber: z.number(), }), });
/* -------------------------------- Track Scrobble Request -------------------------------- */
export const TrackScrobbleRequestSchema = z.object({ method: z.literal("track.scrobble"), api_key: z.string(), api_sig: z.string(), sk: z.string(), "track[0]": z.string(), "artist[0]": z.string(), "timestamp[0]": z.string(), "album[0]": z.string().optional(), "albumArtist[0]": z.string().optional(), "duration[0]": z.string().optional(), format: z.string().optional(), });
/* -------------------------------- Track Update Now Playing Request -------------------------------- */
export const TrackUpdateNowPlayingRequestSchema = z.object({ method: z.literal("track.updateNowPlaying"), api_key: z.string(), api_sig: z.string(), sk: z.string(), track: z.string(), artist: z.string(), album: z.string().optional(), albumArtist: z.string().optional(), duration: z.string().optional(), format: z.string().optional(), });
/* -------------------------------- Scrobble Response -------------------------------- */
export const ScrobbleResponseSchema = z.object({ scrobbles: z.object({ "@attr": z.object({ accepted: z.number(), ignored: z.number(), }), scrobble: z .object({ artist: z.object({ "#text": z.string() }), track: z.object({ "#text": z.string() }), album: z.object({ "#text": z.string() }).optional(), albumArtist: z.object({ "#text": z.string() }).optional(), timestamp: z.string(), ignoredMessage: z .object({ code: z.string(), "#text": z.string() }) .optional(), }) .optional(), }), });
/* -------------------------------- Error Response -------------------------------- */
export const ErrorResponseSchema = z.object({ error: z.number(), message: z.string(), });
export type LegacyNowPlayingRequest = z.infer< typeof LegacyNowPlayingRequestSchema >; export type LegacySubmissionRequest = z.infer< typeof LegacySubmissionRequestSchema >; export type AuthRequest = z.infer<typeof AuthRequestSchema>; export type AuthGetSessionRequest = z.infer< typeof AuthGetSessionRequestSchema >; export type AuthGetSessionResponse = z.infer< typeof AuthGetSessionResponseSchema >; export type TrackScrobbleRequest = z.infer<typeof TrackScrobbleRequestSchema>; export type TrackUpdateNowPlayingRequest = z.infer< typeof TrackUpdateNowPlayingRequestSchema >; export type ScrobbleResponse = z.infer<typeof ScrobbleResponseSchema>; export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;}
export namespace Listenbrainz { /* -------------------------------- TrackMetadata -------------------------------- */
export const TrackMetadataSchema = z.object({ artist_name: z.string(), track_name: z.string(), release_name: z.string().optional(), additional_info: z.record(z.any()).optional(), });
/* -------------------------------- Payload -------------------------------- */
export const PayloadSchema = z.object({ listened_at: z.number().int().nonnegative().optional(), track_metadata: TrackMetadataSchema, });
/* -------------------------------- SubmitListensRequest -------------------------------- */
export const SubmitListensRequestSchema = z.object({ listen_type: z.enum(["single", "playing_now", "import"]), payload: z.array(PayloadSchema), });
/* -------------------------------- SubmitListensResponse -------------------------------- */
export const SubmitListensResponseSchema = z.object({ status: z.string(), code: z.number().int(), });
/* -------------------------------- ValidateTokenResponse -------------------------------- */
export const ValidateTokenResponseSchema = z.object({ code: z.number().int(), message: z.string(), valid: z.boolean(), user_name: z.string().optional(), });
export type TrackMetadata = z.infer<typeof TrackMetadataSchema>;
export type Payload = z.infer<typeof PayloadSchema>; export type SubmitListensRequest = z.infer<typeof SubmitListensRequestSchema>; export type SubmitListensResponse = z.infer< typeof SubmitListensResponseSchema >; export type ValidateTokenResponse = z.infer< typeof ValidateTokenResponseSchema >;}