diff --git a/Server/__pycache__/versionNum.cpython-313.pyc b/Server/__pycache__/versionNum.cpython-313.pyc
new file mode 100644
index 0000000..d9f0a4b
Binary files /dev/null and b/Server/__pycache__/versionNum.cpython-313.pyc differ
diff --git a/Server/static/scripts.js b/Server/static/scripts.js
index 6b1e019..688c8a8 100644
--- a/Server/static/scripts.js
+++ b/Server/static/scripts.js
@@ -198,11 +198,17 @@ function searchSongsEnter(e) {
}
}
-async function searchSongs(searchTerm){
+async function searchSongs(searchTerm,page=-1){
document.getElementById("songlist").innerHTML = ""
- let fetchResults = await getFromServer("search?query="+searchTerm);
- let searchResults = fetchResults.data;
+ let fetchResults = await getFromServer("search?query="+searchTerm+"&page="+page);
+ let searchResults = fetchResults.data.songsobj;
//generate the visual song list
+ // let x = document.createElement("button")
+ // x.addEventListener("click",()=>{
+ // 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)