import { createDiscordPresenceRuntime } from './runtime/discord-presence-runtime'; type DiscordPresenceConfigLike = { enabled?: boolean; }; type DiscordPresenceServiceLike = { start: () => Promise; stop?: () => Promise; publish: (snapshot: { mediaTitle: string | null; mediaPath: string | null; subtitleText: string; currentTimeSec: number | null; mediaDurationSec: number | null; paused: boolean | null; connected: boolean; sessionStartedAtMs: number; }) => void; }; export interface DiscordPresenceLifecycleRuntimeInput { getResolvedConfig: () => { discordPresence: DiscordPresenceConfigLike }; getDiscordPresenceService: () => DiscordPresenceServiceLike | null; setDiscordPresenceService: (service: DiscordPresenceServiceLike | null) => void; getMpvClient: () => { connected?: boolean; currentTimePos?: number | null; requestProperty: (name: string) => Promise; } | null; getCurrentMediaTitle: () => string | null; getCurrentMediaPath: () => string | null; getCurrentSubtitleText: () => string; getPlaybackPaused: () => boolean | null; getFallbackMediaDurationSec: () => number | null; createDiscordPresenceService: (config: unknown) => DiscordPresenceServiceLike; createDiscordRuntime?: typeof createDiscordPresenceRuntime; now?: () => number; } export interface DiscordPresenceLifecycleRuntime { publishDiscordPresence: () => void; initializeDiscordPresenceService: () => Promise; stopDiscordPresenceService: () => Promise; } export function createDiscordPresenceLifecycleRuntime( input: DiscordPresenceLifecycleRuntimeInput, ): DiscordPresenceLifecycleRuntime { let discordPresenceMediaDurationSec: number | null = null; const discordPresenceSessionStartedAtMs = input.now ? input.now() : Date.now(); const discordPresenceRuntime = (input.createDiscordRuntime ?? createDiscordPresenceRuntime)({ getDiscordPresenceService: () => input.getDiscordPresenceService(), isDiscordPresenceEnabled: () => input.getResolvedConfig().discordPresence.enabled === true, getMpvClient: () => input.getMpvClient(), getCurrentMediaTitle: () => input.getCurrentMediaTitle(), getCurrentMediaPath: () => input.getCurrentMediaPath(), getCurrentSubtitleText: () => input.getCurrentSubtitleText(), getPlaybackPaused: () => input.getPlaybackPaused(), getFallbackMediaDurationSec: () => input.getFallbackMediaDurationSec(), getSessionStartedAtMs: () => discordPresenceSessionStartedAtMs, getMediaDurationSec: () => discordPresenceMediaDurationSec, setMediaDurationSec: (next) => { discordPresenceMediaDurationSec = next; }, }); return { publishDiscordPresence: () => { discordPresenceRuntime.publishDiscordPresence(); }, initializeDiscordPresenceService: async () => { if (input.getResolvedConfig().discordPresence.enabled !== true) { input.setDiscordPresenceService(null); return; } input.setDiscordPresenceService( input.createDiscordPresenceService(input.getResolvedConfig().discordPresence), ); await input.getDiscordPresenceService()?.start(); discordPresenceRuntime.publishDiscordPresence(); }, stopDiscordPresenceService: async () => { await input.getDiscordPresenceService()?.stop?.(); input.setDiscordPresenceService(null); }, }; }