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
This commit is contained in:
parent
151ed839c3
commit
8a5534482b
6 changed files with 98 additions and 13 deletions
BIN
Server/__pycache__/versionNum.cpython-313.pyc
Normal file
BIN
Server/__pycache__/versionNum.cpython-313.pyc
Normal file
Binary file not shown.
|
|
@ -198,11 +198,17 @@ function searchSongsEnter(e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchSongs(searchTerm){
|
async function searchSongs(searchTerm,page=-1){
|
||||||
document.getElementById("songlist").innerHTML = ""
|
document.getElementById("songlist").innerHTML = ""
|
||||||
let fetchResults = await getFromServer("search?query="+searchTerm);
|
let fetchResults = await getFromServer("search?query="+searchTerm+"&page="+page);
|
||||||
let searchResults = fetchResults.data;
|
let searchResults = fetchResults.data.songsobj;
|
||||||
//generate the visual song list
|
//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) {
|
for(var fileName in searchResults) {
|
||||||
let currentSongInJSON = searchResults[fileName]
|
let currentSongInJSON = searchResults[fileName]
|
||||||
let newItem = document.createElement("div");
|
let newItem = document.createElement("div");
|
||||||
|
|
@ -241,6 +247,8 @@ async function searchSongs(searchTerm){
|
||||||
if (JSON.stringify(searchResults)==JSON.stringify({})) {
|
if (JSON.stringify(searchResults)==JSON.stringify({})) {
|
||||||
//display error if no results
|
//display error if no results
|
||||||
document.getElementById("songlist").innerHTML = "<h1>We might not have that one...</h1>";
|
document.getElementById("songlist").innerHTML = "<h1>We might not have that one...</h1>";
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ changes visibility with JS-->
|
||||||
<button id="clear-button">Clear Playlist</button>
|
<button id="clear-button">Clear Playlist</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="versionNumber italic">PartyJukebox is under an <a href="https://github.com/kristy-fournier/PartyJukebox/blob/main/LICENSE.md" target="_blank">AGPLV3</a> liscense. You can access the source code <a href=https://github.com/kristy-fournier/PartyJukebox target="_blank">here</a>.</p>
|
<p class="versionNumber italic">PartyJukebox is under an <a href="https://github.com/kristy-fournier/PartyJukebox/blob/main/LICENSE.md" target="_blank">AGPLV3</a> liscense. You can access the source code <a href=https://github.com/kristy-fournier/PartyJukebox target="_blank">here</a>.</p>
|
||||||
<p class="versionNumber">Release {{ REL_VER_NUM }}</p>
|
<p class="versionNumber italic">Release {{ REL_VER_NUM }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--All the buttons are down here but settings is just doing its own thing-->
|
<!--All the buttons are down here but settings is just doing its own thing-->
|
||||||
|
|
|
||||||
67
Server/versionNum.py
Normal file
67
Server/versionNum.py
Normal file
|
|
@ -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<x}")
|
||||||
|
print(f"Z >= Y: {z>=y}")
|
||||||
|
print(f"Z <= Y: {z<=y}")
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import eventlet
|
# import eventlet
|
||||||
eventlet.monkey_patch()
|
# eventlet.monkey_patch()
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask import request,render_template
|
from flask import request,render_template
|
||||||
from flask_cors import CORS
|
|
||||||
from flask_socketio import SocketIO
|
from flask_socketio import SocketIO
|
||||||
import sqlite3 as sql
|
import sqlite3 as sql
|
||||||
import vlc,threading,random,argparse,dotenv,os,hashlib,string,getpass
|
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
|
# 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
|
# Argparse Stuff
|
||||||
parser=argparse.ArgumentParser(description="Options for the Webby Bits")
|
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_NO_ADMIN = ({"error":"no-admin","data":None},401)
|
||||||
ERR_200 = ({"error":"OK","data":None},200)
|
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":
|
if bool(args.admin) and args.admin.lower() != "false":
|
||||||
ADMIN_PASS = hashlib.sha256(bytes(getpass.getpass("Enter AdminPass: "),'utf-8')).hexdigest()
|
ADMIN_PASS = hashlib.sha256(bytes(getpass.getpass("Enter AdminPass: "),'utf-8')).hexdigest()
|
||||||
else:
|
else:
|
||||||
|
|
@ -47,6 +47,7 @@ try:
|
||||||
soundLocation = songDatabase.fetchall()[0][1]
|
soundLocation = songDatabase.fetchall()[0][1]
|
||||||
except sql.OperationalError:
|
except sql.OperationalError:
|
||||||
print("No Database Found, try running databaseGenerator.py")
|
print("No Database Found, try running databaseGenerator.py")
|
||||||
|
os._exit(1)
|
||||||
if soundLocation[-1] == "/" or soundLocation[-1] == "\\":
|
if soundLocation[-1] == "/" or soundLocation[-1] == "\\":
|
||||||
pass
|
pass
|
||||||
elif "/" in soundLocation:
|
elif "/" in soundLocation:
|
||||||
|
|
@ -147,7 +148,7 @@ def handleConnect():
|
||||||
|
|
||||||
@app.route("/",methods=['GET'])
|
@app.route("/",methods=['GET'])
|
||||||
def returnStaticFile():
|
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'])
|
@app.route("/controls", methods=['POST'])
|
||||||
def playerControls():
|
def playerControls():
|
||||||
|
|
@ -232,6 +233,9 @@ def settingsControl():
|
||||||
@app.route("/search", methods=['GET'])
|
@app.route("/search", methods=['GET'])
|
||||||
def searchSongDB():
|
def searchSongDB():
|
||||||
recieveData = request.args.get("query")
|
recieveData = request.args.get("query")
|
||||||
|
page = int(request.args.get("page"))
|
||||||
|
if not(page):
|
||||||
|
page = 1
|
||||||
fileofDB = sql.connect("songDatabase.db")
|
fileofDB = sql.connect("songDatabase.db")
|
||||||
songDatabase = fileofDB.cursor()
|
songDatabase = fileofDB.cursor()
|
||||||
try:
|
try:
|
||||||
|
|
@ -243,6 +247,12 @@ def searchSongDB():
|
||||||
else:
|
else:
|
||||||
songDatabase.execute("SELECT * FROM virtualSongs WHERE virtualSongs MATCH ?",['"' + recieveData +'"'])
|
songDatabase.execute("SELECT * FROM virtualSongs WHERE virtualSongs MATCH ?",['"' + recieveData +'"'])
|
||||||
results = songDatabase.fetchall()
|
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 = {}
|
tempdata = {}
|
||||||
# this is a temporary solution so i dont have to change the client
|
# this is a temporary solution so i dont have to change the client
|
||||||
for i in results:
|
for i in results:
|
||||||
|
|
@ -255,7 +265,7 @@ def searchSongDB():
|
||||||
}
|
}
|
||||||
fileofDB.close()
|
fileofDB.close()
|
||||||
|
|
||||||
return {"error":"ok","data":tempdata},200
|
return {"error":"ok","data":{"songsobj":tempdata,"pages":pages}},200
|
||||||
except sql.OperationalError as e:
|
except sql.OperationalError as e:
|
||||||
print(e)
|
print(e)
|
||||||
fileofDB.close()
|
fileofDB.close()
|
||||||
|
|
@ -325,6 +335,6 @@ if __name__ == "__main__":
|
||||||
queueThread = threading.Thread(target=playQueuedSongs)
|
queueThread = threading.Thread(target=playQueuedSongs)
|
||||||
queueThread.daemon = True
|
queueThread.daemon = True
|
||||||
queueThread.start()
|
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)
|
socketio.run(app=app,host='0.0.0.0', port=portTheUserPicked)
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
- [ ] Security Updates
|
- [ ] Security Updates
|
||||||
- [x] `.env` file for the api keys and other runtime info to be set, rather than in the `.py` files
|
- [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)
|
- [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
|
- [ ] Accessibility
|
||||||
- [ ] Better use of semantic HTML tags
|
- [ ] Better use of semantic HTML tags
|
||||||
- [ ] Full keyboard control (tab, enter to select, tab between control buttons)
|
- [ ] Full keyboard control (tab, enter to select, tab between control buttons)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue