feat(streamer): icecast listener-count poller
This commit is contained in:
parent
6bcf18c1bf
commit
870a41a2f7
1 changed files with 43 additions and 0 deletions
43
streamer/src/icecast.ts
Normal file
43
streamer/src/icecast.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { EventEmitter } from "node:events";
|
||||
|
||||
export interface IcecastOpts {
|
||||
statusUrl: string;
|
||||
mountName: string;
|
||||
intervalMs?: number;
|
||||
}
|
||||
|
||||
export interface IcecastListeners { current: number; peak: number; }
|
||||
|
||||
export class IcecastPoller extends EventEmitter {
|
||||
private timer: NodeJS.Timeout | null = null;
|
||||
private peak = 0;
|
||||
|
||||
constructor(private opts: IcecastOpts) { super(); }
|
||||
|
||||
start(): void {
|
||||
this.poll();
|
||||
this.timer = setInterval(() => this.poll(), this.opts.intervalMs ?? 30000);
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (this.timer) clearInterval(this.timer);
|
||||
}
|
||||
|
||||
private async poll(): Promise<void> {
|
||||
try {
|
||||
const r = await fetch(this.opts.statusUrl, { signal: AbortSignal.timeout(5000) });
|
||||
if (!r.ok) throw new Error(`icecast status ${r.status}`);
|
||||
const j = await r.json() as {
|
||||
icestats: { source?: { listenurl: string; listeners: number }[] | { listenurl: string; listeners: number } };
|
||||
};
|
||||
const sources = j.icestats.source;
|
||||
const list = Array.isArray(sources) ? sources : sources ? [sources] : [];
|
||||
const found = list.find((s) => s.listenurl.endsWith(this.opts.mountName));
|
||||
const current = found?.listeners ?? 0;
|
||||
this.peak = Math.max(this.peak, current);
|
||||
this.emit("listeners", { current, peak: this.peak });
|
||||
} catch (err) {
|
||||
this.emit("warn", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue