Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
Something went wrong. Try again.
4.5 kB · 122 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123import * as z from "zod";import {pollingOptionsSchema} from "../common.ts";import {commonSourceConfigSchema, commonSourceDataSchema, commonSourceOptionsSchema, type EnvSourceSchema} from "./index.ts";
export const spotifySourceDataSchema = z.object({ ...commonSourceDataSchema.shape, ...pollingOptionsSchema.shape, /** * spotify client id * * @examples ["787c921a2a2ab42320831aba0c8f2fc2"] * */ clientId: z.string().meta({ description: "spotify client id", examples: ["787c921a2a2ab42320831aba0c8f2fc2"] }), /** * spotify client secret * * @examples ["ec42e09d5ae0ee0f0816ca151008412a"] * */ clientSecret: z.string().meta({ description: "spotify client secret", examples: ["ec42e09d5ae0ee0f0816ca151008412a"] }), /** * spotify redirect URI -- required only if not the default shown here. URI must end in "callback" * * @default "http://localhost:9078/callback" * @examples ["http://localhost:9078/callback"] * */ redirectUri: z.url({ protocol: /^https?$/, }).optional().meta({ description: "spotify redirect URI -- required only if not the default shown here.", default: "http://localhost:9078/callback", examples: ["http://localhost:9078/callback"] }), /** * How long to wait before polling the source API for new tracks (in seconds) * * It is unlikely you should need to change this unless you scrobble many very short tracks often * * Reading: * * https://developer.spotify.com/documentation/web-api/guides/rate-limits/ * * https://medium.com/mendix/limiting-your-amount-of-calls-in-mendix-most-of-the-time-rest-835dde55b10e * * Rate limit may ~180 req/min * * https://community.spotify.com/t5/Spotify-for-Developers/Web-API-ratelimit/m-p/5503150/highlight/true#M7930 * * Informally indicated as 20 req/sec? Probably for burstiness * * @default 10 * @examples [10] * */ interval: z.number().optional().meta({ description: "How long to wait before polling the source API for new tracks (in seconds)", default: 10, examples: [10] }),});
export const spotifyOptionsSchema = z.object({ /** * Backfill ISRC data if it missing * * If this is enabled and real-time data does not include ISRC then an additional API call is made to get this data. * * @default true * @examples [true] * */ enrichIsrc: z.boolean().optional().meta({ description: "Backfill ISRC data with an additional API call when the real-time polling endpoints omit it", default: true, examples: [true] }),});
export type SpotifySourceOptions = z.infer<typeof spotifyOptionsSchema>;
export type SpotifySourceData = z.infer<typeof spotifySourceDataSchema>;
const envDataSchema = z.object({ SPOTIFY_CLIENT_ID: spotifySourceDataSchema.shape.clientId, SPOTIFY_CLIENT_SECRET: spotifySourceDataSchema.shape.clientSecret, SPOTIFY_REDIRECT_URI: spotifySourceDataSchema.shape.redirectUri, SPOTIFY_SCROBBLE_BACKLOG: z.stringbool().optional().meta({ description: "Should backlogging and history reconciliation be enabled? (see [Scrobbling Backlog and Reconciling History](#scrobbling-backlog-and-reconciling-history)).", default: true }),});
export const envSchemas: EnvSourceSchema<typeof envDataSchema, SpotifySourceConfig> = { env: envDataSchema, prefix: 'SPOTIFY', toConfig: (partial) => ({ data: { clientId: partial.SPOTIFY_CLIENT_ID, clientSecret: partial.SPOTIFY_CLIENT_SECRET, redirectUri: partial.SPOTIFY_REDIRECT_URI }, options: { scrobbleBacklog: partial.SPOTIFY_SCROBBLE_BACKLOG, } })};
export const spotifySourceConfigSchema = z.object({ ...commonSourceConfigSchema.shape, data: spotifySourceDataSchema, options: z.object({ ...commonSourceOptionsSchema.shape, ...spotifyOptionsSchema.shape }).optional()});
export type SpotifySourceConfig = z.infer<typeof spotifySourceConfigSchema>;
export const spotifySourceAIOConfigSchema = z.object({ ...spotifySourceConfigSchema.shape, type: z.literal('spotify'),}).meta({title: 'Spotify'});
export type SpotifySourceAIOConfig = z.infer<typeof spotifySourceAIOConfigSchema>;