Files
PodTui/src/utils/theme-observer.ts
Michael Freno d7aec4e810 fix(memory): bound visualizer PCM cache and feed episode cache
The visualizer's PCM cache decoded the entire episode into RAM (22050 Hz
mono s16 ~160 MB/hr of audio) and held it until stop() — a 3-hour episode
pinned ~500 MB and long-form content hit 2.5 GB. The 4x decode also pulled
the whole remote file even when only minutes were listened to.

- audio-pcm-cache: sliding window around the playback position — the
  decode head caps at maxAheadSec (600s) ahead of the cursor, segments
  older than keepBehindSec (300s) are pruned, and the tail refills as
  playback advances. Steady state ~40 MB regardless of episode length;
  a backward seek past the window restarts a segment there (the existing
  seek-hole mechanism, no new failure mode).
- feed: cap the full-parse episode cache at 1000 episodes/feed so
  archive-heavy subscriptions can't pin their entire history in RAM;
  the visible list stays bounded by the user's cache preference and
  fetch-more keeps working within the ceiling.
- tests: pin the new head-cap and prune contracts (8/8 in
  audio-pcm-cache.test.ts; full suite 193 pass).

Also includes the in-flight cleanup/refactor pass (cover-art resolve
helper, page and comment tightening, ESLint config removal).
2026-08-12 21:02:19 -04:00

45 lines
1.1 KiB
TypeScript

/**
* Theme observer utility for detecting and responding to theme changes.
*
* This module provides utilities for:
* - Listening to SIGUSR2 signals for theme reload
* - Emitting theme change events via the event bus
* - Tracking theme change state
*/
import { emit } from "./event-bus"
function emitThemeReload(): void {
emit("theme.reload", {})
}
export function emitThemeChanged(theme: string, mode: "dark" | "light"): void {
emit("theme.changed", { theme, mode })
}
export function emitThemeModeChanged(mode: "dark" | "light"): void {
emit("theme.mode.changed", { mode })
}
/**
* Setup SIGUSR2 signal handler for theme reload.
* This allows external tools to trigger a theme refresh by sending SIGUSR2 to the process.
*
* Usage: `kill -USR2 <pid>` to trigger a theme reload
*
* @param onReload - Callback to execute when SIGUSR2 is received
* @returns Cleanup function to remove the handler
*/
export function setupThemeSignalHandler(onReload: () => void): () => void {
const handler = () => {
emitThemeReload()
onReload()
}
process.on("SIGUSR2", handler)
return () => {
process.off("SIGUSR2", handler)
}
}