▍ humdrum codex / soft
1.7 KB raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import type { SourceModule } from "../registry";
import {
  CiderConfig,
  CiderPayload,
  type CiderConfig as Config,
  type CiderPayload as Payload,
} from "@/lib/schemas/sources/cider";

export const ciderModule: SourceModule<Config, Payload> = {
  kind: "cider",
  label: "Now Playing",
  keyless: false,
  defaultRefreshSeconds: 30,
  configSchema: CiderConfig,
  payloadSchema: CiderPayload,

  isConfigured: (config) => config.appToken.length > 0,

  async fetch({ config, signal }) {
    const res = await fetch(`${config.host}/api/v1/playback/now-playing`, {
      headers: { apptoken: config.appToken },
      signal,
    });

    if (res.status === 204) return { playing: false, track: null };
    if (!res.ok) throw new Error(`Cider ${res.status}`);

    const j = (await res.json()) as {
      status?: string;
      info?: {
        name?: string;
        artistName?: string;
        albumName?: string;
        artwork?: { url?: string };
        durationInMillis?: number;
        currentPlaybackTime?: number;
      };
    };

    if (j.status !== "ok" || !j.info) return { playing: false, track: null };

    const info = j.info;
    const artRaw = info.artwork?.url ?? null;
    // Replace {w}x{h} template Apple Music uses in artwork URLs
    const artworkUrl = artRaw ? artRaw.replace("{w}", "300").replace("{h}", "300") : null;

    return {
      playing: true,
      track: {
        name: info.name ?? "Unknown",
        artist: info.artistName ?? "Unknown",
        album: info.albumName ?? "Unknown",
        artworkUrl,
        durationMs: (info.durationInMillis ?? 0),
        currentMs: Math.round((info.currentPlaybackTime ?? 0) * 1000),
      },
    };
  },
};