Merge pull request #2 from kristy-fournier/dev

Completely redid database layout
This commit is contained in:
Kristy Fournier 2025-03-05 15:50:35 -05:00 committed by GitHub
commit dfc068abf3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 61 additions and 65 deletions

View file

@ -98,35 +98,33 @@ async function searchSongs(searchTerm){
document.getElementById("songlist").innerHTML = "" document.getElementById("songlist").innerHTML = ""
searchResults = await getFromServer({search:searchTerm},"search").then() searchResults = await getFromServer({search:searchTerm},"search").then()
for (let index in searchResults) {
optionslist.push([index,searchResults[index][0],searchResults[index][1],searchResults[index][2]]);
}
//generate the visual song list //generate the visual song list
for(let i = 0; i < optionslist.length; i++) { for(var fileName in searchResults) {
let currentSongInJSON = searchResults[fileName]
let newItem = document.createElement("div"); let newItem = document.createElement("div");
newItem.className = "item"; newItem.className = "item";
newItem.id = optionslist[i][3]; newItem.id = fileName;
let image = document.createElement("img"); let image = document.createElement("img");
try { try {
if (optionslist[i][2] == null) { if (currentSongInJSON["art"] == null) {
throw "no image lolz" throw "no image lolz"
} }
image.src = optionslist[i][2]; image.src = currentSongInJSON["art"];
} catch(err){ } catch(err){
image.src = "./images/placeholder.png"; image.src = "./images/placeholder.png";
} }
image.id = String(optionslist[i][3])+" image"; image.id = String(fileName)+" image";
let head3 = document.createElement("h3"); let head3 = document.createElement("h3");
head3.innerText = optionslist[i][0]; head3.innerText = currentSongInJSON["title"];
let head4 = document.createElement("h4"); let head4 = document.createElement("h4");
head4.innerText=optionslist[i][1]; head4.innerText = currentSongInJSON["artist"];
newItem.appendChild(image); newItem.appendChild(image);
newItem.appendChild(head3); newItem.appendChild(head3);
newItem.appendChild(head4); newItem.appendChild(head4);
document.getElementById("songlist").appendChild(newItem); document.getElementById("songlist").appendChild(newItem);
} }
if (optionslist.length == 0) { if (searchResults.length == 0) {
//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>";
} }
@ -207,6 +205,11 @@ async function checkSettings(skipServer=false) {
async function generateVisualPlaylist(conditions="") { async function generateVisualPlaylist(conditions="") {
document.getElementById("playlist").innerHTML = "<h1 id=\"playlist-alert\"></h1>"; document.getElementById("playlist").innerHTML = "<h1 id=\"playlist-alert\"></h1>";
playlist = await getFromServer(null, "playlist"); playlist = await getFromServer(null, "playlist");
playlist = Object.values(playlist).map(obj => {
const filename = Object.keys(obj)[0]; // Get the filename
const songData = obj[filename]; // Get the song metadata
return { filename, ...songData }; // Merge filename with song data
});
if (playlist.length==0){ if (playlist.length==0){
document.getElementById("playlist-alert").innerHTML = "Nothing's Queued..." document.getElementById("playlist-alert").innerHTML = "Nothing's Queued..."
} else { } else {
@ -216,10 +219,11 @@ async function generateVisualPlaylist(conditions="") {
document.getElementById("playlist-alert").innerHTML = "Nothing's Queued..." document.getElementById("playlist-alert").innerHTML = "Nothing's Queued..."
} }
} }
for (i in playlist) { for (let i in playlist) {
let fileName = playlist[i]["filename"]
let newItem = document.createElement("div"); let newItem = document.createElement("div");
newItem.className = "item"; newItem.className = "item";
newItem.id = playlist[i]["file"]; newItem.id = fileName;
let image = document.createElement("img"); let image = document.createElement("img");
try { try {
if (playlist[i]["art"] == null) { if (playlist[i]["art"] == null) {
@ -229,7 +233,7 @@ async function generateVisualPlaylist(conditions="") {
} catch(err){ } catch(err){
image.src = "./images/placeholder.png"; image.src = "./images/placeholder.png";
} }
image.id = String(playlist[i]["file"])+" image"; image.id = String(fileName)+" image";
let head3 = document.createElement("h3"); let head3 = document.createElement("h3");
head3.innerText = playlist[i]["title"]; head3.innerText = playlist[i]["title"];
let head4 = document.createElement("h4"); let head4 = document.createElement("h4");
@ -249,6 +253,7 @@ async function generateVisualPlaylist(conditions="") {
} }
} }
}catch(err){ }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.log(err)
} }
let textdiv = document.createElement("div") let textdiv = document.createElement("div")

View file

@ -27,20 +27,19 @@ if args.mode == "update":
with open('songDatabase.json', 'r') as handle: with open('songDatabase.json', 'r') as handle:
songDatabaseList = json.load(handle) songDatabaseList = json.load(handle)
except: except:
songDatabaseList=[] songDatabaseList={"songDirectory":soundLocation,'songData':{}}
for i in songDatabaseList: for i in songDatabaseList["songData"]:
try: try:
songFiles.index(i["file"]) != -1 songFiles.index(i) != -1
except: except:
print("deleted: " + i["file"] + " from database") print("deleted: " + i + " from database")
songDatabaseList.remove(i) songDatabaseList.remove(i)
for i in songDatabaseList: for i in songDatabaseList["songData"]:
songFiles.pop(songFiles.index(i["file"])) songFiles.remove(i)
print("new songs: " + str(songFiles)) print("new songs: " + str(songFiles))
elif args.mode=="new": elif args.mode=="new":
songDatabaseList = [] songDatabaseList={"songDirectory":soundLocation,'songData':{}}
if args.art.lower() == "true": if args.art.lower() == "true":
x = len(songFiles)*0.25 x = len(songFiles)*0.25
if x > 60: if x > 60:
@ -85,7 +84,7 @@ for i in songFiles:
index = (songFiles.index(i))%4 index = (songFiles.index(i))%4
print("\r" + str(loading[index] + str(math.floor((songFiles.index(i)/(len(songFiles)-1))*100))+ "%"), end='', flush=True) print("\r" + str(loading[index] + str(math.floor((songFiles.index(i)/(len(songFiles)-1))*100))+ "%"), end='', flush=True)
# each "song" is stored as a dictionary containing the below stuff, and each dictionary is put into a list # each "song" is stored as a dictionary containing the below stuff, and each dictionary is put into a list
songDatabaseList.append({"file":i,"title":title,"artist":artist,"art":image,"length":length}) songDatabaseList["songData"][i] = ({"title":title,"artist":artist,"art":image,"length":length})
with open('songDatabase.json', 'w') as handle: with open('songDatabase.json', 'w') as handle:
json.dump(songDatabaseList, handle) json.dump(songDatabaseList, handle)

View file

@ -4,12 +4,16 @@ from flask_cors import CORS
import json,vlc,threading,time,random, argparse import json,vlc,threading,time,random, argparse
# Argparse Stuff # Argparse Stuff
parser=argparse.ArgumentParser(description="Options for the Webby Bits") parser=argparse.ArgumentParser(description="Options for the Webby Bits")
parser.add_argument('-d','--directory',help="Directory of the song files (make sure this matches the directory used for the databaseGenerator)", default="./sound/") # this is no longer needed assuming my file works correctly with the generator
# parser.add_argument('-d','--directory',help="Directory of the song files (make sure this matches the directory used for the databaseGenerator)", default="./sound/")
parser.add_argument('-p','--port',help="Port to host on, not the same as the web (client) port",default='19054') parser.add_argument('-p','--port',help="Port to host on, not the same as the web (client) port",default='19054')
portTheUserPicked=parser.parse_args().port portTheUserPicked=parser.parse_args().port
soundLocation = parser.parse_args().directory
# To set the directory permenantly just uncomment the next line # open the json file as a dictionary
# soundLocation = "/example/directory/here/" with open('./songDatabase.json', 'r') as handle:
songDatabaseList = json.load(handle)
soundLocation = songDatabaseList["songDirectory"]
if soundLocation[-1] == "/" or soundLocation[-1] == "\\": if soundLocation[-1] == "/" or soundLocation[-1] == "\\":
pass pass
elif "/" in soundLocation: elif "/" in soundLocation:
@ -33,9 +37,6 @@ player.audio_set_volume(100)
app = Flask(__name__) app = Flask(__name__)
# because you are posting from another domain to this one, you need CORS # because you are posting from another domain to this one, you need CORS
CORS(app) CORS(app)
# open the json file as a dictionary
with open('./songDatabase.json', 'r') as handle:
songDatabaseList = json.load(handle)
def queueSong(song): def queueSong(song):
with playlistLock: with playlistLock:
@ -116,16 +117,16 @@ def searchSongDB():
# the way i put the data in a list was really dumb looking back, i could and should have used a list of dictioaries like i was before # the way i put the data in a list was really dumb looking back, i could and should have used a list of dictioaries like i was before
# i might try to change it but this layout is embedded deep in the client # i might try to change it but this layout is embedded deep in the client
tempData = {} tempData = {}
for i in songDatabaseList: for i in songDatabaseList["songData"]:
if ((i["title"].lower().find(recieveData['search'].lower())) > -1) or (recieveData['search'] == ""): if ((songDatabaseList["songData"][i]["title"].lower().find(recieveData['search'].lower())) > -1) or (recieveData['search'] == ""):
# In future i would change this to index based on the filename so that it is definately unique tempData[i] = songDatabaseList["songData"][i]
tempData[i["title"]] = [i["artist"],i["art"],i["file"]]
try: try:
if (i["artist"].lower().find(recieveData['search'].lower()) > -1): if (songDatabaseList["songData"][i]["artist"].lower().find(recieveData['search'].lower()) > -1):
tempData[i["title"]] = [i["artist"],i["art"],i["file"]] tempData[i] = songDatabaseList["songData"][i]
except: except:
pass pass
# print(tempData)
return tempData return tempData
@app.route("/songadd", methods=["POST"]) @app.route("/songadd", methods=["POST"])
@ -137,26 +138,16 @@ def songadd():
def getPlaylist(): def getPlaylist():
global songNext global songNext
tempPlaylist = [] tempPlaylist = []
# what went through my head to make past-me think this is a good idea??? if songNext != None:
# i mean actually looping through once still shouldn't ever take that long # Adds the currently playing song
# but like a binary search must exist in python and be faster k = songDatabaseList["songData"][songNext]
# wait no binary search only helps if they're sorted
# i mean i guess i could sort them and make searching faster
for k in songDatabaseList:
if k["file"] == songNext:
temp = k.copy() temp = k.copy()
temp["playing"] = True temp["playing"] = True
temp["time"] = player.get_time()/1000 temp["time"] = player.get_time()/1000
tempPlaylist.append(temp) tempPlaylist.append({songNext:temp})
for i in playlist: for i in playlist:
# oh my goodness i did it again tempPlaylist.append({i:songDatabaseList["songData"][i]})
# i seriously need to rewrite the databaseGenerator and this code # print(tempPlaylist)
# wait isn't this literally useless code???
# oh no the playlist only contains names
# i should really have used an object for this.
for j in songDatabaseList:
if j["file"] == i:
tempPlaylist.append(j)
return tempPlaylist return tempPlaylist
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -49,18 +49,19 @@ These are specific details on each section of the app, and how to use them
- Running with `--directory (directoryOfmp3s)` allows for sound files to be in a different place - Running with `--directory (directoryOfmp3s)` allows for sound files to be in a different place
- Default `"./sound"` - Default `"./sound"`
- _This setting might be kinda iffy on Linux. You're on Linux just go and edit it if you have issues_ - _This setting might be kinda iffy on Linux. You're on Linux just go and edit it if you have issues_
- __Make certain you only use forward slashes in your directory, even on Windows__ - ~~__Make certain you only use forward slashes in your directory, even on Windows__~~ I think this should be fine now i'll check later
- `songDatabase.json` stores all the information about each song in this format: - `songDatabase.json` stores all the information about each song in this format:
``` ```
[ {
{ "songDirectory": "./sound/",
"file": "The Search_NF.mp3", "songData": {
"title": "The Search", "Circus_Fox Szn.mp3":
"artist": "NF", {"title": "Circus",
"art": "https://lastfm.freetls.fastly.net/i/u/64s/03125956378d531a44e1b7da89aae795.png", "artist": "Fox Szn",
"length": 292 "art": null,
"length": 141}
} }
] }
``` ```
- `webbyBits.py` imports the database, runs all music playing, and accepts all commands from clients - `webbyBits.py` imports the database, runs all music playing, and accepts all commands from clients
- Searches return matching songs - Searches return matching songs