accelr8 3.7.1 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{app-EOVXVIEE.js → app-7YGYMFSZ.js} +100 -49
- package/dist/chunks/{chunk-P3CEHEKI.js → chunk-UTWXIX5N.js} +1 -1
- package/dist/chunks/{client-OIVTEENE.js → client-3RLQY3ZB.js} +1 -1
- package/dist/chunks/{server-NZ5JUOCF.js → server-V56IHFUH.js} +1 -1
- package/dist/cli.js +4 -4
- package/package.json +1 -1
|
@@ -5,11 +5,15 @@ import {
|
|
|
5
5
|
tzToCoords
|
|
6
6
|
} from "./chunk-HY6ULYGH.js";
|
|
7
7
|
import {
|
|
8
|
-
DEFAULT_SERVER
|
|
9
|
-
|
|
8
|
+
DEFAULT_SERVER,
|
|
9
|
+
VERSION
|
|
10
|
+
} from "./chunk-UTWXIX5N.js";
|
|
10
11
|
|
|
11
12
|
// src/radio/app.ts
|
|
12
13
|
import tk from "terminal-kit";
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
13
17
|
import { WebSocket } from "ws";
|
|
14
18
|
|
|
15
19
|
// src/radio/asciivideo.ts
|
|
@@ -5463,6 +5467,15 @@ var SyncedAudio = class {
|
|
|
5463
5467
|
};
|
|
5464
5468
|
|
|
5465
5469
|
// src/radio/app.ts
|
|
5470
|
+
function rlog(msg) {
|
|
5471
|
+
try {
|
|
5472
|
+
const dir = path.join(os.homedir(), ".accelr8");
|
|
5473
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
5474
|
+
fs.appendFileSync(path.join(dir, "radio.log"), `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
5475
|
+
`);
|
|
5476
|
+
} catch {
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5466
5479
|
var term = tk.terminal;
|
|
5467
5480
|
var ScreenBuffer = tk.ScreenBuffer;
|
|
5468
5481
|
var RENDER_FPS = 20;
|
|
@@ -5561,6 +5574,14 @@ function applyStation(m) {
|
|
|
5561
5574
|
const broadcast = m.broadcast || null;
|
|
5562
5575
|
state = { ...state, schedule: sched, listeners, broadcast, connected: true };
|
|
5563
5576
|
if (audio) audio.setSchedule(sched);
|
|
5577
|
+
if (m.skip) {
|
|
5578
|
+
skipVotes = m.skip.votes ?? 0;
|
|
5579
|
+
skipNeeded = m.skip.needed ?? 1;
|
|
5580
|
+
if (m.skip.trackId && m.skip.trackId !== skipTrackId) {
|
|
5581
|
+
skipTrackId = m.skip.trackId;
|
|
5582
|
+
youVoted = false;
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5564
5585
|
}
|
|
5565
5586
|
function startBackground(opts) {
|
|
5566
5587
|
const tools = detectVoiceTools();
|
|
@@ -5594,42 +5615,44 @@ function makeScreen() {
|
|
|
5594
5615
|
screen = new ScreenBuffer({ dst: term, width: W(), height: H() });
|
|
5595
5616
|
video?.resize(W(), H());
|
|
5596
5617
|
}
|
|
5597
|
-
var volMsg = "";
|
|
5598
|
-
var volMsgUntil = 0;
|
|
5599
|
-
function flashVol() {
|
|
5600
|
-
if (!audio) return;
|
|
5601
|
-
const v = audio.volume, bars = 12, on = Math.round(v / 100 * bars);
|
|
5602
|
-
volMsg = audio.isMuted ? "\u266B muted (m to unmute)" : `\u266B ${"\u2588".repeat(on)}${"\u2591".repeat(bars - on)} ${v}%`;
|
|
5603
|
-
volMsgUntil = Date.now() + 1800;
|
|
5604
|
-
}
|
|
5605
5618
|
function volUp() {
|
|
5606
5619
|
if (audio) {
|
|
5607
5620
|
if (audio.isMuted) audio.toggleMute();
|
|
5608
5621
|
audio.setVolume(audio.volume + 10);
|
|
5609
|
-
flashVol();
|
|
5610
5622
|
}
|
|
5611
5623
|
}
|
|
5612
5624
|
function volDown() {
|
|
5613
5625
|
if (audio) {
|
|
5614
5626
|
if (audio.isMuted) audio.toggleMute();
|
|
5615
5627
|
audio.setVolume(audio.volume - 10);
|
|
5616
|
-
flashVol();
|
|
5617
5628
|
}
|
|
5618
5629
|
}
|
|
5619
5630
|
function muteToggle() {
|
|
5620
|
-
if (audio)
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5631
|
+
if (audio) audio.toggleMute();
|
|
5632
|
+
}
|
|
5633
|
+
var skipVotes = 0;
|
|
5634
|
+
var skipNeeded = 1;
|
|
5635
|
+
var youVoted = false;
|
|
5636
|
+
var skipTrackId = "";
|
|
5637
|
+
function toggleSkip() {
|
|
5638
|
+
youVoted = !youVoted;
|
|
5639
|
+
if (stationWs && stationWs.readyState === 1) stationWs.send(JSON.stringify({ t: youVoted ? "voteSkip" : "unvoteSkip" }));
|
|
5640
|
+
}
|
|
5641
|
+
function drawControls() {
|
|
5642
|
+
const w = screen.width, y = 1;
|
|
5643
|
+
if (screen.height < 3) return;
|
|
5644
|
+
for (let x = 0; x < w; x++) screen.put({ x, y, attr: { color: 231, bgColor: 234 }, dx: 1, dy: 0, wrap: false }, " ");
|
|
5645
|
+
const put2 = (x, s, color = 231, bold = false) => {
|
|
5646
|
+
for (let i = 0; i < s.length && x + i < w; i++) if (x + i >= 0) screen.put({ x: x + i, y, attr: { color, bgColor: 234, bold }, dx: 1, dy: 0, wrap: false }, s[i]);
|
|
5647
|
+
};
|
|
5648
|
+
const vol = audio ? audio.isMuted ? "MUTED" : `vol ${audio.volume}%` : "no audio";
|
|
5649
|
+
put2(1, `\u266A ${vol} [m] mute [+/-] volume [q] quit`);
|
|
5650
|
+
const met = skipVotes >= skipNeeded && skipVotes > 0;
|
|
5651
|
+
const label = youVoted ? "[s] voted \u2713" : "[s] vote skip";
|
|
5652
|
+
const right = `${label} skip ${skipVotes}/${skipNeeded} `;
|
|
5653
|
+
put2(w - right.length, right, met ? C_GOOD : 231, youVoted);
|
|
5654
|
+
}
|
|
5655
|
+
var C_GOOD = 46;
|
|
5633
5656
|
var BG = 16;
|
|
5634
5657
|
function blitVideo() {
|
|
5635
5658
|
const w = screen.width, h = screen.height;
|
|
@@ -5656,21 +5679,26 @@ function blitOverlay(cells) {
|
|
|
5656
5679
|
screen.put({ x: c.x, y: c.y, attr: { color: c.color ?? 231, bgColor: bg, bold: !!c.bold }, dx: 1, dy: 0, wrap: false }, c.ch || " ");
|
|
5657
5680
|
}
|
|
5658
5681
|
}
|
|
5682
|
+
var renderErrs = 0;
|
|
5659
5683
|
function renderFrame() {
|
|
5660
5684
|
if (!running) return;
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5685
|
+
try {
|
|
5686
|
+
const tMs = Date.now() - startedAt;
|
|
5687
|
+
if (visuals) {
|
|
5688
|
+
lastFrame = visuals.frame(tMs, screen.width, screen.height);
|
|
5689
|
+
frameW = screen.width;
|
|
5690
|
+
frameH = screen.height;
|
|
5691
|
+
}
|
|
5692
|
+
const serverNowMs = serverNow();
|
|
5693
|
+
state = { ...state, serverNowMs, nowPlaying: nowPlaying(state.schedule, serverNowMs), nowShowing: nowShowing(state.schedule, serverNowMs) };
|
|
5694
|
+
blitVideo();
|
|
5695
|
+
const cells = renderOverlay({ w: screen.width, h: screen.height, tMs, state });
|
|
5696
|
+
blitOverlay(cells);
|
|
5697
|
+
drawControls();
|
|
5698
|
+
if (screen.dst) screen.draw({ delta: true });
|
|
5699
|
+
} catch (e) {
|
|
5700
|
+
if (renderErrs++ < 5) rlog(`renderFrame error @${screen?.width}x${screen?.height}: ${e?.stack || e?.message || e}`);
|
|
5701
|
+
}
|
|
5674
5702
|
}
|
|
5675
5703
|
function teardown() {
|
|
5676
5704
|
running = false;
|
|
@@ -5705,33 +5733,56 @@ function quit() {
|
|
|
5705
5733
|
process.exit(0);
|
|
5706
5734
|
}
|
|
5707
5735
|
function runRadio(opts) {
|
|
5708
|
-
|
|
5736
|
+
let tz = "UTC";
|
|
5737
|
+
try {
|
|
5738
|
+
tz = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
5739
|
+
} catch {
|
|
5740
|
+
}
|
|
5709
5741
|
me = { id: "me_" + Math.random().toString(36).slice(2, 10), name: opts.name || "you", tz, color: 39 };
|
|
5710
5742
|
state = baseState(me);
|
|
5743
|
+
try {
|
|
5744
|
+
const tools = detectVoiceTools();
|
|
5745
|
+
rlog(`\u2500\u2500 radio start v${VERSION} \xB7 ${process.platform} \xB7 node ${process.version} \xB7 term ${process.stdout.columns}x${process.stdout.rows} \xB7 TERM=${process.env.TERM} \xB7 ffmpeg=${!!tools.ffmpegPath} ffplay=${!!tools.ffplayPath}`);
|
|
5746
|
+
} catch (e) {
|
|
5747
|
+
rlog(`start probe failed: ${e?.stack || e}`);
|
|
5748
|
+
}
|
|
5711
5749
|
const die = (err) => {
|
|
5750
|
+
const detail = err instanceof Error ? err.stack || err.message : String(err);
|
|
5751
|
+
rlog(`CRASH: ${detail}`);
|
|
5712
5752
|
teardown();
|
|
5713
|
-
console.error("
|
|
5714
|
-
|
|
5753
|
+
console.error("\naccelr8 radio crashed:\n" + detail + "\n\nlog: " + path.join(os.homedir(), ".accelr8", "radio.log") + "\n(press any key to close)");
|
|
5754
|
+
try {
|
|
5755
|
+
process.stdin.setRawMode?.(true);
|
|
5756
|
+
process.stdin.resume();
|
|
5757
|
+
process.stdin.once("data", () => process.exit(1));
|
|
5758
|
+
setTimeout(() => process.exit(1), 3e4);
|
|
5759
|
+
} catch {
|
|
5760
|
+
process.exit(1);
|
|
5761
|
+
}
|
|
5715
5762
|
};
|
|
5716
5763
|
process.on("uncaughtException", die);
|
|
5717
5764
|
process.on("unhandledRejection", die);
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5765
|
+
try {
|
|
5766
|
+
term.fullscreen(true);
|
|
5767
|
+
term.hideCursor();
|
|
5768
|
+
term.grabInput(true);
|
|
5769
|
+
makeScreen();
|
|
5770
|
+
running = true;
|
|
5771
|
+
startBackground(opts);
|
|
5772
|
+
connectStation(opts);
|
|
5773
|
+
} catch (e) {
|
|
5774
|
+
return die(e);
|
|
5775
|
+
}
|
|
5725
5776
|
term.on("key", (name) => {
|
|
5726
5777
|
if (name === "CTRL_C" || name === "q" || name === "ESCAPE") return quit();
|
|
5727
5778
|
if (name === "m") return muteToggle();
|
|
5779
|
+
if (name === "s") return toggleSkip();
|
|
5728
5780
|
if (name === "+" || name === "=" || name === "UP") return volUp();
|
|
5729
5781
|
if (name === "-" || name === "_" || name === "DOWN") return volDown();
|
|
5730
5782
|
});
|
|
5731
5783
|
term.on("resize", () => makeScreen());
|
|
5732
5784
|
process.on("SIGINT", quit);
|
|
5733
5785
|
process.on("SIGTERM", quit);
|
|
5734
|
-
flashVol();
|
|
5735
5786
|
renderTimer = setInterval(renderFrame, Math.round(1e3 / RENDER_FPS));
|
|
5736
5787
|
renderFrame();
|
|
5737
5788
|
}
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
DEFAULT_SERVER,
|
|
4
4
|
PORT,
|
|
5
5
|
VERSION
|
|
6
|
-
} from "./chunks/chunk-
|
|
6
|
+
} from "./chunks/chunk-UTWXIX5N.js";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
var HELP = `
|
|
@@ -53,7 +53,7 @@ async function main() {
|
|
|
53
53
|
console.error(`invalid port: ${argVal(args, "--port")}`);
|
|
54
54
|
process.exit(1);
|
|
55
55
|
}
|
|
56
|
-
const { runServer } = await import("./chunks/server-
|
|
56
|
+
const { runServer } = await import("./chunks/server-V56IHFUH.js");
|
|
57
57
|
runServer(port);
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
@@ -67,7 +67,7 @@ async function main() {
|
|
|
67
67
|
console.error("accelr8 radio needs an interactive terminal (TTY).");
|
|
68
68
|
process.exit(1);
|
|
69
69
|
}
|
|
70
|
-
const { runRadio } = await import("./chunks/app-
|
|
70
|
+
const { runRadio } = await import("./chunks/app-7YGYMFSZ.js");
|
|
71
71
|
runRadio({
|
|
72
72
|
name: argVal(args, "--name"),
|
|
73
73
|
server: argVal(args, "--server"),
|
|
@@ -90,7 +90,7 @@ async function main() {
|
|
|
90
90
|
const { cachedUpdate, refreshUpdateCache } = await import("./chunks/update-UEPNGB6Y.js");
|
|
91
91
|
refreshUpdateCache();
|
|
92
92
|
const update = cachedUpdate(VERSION);
|
|
93
|
-
const { runClient } = await import("./chunks/client-
|
|
93
|
+
const { runClient } = await import("./chunks/client-3RLQY3ZB.js");
|
|
94
94
|
runClient({
|
|
95
95
|
name: argVal(args, "--name"),
|
|
96
96
|
server: argVal(args, "--server"),
|