Refactor, add types, increase retry delay

This commit is contained in:
Isaiah Billingsley 2026-02-19 17:20:35 -05:00
parent 5e8a821ee3
commit 73fcb36e04
3 changed files with 106 additions and 44 deletions

View File

@ -1,6 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"checkJs": true, "checkJs": true,
"target": "es2021" "target": "es2021",
"noImplicitAny": false
} }
} }

65
main.js
View File

@ -2,37 +2,49 @@
// https://github.com/hardcpp/BeatSaberPlus/wiki/%5BEN%5D-Song-Overlay // https://github.com/hardcpp/BeatSaberPlus/wiki/%5BEN%5D-Song-Overlay
const bspUrl = "ws://localhost:2947/socket"; const bspUrl = "ws://localhost:2947/socket";
const retryMs = 5000; const retryMs = 10000;
let retries = 0; let retries = 0;
function connect() { function connect() {
console.log(`Connecting to ${bspUrl} (attempt ${retries++})`); console.log(`Connecting to ${bspUrl} (attempt ${retries++})`);
const ws = new WebSocket(bspUrl); const ws = new WebSocket(bspUrl);
ws.onopen = () => console.log("Connection open."); ws.onopen = onOpen;
ws.onmessage = (e) => { ws.onmessage = onMessage;
const data = JSON.parse(e.data); ws.onclose = onClose;
switch (data._type) { }
case "event":
switch (data._event) {
case "gameState":
document.body.className = data.gameStateChanged;
break;
case "mapInfo": function onOpen() {
updateMapInfo(data.mapInfoChanged); console.log("Connection open.");
break; retries = 0;
} }
break;
default: /** @param {MessageEvent<string>} e */
console.log("message", e.data); function onMessage(e) {
break; /** @type {BeatSaberPlusEvent} */
} const data = JSON.parse(e.data);
}; switch (data._type) {
ws.onclose = (e) => { case "event":
console.log(`Connection closed. code: ${e.code}, reason: ${e.reason}, clean: ${e.wasClean}`); switch (data._event) {
setTimeout(connect, retryMs); case "gameState":
}; document.body.className = data.gameStateChanged;
break;
case "mapInfo":
updateMapInfo(data.mapInfoChanged);
break;
}
break;
default:
console.log("message", e.data);
break;
}
}
/** @param {CloseEvent} e */
function onClose(e) {
console.log(`Connection closed. code: ${e.code}, reason: ${e.reason}, clean: ${e.wasClean}`);
setTimeout(connect, retryMs);
} }
const cover = document.getElementById("cover"); const cover = document.getElementById("cover");
@ -56,10 +68,11 @@ function updateMapInfo(data) {
mapper.textContent = data.mapper || ""; mapper.textContent = data.mapper || "";
difficulty.textContent = data.difficulty.replace("Plus", " +") || ""; difficulty.textContent = data.difficulty.replace("Plus", " +") || "";
characteristicIcon.setAttribute("src", `images/characteristic/${data.characteristic}.svg`); characteristicIcon.setAttribute("src", `images/characteristic/${data.characteristic}.svg`);
difficultyLabel.textContent = ""; difficultyLabel.textContent = ""; // BS+ does not provide label
bsrKey.textContent = data.BSRKey || ""; bsrKey.textContent = data.BSRKey || ""; // Always empty?
type.textContent = !custom ? "OST" : data.level_id.endsWith(" WIP") ? "WIP" : ""; type.textContent = !custom ? "OST" : data.level_id.endsWith(" WIP") ? "WIP" : "";
// Fetch extra info from BeatSaver
if (custom) { if (custom) {
fetch(`https://api.beatsaver.com/maps/hash/${data.level_id.substring(13, 53)}`) fetch(`https://api.beatsaver.com/maps/hash/${data.level_id.substring(13, 53)}`)
.then(response => response.json()) .then(response => response.json())

82
types.d.ts vendored
View File

@ -1,20 +1,68 @@
interface Document { // https://github.com/hardcpp/BeatSaberPlus/wiki/%5BEN%5D-Song-Overlay
getElementById(elementId: string): HTMLElement;
interface HandshakeEvent {
"_type": "handshake";
"protocolVersion": number;
"gameVersion": string;
"playerName": string;
"playerPlatformId": string;
} }
interface MapInfoChanged { interface GameStateEvent {
"level_id": string; "_type": "event";
"name": string; "_event": "gameState";
"sub_name": string; "gameStateChanged": "Menu" | "Playing";
"artist": string; }
"mapper": string;
"characteristic": string; interface ResumeEvent {
"difficulty": string; "_type": "event";
"duration": number; "_event": "resume";
"BPM": number; "resumeTime": number;
"PP": number; }
"BSRKey": string;
"coverRaw": string; interface PauseEvent {
"time": number; "_type": "event";
"timeMultiplier": number; "_event": "pause";
"pauseTime": number;
}
interface MapInfoChangedEvent {
"_type": "event";
"_event": "mapInfo";
"mapInfoChanged": {
"level_id": string;
"name": string;
"sub_name": string;
"artist": string;
"mapper": string;
"characteristic": string;
"difficulty": string;
"duration": number;
"BPM": number;
"PP": number;
"BSRKey": string;
"coverRaw": string;
"time": number;
"timeMultiplier": number;
};
}
interface ScoreEvent {
"_type": "event";
"_event": "score";
"scoreEvent": {
"time": number;
"score": number;
"accuracy": number;
"combo": number;
"missCount": number;
"currentHealth": number;
};
}
type BeatSaberPlusEvent = HandshakeEvent | GameStateEvent | ResumeEvent | PauseEvent | MapInfoChangedEvent | ScoreEvent;
type MapInfoChanged = MapInfoChangedEvent["mapInfoChanged"];
interface Document {
getElementById(elementId: string): HTMLElement; // Assume non-null
} }