feat(streamer): BRANDING env to hide denpa.fm refs, drop station pill

This commit is contained in:
devilreef 2026-04-30 19:12:50 +06:00
parent 3b4ce1ce39
commit 9eaa16d818
Signed by: devilreef
SSH key fingerprint: SHA256:UZisRr4iuXx+IhkbZnR655L2RWAT6o2rgbGv5F/6m3Y
7 changed files with 45 additions and 29 deletions

View file

@ -16,6 +16,8 @@ FRAMERATE=30
RESOLUTION=1920x1080 RESOLUTION=1920x1080
STATION_TUNE_IN_URL=denpa.femboy.page STATION_TUNE_IN_URL=denpa.femboy.page
# set to false to hide all "denpa.fm" branding + links in the overlay
BRANDING=true
ICECAST_STATUS_URL=http://icecast:8000/status-json.xsl ICECAST_STATUS_URL=http://icecast:8000/status-json.xsl

View file

@ -21,6 +21,7 @@ export interface Config {
stationDisplayName?: string; stationDisplayName?: string;
stationTagline?: string; stationTagline?: string;
stationTuneInUrl: string; stationTuneInUrl: string;
branding: boolean;
healthPort: number; healthPort: number;
logLevel: "debug" | "info" | "warn" | "error"; logLevel: "debug" | "info" | "warn" | "error";
icecastStatusUrl?: string; icecastStatusUrl?: string;
@ -77,6 +78,7 @@ export function loadConfig(env: Record<string, string | undefined> = process.env
stationDisplayName: env.STATION_DISPLAY_NAME || undefined, stationDisplayName: env.STATION_DISPLAY_NAME || undefined,
stationTagline: env.STATION_TAGLINE || undefined, stationTagline: env.STATION_TAGLINE || undefined,
stationTuneInUrl: env.STATION_TUNE_IN_URL ?? "denpa.femboy.page", stationTuneInUrl: env.STATION_TUNE_IN_URL ?? "denpa.femboy.page",
branding: (env.BRANDING ?? "true").toLowerCase() !== "false",
healthPort: Number(env.HEALTH_PORT ?? 12010), healthPort: Number(env.HEALTH_PORT ?? 12010),
logLevel, logLevel,
icecastStatusUrl: env.ICECAST_STATUS_URL || undefined, icecastStatusUrl: env.ICECAST_STATUS_URL || undefined,

View file

@ -34,6 +34,7 @@ async function main() {
station: cfg.station, station: cfg.station,
tz: cfg.tz, tz: cfg.tz,
tuneInUrl: cfg.stationTuneInUrl, tuneInUrl: cfg.stationTuneInUrl,
branding: cfg.branding,
}); });
const pcm = new PcmTap({ host: cfg.pcmHost, port: cfg.pcmPort }); const pcm = new PcmTap({ host: cfg.pcmHost, port: cfg.pcmPort });

View file

@ -11,6 +11,7 @@ export interface PageServerOpts {
station: string; station: string;
tz: string; tz: string;
tuneInUrl: string; tuneInUrl: string;
branding: boolean;
} }
export class PageServer extends EventEmitter { export class PageServer extends EventEmitter {
@ -77,6 +78,7 @@ export class PageServer extends EventEmitter {
station: this.opts.station, station: this.opts.station,
tz: this.opts.tz, tz: this.opts.tz,
tuneInUrl: this.opts.tuneInUrl, tuneInUrl: this.opts.tuneInUrl,
branding: this.opts.branding,
})}</script>`; })}</script>`;
let html = ""; let html = "";
createReadStream(indexPath, "utf8") createReadStream(indexPath, "utf8")

View file

@ -5,7 +5,7 @@ import { StreamModern } from "./modern.tsx";
declare global { declare global {
interface Window { interface Window {
__STREAMER_CONFIG__: { style: "denpa" | "modern"; station: string; tz: string; tuneInUrl: string }; __STREAMER_CONFIG__: { style: "denpa" | "modern"; station: string; tz: string; tuneInUrl: string; branding: boolean };
} }
} }

View file

@ -6,7 +6,7 @@ import { fmtMs, fmtClock, fmtClockSec, fmtJpDate } from "./shared/format.ts";
const KAOMOJI_STREAM = ["(´。• ᵕ •。`)", "٩(◕‿◕)۶", "(。◕‿◕。)", "(>ω<)", "(✿◠‿◠)"]; const KAOMOJI_STREAM = ["(´。• ᵕ •。`)", "٩(◕‿◕)۶", "(。◕‿◕。)", "(>ω<)", "(✿◠‿◠)"];
interface Cfg { station: string; tz: string; tuneInUrl: string; } interface Cfg { station: string; tz: string; tuneInUrl: string; branding: boolean; }
interface Listeners { current: number; peak: number; } interface Listeners { current: number; peak: number; }
interface Props { cfg: Cfg; listeners: Listeners; } interface Props { cfg: Cfg; listeners: Listeners; }
@ -148,15 +148,19 @@ export function StreamDenpa({ cfg, listeners }: Props) {
`}</style> `}</style>
<div className="sd-header"> <div className="sd-header">
<div className="sd-wm"> {cfg.branding && (
<div className="eyebrow"> TRANSMISSION</div> <>
<span className="big">denpa.fm</span> <div className="sd-wm">
</div> <div className="eyebrow"> TRANSMISSION</div>
<div className="sd-channel"> <span className="big">denpa.fm</span>
{channel} <br/> </div>
{nameJp}<br/> <div className="sd-channel">
{"<3"} block radio {channel} <br/>
</div> {nameJp}<br/>
{"<3"} block radio
</div>
</>
)}
<div className="sd-status"> <div className="sd-status">
<div className="live">[<span className="blink">REC</span>] ON AIR</div> <div className="live">[<span className="blink">REC</span>] ON AIR</div>
<div>{fmtJpDate(now)}</div> <div>{fmtJpDate(now)}</div>
@ -245,15 +249,17 @@ export function StreamDenpa({ cfg, listeners }: Props) {
<div className="sd-bomb b2"><span className="sd-sticker" style={{ background: "#ffe24a", color: "#0a0410", transform: "rotate(5deg)" }}>SIDE A · CH.01</span></div> <div className="sd-bomb b2"><span className="sd-sticker" style={{ background: "#ffe24a", color: "#0a0410", transform: "rotate(5deg)" }}>SIDE A · CH.01</span></div>
{/* Bottom strip */} {/* Bottom strip */}
<div className="sd-bottom"> {cfg.branding && (
<div className="sd-listen"><b>&gt;&gt;</b> tune in @ {cfg.tuneInUrl}</div> <div className="sd-bottom">
<div className="sd-ticker"> <div className="sd-listen"><b>&gt;&gt;</b> tune in @ {cfg.tuneInUrl}</div>
<div className="sd-ticker-inner"> <div className="sd-ticker">
now broadcasting from a small room in tokyo 24/7 always-on {cfg.station} station stream URL: {cfg.tuneInUrl} requests via @denpa_bot no ads · no algorithms · just blocks {KAOMOJI_STREAM.join(" ※ ")} <div className="sd-ticker-inner">
now broadcasting from a small room in tokyo 24/7 always-on {cfg.station} station stream URL: {cfg.tuneInUrl} requests via @denpa_bot no ads · no algorithms · just blocks {KAOMOJI_STREAM.join(" ※ ")}
</div>
</div> </div>
<div className="sd-clock">{fmtClock(now)}</div>
</div> </div>
<div className="sd-clock">{fmtClock(now)}</div> )}
</div>
</div> </div>
); );
} }

View file

@ -4,7 +4,7 @@ import { useSpectrum } from "./shared/useSpectrum.ts";
import { useElapsed } from "./shared/useElapsed.ts"; import { useElapsed } from "./shared/useElapsed.ts";
import { fmtMs, fmtClock } from "./shared/format.ts"; import { fmtMs, fmtClock } from "./shared/format.ts";
interface Cfg { station: string; tz: string; tuneInUrl: string; } interface Cfg { station: string; tz: string; tuneInUrl: string; branding: boolean; }
interface Listeners { current: number; peak: number; } interface Listeners { current: number; peak: number; }
interface Props { cfg: Cfg; listeners: Listeners; } interface Props { cfg: Cfg; listeners: Listeners; }
@ -202,10 +202,12 @@ export function StreamModern({ cfg, listeners }: Props) {
<div className="sm-bg"></div> <div className="sm-bg"></div>
<div className="sm-grain"></div> <div className="sm-grain"></div>
<div className="sm-brand"> {cfg.branding && (
<span className="sm-brand-dot"></span> <div className="sm-brand">
denpa.fm {cfg.station} <span className="sm-brand-dot"></span>
</div> denpa.fm {cfg.station}
</div>
)}
<div className="sm-meta-top"> <div className="sm-meta-top">
<div className="sm-live"><span className="sm-live-dot"></span>Live</div> <div className="sm-live"><span className="sm-live-dot"></span>Live</div>
@ -221,7 +223,6 @@ export function StreamModern({ cfg, listeners }: Props) {
<div className="sm-right"> <div className="sm-right">
<div className="sm-eyebrow"> <div className="sm-eyebrow">
<span>Now playing</span> <span>Now playing</span>
<span className="pill">{cfg.station}</span>
</div> </div>
<h1 className="sm-title">{np.title}</h1> <h1 className="sm-title">{np.title}</h1>
<div className="sm-artist">{np.artist}</div> <div className="sm-artist">{np.artist}</div>
@ -255,11 +256,13 @@ export function StreamModern({ cfg, listeners }: Props) {
</div> </div>
</div> </div>
<div className="sm-bottom"> {cfg.branding && (
<span>Tune in at <span className="listeners">{cfg.tuneInUrl}</span></span> <div className="sm-bottom">
<span><span className="listeners">{listeners.current}</span> listeners · 24/7 · auto-DJ</span> <span>Tune in at <span className="listeners">{cfg.tuneInUrl}</span></span>
<span>{cfg.tuneInUrl}</span> <span><span className="listeners">{listeners.current}</span> listeners · 24/7 · auto-DJ</span>
</div> <span>{cfg.tuneInUrl}</span>
</div>
)}
</div> </div>
); );
} }