Sockets allowing for live updates rather than complete rebuilds #7

Merged
kristy-fournier merged 20 commits from timerChanges into main 2026-02-11 09:39:36 -05:00
4 changed files with 48 additions and 19 deletions
Showing only changes of commit 17632d4dea - Show all commits

View file

@ -6,6 +6,8 @@
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<link rel="manifest" href="manifest.json" /> <link rel="manifest" href="manifest.json" />
<meta charset="utf-8"> <meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-sha256/0.11.0/sha256.min.js"></script>
<!-- above allows use of sha256() on http -->
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script> <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
</head> </head>
<body id="test-body"> <body id="test-body">

View file

@ -2,7 +2,8 @@
let ip; let ip;
let alertTime = 2; let alertTime = 2;
let adminPass = ""; let adminPass = "";
let justSkipped = false let justSkipped = false;
let justChangedSetting = false;
const ERR_NO_ADMIN = 401; const ERR_NO_ADMIN = 401;
const VALID_FILE_EXT = ["mp3","flac","wav"]; const VALID_FILE_EXT = ["mp3","flac","wav"];
@ -41,12 +42,16 @@ async function alertText(text="Song Added!") {
} }
// a lot of this is kinda waffly because i was trying to get // a lot of this is kinda waffly because i was trying to get
// it to return the right stuff and javascript is asyrcronouse (boo) // it to return the right stuff and javascript is asyrcronouse (boo)
async function getFromServer(bodyInfo, source="",password=adminPass) { async function getFromServer(bodyInfo, source="", secure=false, password=adminPass) {
try{ try{
if (bodyInfo != null) { if (bodyInfo != null) {
// the currently set password is always included in every request // the currently set password is always included in every request
bodyInfo["password"] = password; bodyInfo["password"] = password;
} }
let href = "";
if(secure) {
href = "https://"+ip+"/"
}
const response = await fetch("http://"+ip+"/"+source, { const response = await fetch("http://"+ip+"/"+source, {
method: "POST", method: "POST",
body: JSON.stringify(bodyInfo), body: JSON.stringify(bodyInfo),
@ -142,8 +147,13 @@ async function controlButton(buttonType) {
document.getElementById("settings-mode").style.display = "block"; document.getElementById("settings-mode").style.display = "block";
checkSettings() checkSettings()
} else if (buttonType = "pm") { //Partymode toggle (in settings) } else if (buttonType = "pm") { //Partymode toggle (in settings)
await getFromServer({setting: "partymode-toggle"}, "settings") let response = await getFromServer({setting: "partymode-toggle"}, "settings")
checkSettings(true) if(response.ok) {
justChangedSetting = true;
checkSettings();
} else {
// dont think anything is needed here
}
} }
@ -517,19 +527,19 @@ function toggleDark(e) {
qrCodeGenerate(); qrCodeGenerate();
} }
async function sha256(message) { // async function sha256(message) {
// Encode the message as UTF-8 // // Encode the message as UTF-8
const msgBuffer = new TextEncoder().encode(message); // const msgBuffer = new TextEncoder().encode(message);
// Hash the message // // Hash the message
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer); // const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
// Convert ArrayBuffer to hex string // // Convert ArrayBuffer to hex string
const hashArray = Array.from(new Uint8Array(hashBuffer)); // const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hashHex; // return hashHex;
} // }
copilot-pull-request-reviewer[bot] commented 2026-02-11 09:28:38 -05:00 (Migrated from github.com)

In addToPlaylist, i is assigned without let/const, creating an implicit global. Also image.id = String(songObject[newItem.id]) + " image" will usually become "[object Object] image" and won’t be unique/meaningful. Declare i locally and base the image id on the filename (newItem.id) like the rest of the file does.

In `addToPlaylist`, `i` is assigned without `let/const`, creating an implicit global. Also `image.id = String(songObject[newItem.id]) + " image"` will usually become "[object Object] image" and won’t be unique/meaningful. Declare `i` locally and base the image id on the filename (`newItem.id`) like the rest of the file does.
async function adminPassEnter(e) { async function adminPassEnter(e) {
if (e.key == "Enter") { if (e.key == "Enter") {
@ -559,6 +569,8 @@ async function submitPerms(e) {
// its not perfect if you spam click, but it gets the point across to the user // its not perfect if you spam click, but it gets the point across to the user
let clickedBox = e.srcElement; let clickedBox = e.srcElement;
clickedBox.checked = !clickedBox.checked; clickedBox.checked = !clickedBox.checked;
} else {
justChangedSetting = true;
} }
} }
@ -627,8 +639,9 @@ document.getElementById("songlist").addEventListener('keydown', function(e){chec
document.getElementById("songlist").addEventListener('click', function(e){checkWhatSongWasClicked(e)}); document.getElementById("songlist").addEventListener('click', function(e){checkWhatSongWasClicked(e)});
//makes the controls look mostly normal on all screens, best solution i could find, idk man //makes the controls look mostly normal on all screens, best solution i could find, idk man
let tempWidth = document.getElementById('controls').clientWidth; // replaced this with "transform" css stuff
document.getElementById("controls").style.marginLeft = "-"+String(parseInt(tempWidth/2))+"px"; // let tempWidth = document.getElementById('controls').clientWidth;
// document.getElementById("controls").style.marginLeft = "-"+String(parseInt(tempWidth/2))+"px";
//for my use case (my immediate family), they dont know how to set an ip //for my use case (my immediate family), they dont know how to set an ip
//using this allows the creator of the link for, a qr code for example, to set the ip before distributing the code, and it would all work smoothly //using this allows the creator of the link for, a qr code for example, to set the ip before distributing the code, and it would all work smoothly
@ -665,13 +678,13 @@ socket = io("http://"+ip,{
socket.on("songAdd", function(data) { socket.on("songAdd", function(data) {
// console.log("recieved data from songAdd"); // console.log("recieved data from songAdd");
console.log(data); // console.log(data);
addToPlaylist(data); addToPlaylist(data);
}) })
socket.on("timeUpdate", function(data) { socket.on("timeUpdate", function(data) {
// console.log("recieved data from timeUpdate"); // console.log("recieved data from timeUpdate");
console.log(data); // console.log(data);
copilot-pull-request-reviewer[bot] commented 2026-02-11 09:28:37 -05:00 (Migrated from github.com)

The settingsChange socket handler still logs to console (console.log(data) / console.log("working")). These debug statements will be noisy for all clients; remove them once behavior is validated.

    if (justChangedSetting) {
The `settingsChange` socket handler still logs to console (`console.log(data)` / `console.log("working")`). These debug statements will be noisy for all clients; remove them once behavior is validated. ```suggestion if (justChangedSetting) { ```
playlistElapsedSeconds = data["elapsedTime"]; playlistElapsedSeconds = data["elapsedTime"];
currentlyPlaying = data["playingState"] currentlyPlaying = data["playingState"]
}); });
@ -682,4 +695,14 @@ socket.on("skipSong",() => {
} else { } else {
justSkipped = false; justSkipped = false;
} }
}) })
socket.on("settingsChange",(data) => {
console.log(data);
if(justChangedSetting) {
console.log("working");
justChangedSetting = false;
} else {
checkSettings();
}
});

View file

@ -62,6 +62,7 @@ h4 {
left: 50%; left: 50%;
bottom: 0; bottom: 0;
margin: 0 auto; margin: 0 auto;
transform: translateX(-50%);
background-color:var(--bg-main); background-color:var(--bg-main);
} }

View file

@ -190,6 +190,7 @@ def settingsControl():
volumeLevel = int(recieveData["level"]) volumeLevel = int(recieveData["level"])
if(volumeLevel <= 100 and volumeLevel >= 0): if(volumeLevel <= 100 and volumeLevel >= 0):
volumePassed = player.audio_set_volume(volumeLevel) volumePassed = player.audio_set_volume(volumeLevel)
socketio.emit("settingsChange")
return {"error":"ok","data":{"volumePassed":volumePassed}},200 return {"error":"ok","data":{"volumePassed":volumePassed}},200
else: else:
return {"error":"Invalid volume level","data":None},422 return {"error":"Invalid volume level","data":None},422
@ -198,11 +199,13 @@ def settingsControl():
elif recieveData["setting"] == "partymode-toggle": elif recieveData["setting"] == "partymode-toggle":
if ADMIN_PASS == recieveData['password'] or controlPerms["PM"]: if ADMIN_PASS == recieveData['password'] or controlPerms["PM"]:
partyMode = not(partyMode) partyMode = not(partyMode)
socketio.emit("settingsChange")
return ERR_200 return ERR_200
else: else:
return ERR_NO_ADMIN return ERR_NO_ADMIN
elif recieveData["setting"] == "perms": elif recieveData["setting"] == "perms":
if ADMIN_PASS == recieveData["password"]: if ADMIN_PASS == recieveData["password"]:
socketio.emit("settingsChange")
controlPerms = recieveData["admin"] controlPerms = recieveData["admin"]
# print(recieveData["admin"]) # print(recieveData["admin"])
return ERR_200 return ERR_200