From 8a5534482be6d379b39a9193ae17832306e2c165 Mon Sep 17 00:00:00 2001 From: Kristy F <124598538+kristy-fournier@users.noreply.github.com> Date: Tue, 14 Apr 2026 12:53:26 -0400 Subject: [PATCH] Add versionNum Object, pages for search This will be tweaked a lot more but i really need to go study for something instead of doing this --- Server/__pycache__/versionNum.cpython-313.pyc | Bin 0 -> 4355 bytes Server/static/scripts.js | 14 +++- Server/templates/index.html | 2 +- Server/versionNum.py | 67 ++++++++++++++++++ Server/webbyBits.py | 26 ++++--- wishlist.md | 2 +- 6 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 Server/__pycache__/versionNum.cpython-313.pyc create mode 100644 Server/versionNum.py diff --git a/Server/__pycache__/versionNum.cpython-313.pyc b/Server/__pycache__/versionNum.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9f0a4b7c21233a25f04d43394470e70b2bc64a6 GIT binary patch literal 4355 zcmbUkTTmO<^{%ulRzgBD5(Z1em2Ki$I7qR9*4Efe8NUc|X`6+P08KOk)>v3tk-JOA z(0uUW>5xe}hG`j#si(+aF*8j<`V;%hKmD-#V`-EQ%8uLVwEgiPDemOA=j^ToQWlTX zJ8<^gbM8I&p65N#;4-nQ_pxp{)Lmuu;~c1Gr$nCN(3S>Z<9fWGC|TtjuOG* zCxW%tqOYQsxK&`IF+!3b6B4%opA&3CgTVK)#tJrWd8bjw_d>zm3-WPL8?12a_+A)i zt1I}p{V3U;2Z=VfRrto7ubm5yI2*S`2MB2*-Ih9DqsF^s%5%nTaW)DXn(TAMd64-> zQ(lwC>#XNZyQkeD&vR5Q#Hfu)Ny;ioC6$%r$-U}Y^$D{R2V|AR31tLAEdoQWLL*vz zhNWzr6P$t-@m^yuwFxeP)wm5plfY>hFSrGphS`M%KcNnR2iPdssdL&9@~Ey~id2Rh z49#UGMEV?^ImsCU@q+}o53|z)$SR3>(n!@tESNU@Mo8?67%E`0ol%iTwl0tEJ$fnxC`hr4J(zMzj&1J5F&rIEmLNxaVDW<*ZxJI)X zV`E#bqjotMC$a=!k^G}Ma3``7$sa2CPHp7wTA%K@z zCF9iqfMBR*1F(z%RHG7BDEI}cQD^I@P>t)yt~)4lL!4%BGs{AG;lT%x)o)2M-pepB zH<`{#qUx=+tw!|0D)|_IMS^yD;UrVu=>#iuZFpG433F~p!V7%lxJe66UG5aa1I2z)qE9J?=Gk(AccWYW+9Z{ zr>HN*jHh-0Aq#DSk7}o)GDjtdK^a{bH0;)pNI(cf`Dm%NoI!4dr7}D(V7v0c)*QR; zSaU3YkUy0l{$%XlSpMoJv)S=w=NFxu?FC=olD*vMz8$?CEjwFsr*gyVV{2o%tA#_M zqBFGgR@vQF;M;Tq?+qd}j8<y@-Gyo;*W?3zni=<0&J>xDW$1FquCmJfthjH+s#XXv8h~A@eHa#AqBKi4 zjHqNMvzghNfV3qN;(HK}zWR7X>T4iH{u2O5;*AC2AZF1ZfFsdvwB1-grY?#+v(z}cerY{7Z9 zvZ5!?{ytiAyz{Y$siv90PmIC`{A#)+?~0pwRC~+)bcOHYTb8TV=)BY!VsWP zK#fLS!?bQ)!!QIW`V9m?{nl~Sra!5AZ^+Wa$iP04;w^NlMaQ+RIbv zW>6DHB9X~X&7~1{CKB(>CDR7Sok(0uQCUf+BvHyH5)_NC>Xh-v)nrCgu4kw8NcsVu z*n!{;1Q7(?0Mr(I$Z>TdsX*U4F{g+!$T^J*ptT@cd#c|WuZ}K~@%q0eFDxt<*lr@W z<{gWT`_YaSux-R%G&9^7^TNh*hh8{&uKhngC)fVpc7{8tOGG)ST_%~5;HVauQmh%z z!M{Z1lIhv&$py!$@ab@O*Mz7f7x-B4{Q2N$G`P?Z3-;;AXz*Mx1{8iQ*r)RVJEvho zAqSf5+8p#VU^0q7KXeU#j0Z3`^~Z*pr)U+GS%9Bq(6K9ZN~`=i-Rgbx60CzdN#s8R z*tRkZ^EYzzTT2gf@*4tR8-5P5&ZUKt_0ZRR%W^Wu5`TEH|7+I1bmZ2+cRvHmzkt?!c=>X{5%`L2#|2lG`{ + // searchSongs(searchTerm,page+1); + // }) + // x.textContent = "Next Page" + // document.getElementById("songlist-mode").appendChild(x) for(var fileName in searchResults) { let currentSongInJSON = searchResults[fileName] let newItem = document.createElement("div"); @@ -241,6 +247,8 @@ async function searchSongs(searchTerm){ if (JSON.stringify(searchResults)==JSON.stringify({})) { //display error if no results document.getElementById("songlist").innerHTML = "

We might not have that one...

"; + } else { + } } diff --git a/Server/templates/index.html b/Server/templates/index.html index 8775d11..1cbc5cf 100644 --- a/Server/templates/index.html +++ b/Server/templates/index.html @@ -113,7 +113,7 @@ changes visibility with JS-->

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

-

Release {{ REL_VER_NUM }}

+

Release {{ REL_VER_NUM }}

diff --git a/Server/versionNum.py b/Server/versionNum.py new file mode 100644 index 0000000..123cfbd --- /dev/null +++ b/Server/versionNum.py @@ -0,0 +1,67 @@ +from __future__ import annotations +class VersionNumber: + def __init__(self,major:int,minor:int,patch:int,extra:str): + self.major = major + self.minor = minor + self.patch = patch + self.extra = extra + + # From String like "x.y.z-extra" + @staticmethod + def fromString(verString:str) -> VersionNumber: + numList = verString.split(".") + major = int(numList[0]) + minor = int(numList[1]) + patch = int(numList[2].split("-")[0]) + extra = numList[2].split("-")[1] + return VersionNumber(major,minor,patch,extra) + + + def clone(verNumIn:VersionNumber) -> VersionNumber: + return VersionNumber(verNumIn.major,verNumIn.minor,verNumIn.patch,verNumIn.extra) + + def __str__(self) -> str: + returnStr = f"v{self.major}.{self.minor}.{self.patch}" + if(self.extra): + returnStr += f"-{self.extra}" + return returnStr + + def __eq__(self,comp) -> bool: + if type(comp) == VersionNumber: + return self.major == comp.major and self.minor == comp.minor and self.patch == comp.patch and self.extra == comp.extra + elif type(comp) == str: + return self == VersionNumber.fromString(comp) + elif type(comp) == type(None): + return False + else: + raise TypeError + + def __gt__(self,comp): + if type(comp) == VersionNumber: + if(self.major > comp.major): + return True + elif(self.major == comp.major and self.minor > comp.minor): + return True + elif(self.major == comp.major and self.minor == comp.minor and self.patch > comp.patch): + return True + return False + elif type(comp) == str: + return self > VersionNumber.fromString(comp) + else: + raise TypeError + + def __ge__(self,comp): + return self > comp or self == comp + +if __name__ == "__main__": + x = VersionNumber(1,2,4,"alpha") + y = VersionNumber.fromString("1.2.3-beta") + z = VersionNumber.clone(x) + print(x) + print(y) + print(z) + print(f"X == Y: {x==y}") + print(f"X > Y: {x>y}") + print(f"Y < X: {y= Y: {z>=y}") + print(f"Z <= Y: {z<=y}") diff --git a/Server/webbyBits.py b/Server/webbyBits.py index 2b611af..74f98df 100644 --- a/Server/webbyBits.py +++ b/Server/webbyBits.py @@ -1,14 +1,14 @@ -import eventlet -eventlet.monkey_patch() +# import eventlet +# eventlet.monkey_patch() from flask import Flask from flask import request,render_template -from flask_cors import CORS from flask_socketio import SocketIO import sqlite3 as sql import vlc,threading,random,argparse,dotenv,os,hashlib,string,getpass +from versionNum import VersionNumber # So i'm famously bad at following Semantic versioning, we're gonna see how this goes -REL_VER_NUM = "0.0.1" +REL_VER_NUM = VersionNumber(0,0,2,"alpha") # Argparse Stuff parser=argparse.ArgumentParser(description="Options for the Webby Bits") @@ -19,7 +19,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 +ERR_MISSING_ARGS = ({"error":"Request missing required arguments","data":None},400) if bool(args.admin) and args.admin.lower() != "false": ADMIN_PASS = hashlib.sha256(bytes(getpass.getpass("Enter AdminPass: "),'utf-8')).hexdigest() else: @@ -47,6 +47,7 @@ try: soundLocation = songDatabase.fetchall()[0][1] except sql.OperationalError: print("No Database Found, try running databaseGenerator.py") + os._exit(1) if soundLocation[-1] == "/" or soundLocation[-1] == "\\": pass elif "/" in soundLocation: @@ -147,7 +148,7 @@ def handleConnect(): @app.route("/",methods=['GET']) def returnStaticFile(): - return render_template("index.html",REL_VER_NUM=REL_VER_NUM) + return render_template("index.html",REL_VER_NUM=str(REL_VER_NUM)) @app.route("/controls", methods=['POST']) def playerControls(): @@ -232,6 +233,9 @@ def settingsControl(): @app.route("/search", methods=['GET']) def searchSongDB(): recieveData = request.args.get("query") + page = int(request.args.get("page")) + if not(page): + page = 1 fileofDB = sql.connect("songDatabase.db") songDatabase = fileofDB.cursor() try: @@ -243,6 +247,12 @@ def searchSongDB(): else: songDatabase.execute("SELECT * FROM virtualSongs WHERE virtualSongs MATCH ?",['"' + recieveData +'"']) results = songDatabase.fetchall() + pages = (len(results)//20)+1 + if(page>0): + # Numbers <0 use old rendering + inBound = 20*(page-1) + outBound = 20*page + results = results[inBound:outBound] tempdata = {} # this is a temporary solution so i dont have to change the client for i in results: @@ -255,7 +265,7 @@ def searchSongDB(): } fileofDB.close() - return {"error":"ok","data":tempdata},200 + return {"error":"ok","data":{"songsobj":tempdata,"pages":pages}},200 except sql.OperationalError as e: print(e) fileofDB.close() @@ -325,6 +335,6 @@ if __name__ == "__main__": queueThread = threading.Thread(target=playQueuedSongs) queueThread.daemon = True queueThread.start() - print(f"PartyJukebox v{REL_VER_NUM} running on port {portTheUserPicked}") + print(f"PartyJukebox {REL_VER_NUM} running on port {portTheUserPicked}") socketio.run(app=app,host='0.0.0.0', port=portTheUserPicked) \ No newline at end of file diff --git a/wishlist.md b/wishlist.md index 2602f75..13d6bfb 100644 --- a/wishlist.md +++ b/wishlist.md @@ -14,7 +14,7 @@ - [ ] Security Updates - [x] `.env` file for the api keys and other runtime info to be set, rather than in the `.py` files - [x] Hashing rather than plaintext sending passwords (that way at least the password text itself isn't transmitted over the network) - - [ ] Actually use TLS, for posting (CORS seems like an issue) + - [ ] Actually use TLS, for posting - [ ] Accessibility - [ ] Better use of semantic HTML tags - [ ] Full keyboard control (tab, enter to select, tab between control buttons)