From 9bdac82f10ef6cb7ab0283b964c22b47654d8a5e Mon Sep 17 00:00:00 2001 From: Kristy Fournier Date: Sun, 25 Jan 2026 19:04:02 -0500 Subject: [PATCH 1/6] In the thick of changing the responses to requests --- Client/index.html | 3 ++- Client/scripts.js | 31 ++++++++++++++++++++----------- Client/styles.css | 7 +++++++ Server/webbyBits.py | 33 +++++++++++++++++---------------- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Client/index.html b/Client/index.html index 7172540..428fb2d 100644 --- a/Client/index.html +++ b/Client/index.html @@ -5,6 +5,7 @@ + @@ -107,7 +108,7 @@ changes visibility with JS-->

Wipe the playlist, except the currently playing song*

-

PartyJukebox is under an AGPLV3 liscense. You can access the source code here.

+

PartyJukebox is under an AGPLV3 liscense. You can access the source code here.

diff --git a/Client/scripts.js b/Client/scripts.js index 826709f..1d34c71 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -2,7 +2,7 @@ let ip; let alertTime = 2; let adminPass = ""; -const ERR_NO_ADMIN = "401"; // gonna use this later to refactor +const ERR_NO_ADMIN = 401; // gonna use this later to refactor const VALID_FILE_EXT = ["mp3","flac","wav"]; const params = new URLSearchParams(location.search); @@ -46,8 +46,9 @@ async function getFromServer(bodyInfo, source="",password=adminPass) { "Content-type": "application/json; charset=UTF-8" } }); + const data = await response.json(); - if (data == ERR_NO_ADMIN) { + if (response.status == ERR_NO_ADMIN) { // im suprised i didn't comment on this already but this is kinda lame desing // its not wrong but you know // it is easy which i like @@ -56,9 +57,11 @@ async function getFromServer(bodyInfo, source="",password=adminPass) { } return await data; } catch(e) { + console.log("error print here:"); + console.log(e); if (e == "TypeError: Failed to fetch"){ alertText("Error: Can't Connect to Server (is the ip set?)") - } else if(e == "") { + } else if(e === "") { } else { alertText("Error: " + e); @@ -155,6 +158,13 @@ async function searchSongs(searchTerm){ newItem.appendChild(image); newItem.appendChild(head3); newItem.appendChild(head4); + // I like this concept but i'm leaving it out for now + // if(currentSongInJSON.lossless === 1) { + // let losslesstag = document.createElement("p"); + // losslesstag.textContent = "Ⓛ"; + // losslesstag.classList.add("lossless-tag"); + // newItem.appendChild(losslesstag); + // } document.getElementById("songlist").appendChild(newItem); } @@ -301,7 +311,7 @@ async function generateVisualPlaylist(conditions="") { let timeLeft =document.createElement("h5"); timeLeft.style.fontWeight = 100; try { - if (i == 0) { + if (i == 0) { // Only the first song in the loop gets a time head5.innerHTML="Playing"; if ((conditions != "skip-button")) { let mins = Math.floor(playlist[i]["time"]/60); @@ -313,7 +323,7 @@ async function generateVisualPlaylist(conditions="") { } }catch(err){ // i dont know why there's a try catch here but i'm leaving it i dont want to break something - console.log(err) + console.error(err) } let textdiv = document.createElement("div") textdiv.className="text" @@ -332,11 +342,9 @@ async function submitSong(songid) { let returncode = await getFromServer({song: songid}, "songadd"); if(returncode == ERR_NO_ADMIN) { // right now the error is alerted in getFromServer, maybe will change that - } - else if(returncode["error"]=="song-in-queue") { + } else if(returncode["error"]=="song-in-queue") { alertText("That song's about to play! Hang on!") - } - else { + } else { alertText("Added to Queue"); } } @@ -346,11 +354,10 @@ function checkWhatSongWasClicked(e) { if ((itemId.length-itemId.lastIndexOf("image") == 5) && itemId.lastIndexOf("image")!=-1) { itemId = itemId.slice(0,-6) } + let filenameSep = itemId.split('.') //i feel like later kristy won't apreciate this //one of my files was "file.MP3" so it didn't work //windows be like - let filenameSep = itemId.split('.') - if (VALID_FILE_EXT.includes(filenameSep[filenameSep.length-1].toLowerCase())) { submitSong(itemId); } @@ -443,6 +450,8 @@ document.getElementById("volumerange").onchange = async function() { if (returnValue == ERR_NO_ADMIN) { // alertText("Error: Admin restricted action"); // there's an admin restrict alert built into getFromServer + // i wanna put the volume slider back to where it was but idk a good way to keep the previous volume + checkSettings(false); } else if (returnValue["volumePassed"] !=0) { // i forgot about this, i had to do this because it confused the crap out of me one time // vlc doesn't let you change the volume of nothing, which makes sense if you think about it diff --git a/Client/styles.css b/Client/styles.css index 024e988..21f7b7c 100644 --- a/Client/styles.css +++ b/Client/styles.css @@ -134,6 +134,7 @@ h4 { .songlist > .item > h3, .songlist > .item > h4{ margin-left: 2px; margin-right: 2px; + margin: 5px; word-wrap: break-word; } @@ -152,6 +153,12 @@ h4 { width: 20%; min-width: 50px; } + +.lossless-tag { + width:16px; + padding: 1px; + margin-left: auto; +} /* playlist mode stuff */ .playlist { diff --git a/Server/webbyBits.py b/Server/webbyBits.py index 130131b..056d23f 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -10,10 +10,9 @@ parser.add_argument('-a','--admin',help="Add an admin password to be used in the args = parser.parse_args() dotenv.load_dotenv() portTheUserPicked=os.getenv("SERVER_PORT") -# Just a note that the return code "401" as of now is used to mean "you don't have the password" -# This is not great design, and the whole "returning string codes" thing is something to add to the todo list -# I mean returning 200 when no return is necesary i think is fine but we'll see -ERR_NO_ADMIN = "401" + +ERR_NO_ADMIN = ({"error":"no-admin"},401) +ERR_200 = ({"error":"OK"},200) if args.admin: ADMIN_PASS = hashlib.sha256(bytes(args.admin,'utf-8')).hexdigest() else: @@ -99,7 +98,8 @@ def playQueuedSongs(): # the above 2 means this only applies if (a song is playing or paused) and (the queue is empty) playlist.append(result[0][0]) # check for new songs every second - # I just didn't want to eat too much processing looping + # I just didn't want to eat too much processing looping + # this also has another useful affect that skips get "queued" to only 1 per second, that way somebody usually can't skip twice accidentally time.sleep(1) @app.route("/controls", methods=['POST']) @@ -112,26 +112,27 @@ def playerControls(): if recieveData["control"] == "play-pause": if ADMIN_PASS == recieveData['password'] or controlPerms["PP"]: player.pause() - return "200" + return ERR_200 else: return ERR_NO_ADMIN elif recieveData["control"] == "skip": if ADMIN_PASS == recieveData['password'] or controlPerms["SK"]: skipNow = True - return "200" + return ERR_200 else: return ERR_NO_ADMIN + # Maybe i should have put this next one in the "settings" section elif recieveData["control"] == "clear": if ADMIN_PASS == recieveData['password']: # this is only ever allowed with the adminpassword with playlistLock: playlist.clear() - return "200" + return ERR_200 else: return ERR_NO_ADMIN else: - return "400" + return {"error":"Not a valid control"},400 else: - return "400" + return {"error":"No control sent"},400 @app.route("/settings", methods=['POST']) def settingsControl(): @@ -149,14 +150,13 @@ def settingsControl(): elif recieveData["setting"] == "partymode-toggle": if ADMIN_PASS == recieveData['password'] or controlPerms["PM"]: partyMode = not(partyMode) - return "200" + return ERR_200 else: return ERR_NO_ADMIN elif recieveData["setting"] == "perms": - if ADMIN_PASS == recieveData["password"] and ADMIN_PASS: - #if an adminpass doesn't exist these perms can never be changed + if ADMIN_PASS == recieveData["password"]: controlPerms = recieveData["admin"] - return "200" + return ERR_200 else: return ERR_NO_ADMIN elif recieveData["setting"] == "getsettings": @@ -184,7 +184,8 @@ def searchSongDB(): "title": i[1], "artist": i[2], "art": i[3], - "length": i[4] + "length": i[4], + "lossless":i[5] } fileofDB.close() return tempdata @@ -201,7 +202,7 @@ def songadd(): # probably with a checkbox like the other admin controls if True: queueSong(recieveData['song']) - return "200" + return ERR_200 else: # the password is incorrect (technically a password not existing falls into the above case because controlPerms is never changed) return ERR_NO_ADMIN From 0b64a6f29721b4033ba5d3fb441a3b138c82eeb0 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:09:26 -0500 Subject: [PATCH 2/6] Okay the backend should be done so im committing now im gonna fix the frontend next --- Client/scripts.js | 7 +++---- Server/webbyBits.py | 27 ++++++++++++++++----------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Client/scripts.js b/Client/scripts.js index 1d34c71..8f556be 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -59,10 +59,8 @@ async function getFromServer(bodyInfo, source="",password=adminPass) { } catch(e) { console.log("error print here:"); console.log(e); - if (e == "TypeError: Failed to fetch"){ + if (e.contains("TypeError: Failed to fetch")){ alertText("Error: Can't Connect to Server (is the ip set?)") - } else if(e === "") { - } else { alertText("Error: " + e); } @@ -133,7 +131,8 @@ function searchSongsEnter(e) { async function searchSongs(searchTerm){ document.getElementById("songlist").innerHTML = "" - searchResults = await getFromServer({search:searchTerm},"search").then() + let fetchResults = await getFromServer({search:searchTerm},"search").then(); + let searchResults = fetchResults.data; //generate the visual song list for(var fileName in searchResults) { let currentSongInJSON = searchResults[fileName] diff --git a/Server/webbyBits.py b/Server/webbyBits.py index 056d23f..65cd09a 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -11,8 +11,8 @@ args = parser.parse_args() dotenv.load_dotenv() portTheUserPicked=os.getenv("SERVER_PORT") -ERR_NO_ADMIN = ({"error":"no-admin"},401) -ERR_200 = ({"error":"OK"},200) +ERR_NO_ADMIN = ({"error":"no-admin","data":None},401) +ERR_200 = ({"error":"OK","data":None},200) if args.admin: ADMIN_PASS = hashlib.sha256(bytes(args.admin,'utf-8')).hexdigest() else: @@ -130,9 +130,9 @@ def playerControls(): else: return ERR_NO_ADMIN else: - return {"error":"Not a valid control"},400 + return {"error":"Not a valid control","data":None},400 else: - return {"error":"No control sent"},400 + return {"error":"No control sent","data":None},400 @app.route("/settings", methods=['POST']) def settingsControl(): @@ -143,8 +143,11 @@ def settingsControl(): recieveData = request.get_json(force=True) if recieveData["setting"] == "volume": if ADMIN_PASS == recieveData['password'] or controlPerms["VOL"]: - volumePassed = player.audio_set_volume(int(recieveData["level"])) - return {"volumePassed":volumePassed} + if(recieveData["level"] <= 100 and recieveData["level"] >= 0): + volumePassed = player.audio_set_volume(int(recieveData["level"])) + return {"error":"ok","data":{"volumePassed":volumePassed}},200 + else: + return {"error":"Invalid volume level","data":None} else: return ERR_NO_ADMIN elif recieveData["setting"] == "partymode-toggle": @@ -161,9 +164,9 @@ def settingsControl(): return ERR_NO_ADMIN elif recieveData["setting"] == "getsettings": # probably should have made this a different request type or something but it works - return {"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms} + return {"error":"ok","data":{"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms}},200 else: - return "400" + return {"error":"Not a valid setting","data":None},400 @app.route("/search", methods=['POST']) def searchSongDB(): @@ -188,12 +191,13 @@ def searchSongDB(): "lossless":i[5] } fileofDB.close() - return tempdata + + return {"error":"ok","data":tempdata},200 @app.route("/songadd", methods=["POST"]) def songadd(): recieveData=request.get_json(force=True) - if (ADMIN_PASS and ADMIN_PASS == recieveData['password']) or controlPerms["AS"]: + if (ADMIN_PASS == recieveData['password']) or controlPerms["AS"]: # Password exists and is correct, or it's not restricted # if (recieveData['song'] in playlist): # return {"error":"song-in-queue"} @@ -239,7 +243,8 @@ def getPlaylist(): } tempPlaylist.append({i:k}) fileofDB.close() - return tempPlaylist + + return {"error":"ok","data":tempPlaylist} if __name__ == "__main__": # There's not really a whole lot of point to a main function for something like this, you'd never use any of these methods From 00550cca852fe7433a8257aa9de7686238ff8ab1 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:39:17 -0500 Subject: [PATCH 3/6] I got distracted and broke something but the responses should be good now --- Client/scripts.js | 25 +++++++++++++++++-------- Server/webbyBits.py | 9 +++++---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Client/scripts.js b/Client/scripts.js index 8f556be..9ecb8a8 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -2,7 +2,7 @@ let ip; let alertTime = 2; let adminPass = ""; -const ERR_NO_ADMIN = 401; // gonna use this later to refactor +const ERR_NO_ADMIN = 401; const VALID_FILE_EXT = ["mp3","flac","wav"]; const params = new URLSearchParams(location.search); @@ -54,12 +54,15 @@ async function getFromServer(bodyInfo, source="",password=adminPass) { // it is easy which i like // and it overrides any other non-async alerts which is nice alertText("Error: Admin restricted action") + } else if(response.status !== 200){ + alertText("Error: "+data.error); } + data["status"] = response.status; return await data; } catch(e) { console.log("error print here:"); console.log(e); - if (e.contains("TypeError: Failed to fetch")){ + if (e == "TypeError: Failed to fetch"){ alertText("Error: Can't Connect to Server (is the ip set?)") } else { alertText("Error: " + e); @@ -87,6 +90,8 @@ function getCookie(cname) { return ""; } //someone more organised than me would have set all these html elements to variables so they dont have to get them 50 times +// also someone who likes things not being dumb more than me would have separated the client and server buttons +let timer = null; async function controlButton(buttonType) { if (buttonType == "pp") { // Play-Pause button getFromServer({control: "play-pause"}, "controls") @@ -101,6 +106,9 @@ async function controlButton(buttonType) { document.getElementById("playlist-mode").style.display = "block"; document.getElementById("songlist-mode").style.display = "none"; document.getElementById("settings-mode").style.display = "none"; + timer = setInterval(() => { + + }) generateVisualPlaylist(); } else if (buttonType == "se") { //SearchMode button document.getElementById("songlist").innerHTML = "

Search to find songs!

"; @@ -246,7 +254,8 @@ async function checkSettings(skipServer=false) { } } //ping the server here - x = await getFromServer({setting: "getsettings"}, "settings"); + data = await getFromServer({setting: "getsettings"}, "settings"); + x = data["data"]; if (!(skipServer) || partyButtonState=="N/A") { if (x["partymode"] == false) { document.getElementById("partymode-button").innerHTML = "Off"; @@ -271,7 +280,8 @@ async function checkSettings(skipServer=false) { async function generateVisualPlaylist(conditions="") { document.getElementById("playlist").innerHTML = "

"; - playlist = await getFromServer(null, "playlist"); + data = await getFromServer(null, "playlist"); + playlist = data["data"]; playlist = Object.values(playlist).map(obj => { const filename = Object.keys(obj)[0]; // Get the filename const songData = obj[filename]; // Get the song metadata @@ -446,18 +456,17 @@ document.getElementById("volumerange").onchange = async function() { // there is no reason for this not to be a defined function // FIX THIS let returnValue = await getFromServer({setting:"volume",level:this.value}, "settings") - if (returnValue == ERR_NO_ADMIN) { + if (returnValue["status"] == ERR_NO_ADMIN) { // alertText("Error: Admin restricted action"); // there's an admin restrict alert built into getFromServer // i wanna put the volume slider back to where it was but idk a good way to keep the previous volume checkSettings(false); - } else if (returnValue["volumePassed"] !=0) { + } else if (returnValue["data"]["volumePassed"] !=0) { // i forgot about this, i had to do this because it confused the crap out of me one time // vlc doesn't let you change the volume of nothing, which makes sense if you think about it alertText("Nothing is playing") document.getElementById("volumerange").value = -1 - } - else if (this.value == 0) { + } else if (this.value == 0) { alertText("The volume is now set to 0 (Pause?)") } else { alertText("The volume is now set to " + this.value.toString()) diff --git a/Server/webbyBits.py b/Server/webbyBits.py index 65cd09a..a506e82 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -143,11 +143,12 @@ def settingsControl(): recieveData = request.get_json(force=True) if recieveData["setting"] == "volume": if ADMIN_PASS == recieveData['password'] or controlPerms["VOL"]: - if(recieveData["level"] <= 100 and recieveData["level"] >= 0): - volumePassed = player.audio_set_volume(int(recieveData["level"])) + volumeLevel = int(recieveData["level"]) + if(volumeLevel <= 100 and volumeLevel >= 0): + volumePassed = player.audio_set_volume(volumeLevel) return {"error":"ok","data":{"volumePassed":volumePassed}},200 else: - return {"error":"Invalid volume level","data":None} + return {"error":"Invalid volume level","data":None},422 else: return ERR_NO_ADMIN elif recieveData["setting"] == "partymode-toggle": @@ -166,7 +167,7 @@ def settingsControl(): # probably should have made this a different request type or something but it works return {"error":"ok","data":{"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms}},200 else: - return {"error":"Not a valid setting","data":None},400 + return {"error":"Not a valid setting","data":None},422 @app.route("/search", methods=['POST']) def searchSongDB(): From 417ecc8cede000e8b614ae940875055afcf38403 Mon Sep 17 00:00:00 2001 From: Kristy Fournier <124598538+kristy-fournier@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:50:59 -0500 Subject: [PATCH 4/6] messing around, will fix later --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3920035..87c9ad3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ server/sound/ *.db start.bat -.env \ No newline at end of file +.env +venv/ \ No newline at end of file From 2002dd1afaa4bd7ff70bada3567bfdd253f21395 Mon Sep 17 00:00:00 2001 From: Kristy Fournier Date: Mon, 26 Jan 2026 12:15:56 -0500 Subject: [PATCH 5/6] removed broken timer, finalised new responses --- Client/scripts.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Client/scripts.js b/Client/scripts.js index 9ecb8a8..8b97fbd 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -47,21 +47,24 @@ async function getFromServer(bodyInfo, source="",password=adminPass) { } }); - const data = await response.json(); + let data = await response.json(); // original json if (response.status == ERR_NO_ADMIN) { // im suprised i didn't comment on this already but this is kinda lame desing // its not wrong but you know // it is easy which i like // and it overrides any other non-async alerts which is nice alertText("Error: Admin restricted action") - } else if(response.status !== 200){ + } else if(!response.ok){ alertText("Error: "+data.error); } + // we add some information from the response just in case it is needed + data["ok"] = response.ok; data["status"] = response.status; + // console.log(data); return await data; } catch(e) { - console.log("error print here:"); - console.log(e); + // console.log("error print here:"); + // console.log(e); if (e == "TypeError: Failed to fetch"){ alertText("Error: Can't Connect to Server (is the ip set?)") } else { @@ -91,7 +94,6 @@ function getCookie(cname) { } //someone more organised than me would have set all these html elements to variables so they dont have to get them 50 times // also someone who likes things not being dumb more than me would have separated the client and server buttons -let timer = null; async function controlButton(buttonType) { if (buttonType == "pp") { // Play-Pause button getFromServer({control: "play-pause"}, "controls") @@ -106,9 +108,6 @@ async function controlButton(buttonType) { document.getElementById("playlist-mode").style.display = "block"; document.getElementById("songlist-mode").style.display = "none"; document.getElementById("settings-mode").style.display = "none"; - timer = setInterval(() => { - - }) generateVisualPlaylist(); } else if (buttonType == "se") { //SearchMode button document.getElementById("songlist").innerHTML = "

Search to find songs!

"; From fce09edfc555a54a97cf6a6ca65d4df45c289c39 Mon Sep 17 00:00:00 2001 From: Kristy Fournier Date: Mon, 26 Jan 2026 12:30:08 -0500 Subject: [PATCH 6/6] Added proper handling of internal errors (should be no 500s anywhere) --- Client/scripts.js | 1 - Server/webbyBits.py | 135 ++++++++++++++++++++++++-------------------- 2 files changed, 75 insertions(+), 61 deletions(-) diff --git a/Client/scripts.js b/Client/scripts.js index 8b97fbd..cb7361e 100644 --- a/Client/scripts.js +++ b/Client/scripts.js @@ -38,7 +38,6 @@ async function getFromServer(bodyInfo, source="",password=adminPass) { // the currently set password is always included in every request bodyInfo["password"] = password; } - // console.log(bodyInfo); const response = await fetch("http://"+ip+"/"+source, { method: "POST", body: JSON.stringify(bodyInfo), diff --git a/Server/webbyBits.py b/Server/webbyBits.py index a506e82..d0d2e36 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -13,6 +13,7 @@ portTheUserPicked=os.getenv("SERVER_PORT") ERR_NO_ADMIN = ({"error":"no-admin","data":None},401) ERR_200 = ({"error":"OK","data":None},200) +ERR_MISSING_ARGS = ({"error":"Request missing required arguments","data":None}),400 if args.admin: ADMIN_PASS = hashlib.sha256(bytes(args.admin,'utf-8')).hexdigest() else: @@ -108,7 +109,7 @@ def playerControls(): global skipNow global partyMode recieveData=request.get_json(force=True) - if recieveData["control"] != None: + try: if recieveData["control"] == "play-pause": if ADMIN_PASS == recieveData['password'] or controlPerms["PP"]: player.pause() @@ -131,8 +132,8 @@ def playerControls(): return ERR_NO_ADMIN else: return {"error":"Not a valid control","data":None},400 - else: - return {"error":"No control sent","data":None},400 + except KeyError: + return ERR_MISSING_ARGS @app.route("/settings", methods=['POST']) def settingsControl(): @@ -141,76 +142,90 @@ def settingsControl(): global partyMode global player recieveData = request.get_json(force=True) - if recieveData["setting"] == "volume": - if ADMIN_PASS == recieveData['password'] or controlPerms["VOL"]: - volumeLevel = int(recieveData["level"]) - if(volumeLevel <= 100 and volumeLevel >= 0): - volumePassed = player.audio_set_volume(volumeLevel) - return {"error":"ok","data":{"volumePassed":volumePassed}},200 + try: + if recieveData["setting"] == "volume": + if ADMIN_PASS == recieveData['password'] or controlPerms["VOL"]: + volumeLevel = int(recieveData["level"]) + if(volumeLevel <= 100 and volumeLevel >= 0): + volumePassed = player.audio_set_volume(volumeLevel) + return {"error":"ok","data":{"volumePassed":volumePassed}},200 + else: + return {"error":"Invalid volume level","data":None},422 else: - return {"error":"Invalid volume level","data":None},422 + return ERR_NO_ADMIN + elif recieveData["setting"] == "partymode-toggle": + if ADMIN_PASS == recieveData['password'] or controlPerms["PM"]: + partyMode = not(partyMode) + return ERR_200 + else: + return ERR_NO_ADMIN + elif recieveData["setting"] == "perms": + if ADMIN_PASS == recieveData["password"]: + controlPerms = recieveData["admin"] + return ERR_200 + else: + return ERR_NO_ADMIN + elif recieveData["setting"] == "getsettings": + # probably should have made this a different request type or something but it works + return {"error":"ok","data":{"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms}},200 else: - return ERR_NO_ADMIN - elif recieveData["setting"] == "partymode-toggle": - if ADMIN_PASS == recieveData['password'] or controlPerms["PM"]: - partyMode = not(partyMode) - return ERR_200 - else: - return ERR_NO_ADMIN - elif recieveData["setting"] == "perms": - if ADMIN_PASS == recieveData["password"]: - controlPerms = recieveData["admin"] - return ERR_200 - else: - return ERR_NO_ADMIN - elif recieveData["setting"] == "getsettings": - # probably should have made this a different request type or something but it works - return {"error":"ok","data":{"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms}},200 - else: - return {"error":"Not a valid setting","data":None},422 + return {"error":"Not a valid setting","data":None},400 + except: + return ERR_MISSING_ARGS @app.route("/search", methods=['POST']) def searchSongDB(): recieveData=request.get_json(force=True) fileofDB = sql.connect("songDatabase.db") songDatabase = fileofDB.cursor() - results = [] - if (recieveData['search'] == ""): - songDatabase.execute("SELECT * FROM virtualSongs") - results = songDatabase.fetchall() - else: - songDatabase.execute("SELECT * FROM virtualSongs WHERE virtualSongs MATCH ?",[recieveData['search']]) - results = songDatabase.fetchall() - tempdata = {} - # this is a temporary solution so i dont have to change the client - for i in results: - tempdata[i[0]] = { - "title": i[1], - "artist": i[2], - "art": i[3], - "length": i[4], - "lossless":i[5] - } - fileofDB.close() + try: + results = [] + if (recieveData['search'] == ""): + songDatabase.execute("SELECT * FROM virtualSongs") + results = songDatabase.fetchall() + else: + songDatabase.execute("SELECT * FROM virtualSongs WHERE virtualSongs MATCH ?",[recieveData['search']]) + results = songDatabase.fetchall() + tempdata = {} + # this is a temporary solution so i dont have to change the client + for i in results: + tempdata[i[0]] = { + "title": i[1], + "artist": i[2], + "art": i[3], + "length": i[4], + "lossless":i[5] + } + fileofDB.close() + + return {"error":"ok","data":tempdata},200 + except KeyError: + fileofDB.close() + return ERR_MISSING_ARGS + except sql.OperationalError: + fileofDB.close() + return ({"error":"Invalid search, sorry!","data":None},422) - return {"error":"ok","data":tempdata},200 @app.route("/songadd", methods=["POST"]) def songadd(): recieveData=request.get_json(force=True) - if (ADMIN_PASS == recieveData['password']) or controlPerms["AS"]: - # Password exists and is correct, or it's not restricted - # if (recieveData['song'] in playlist): - # return {"error":"song-in-queue"} - # else: - # Right now the above is disabled since i want to make it optional first - # probably with a checkbox like the other admin controls - if True: - queueSong(recieveData['song']) - return ERR_200 - else: - # the password is incorrect (technically a password not existing falls into the above case because controlPerms is never changed) - return ERR_NO_ADMIN + try: + if (ADMIN_PASS == recieveData['password']) or controlPerms["AS"]: + # Password exists and is correct, or it's not restricted + # if (recieveData['song'] in playlist): + # return {"error":"song-in-queue"} + # else: + # Right now the above is disabled since i want to make it optional first + # probably with a checkbox like the other admin controls + if True: + queueSong(recieveData['song']) + return ERR_200 + else: + # the password is incorrect (technically a password not existing falls into the above case because controlPerms is never changed) + return ERR_NO_ADMIN + except KeyError: + return ERR_MISSING_ARGS @app.route("/playlist", methods=["POST"]) def getPlaylist():