Using dotenv, refactored some stuff, made making database slightly faster with art

This commit is contained in:
Kristy Fournier 2026-01-21 16:49:04 -05:00
parent 0cd6b4ce2e
commit 5772edf88a
4 changed files with 30 additions and 26 deletions

View file

@ -4,26 +4,27 @@ from mutagen.mp3 import MP3
import mutagen.flac import mutagen.flac
import mutagen.wave import mutagen.wave
import sqlite3 as sql import sqlite3 as sql
import requests, ast, time, math, argparse import requests, ast, time, math, argparse, dotenv
loading = ["-","\\","|","/"] loading = ["-","\\","|","/"]
parser=argparse.ArgumentParser(description="Options for the generation of the song database") parser=argparse.ArgumentParser(description="Options for the generation of the song database")
parser.add_argument('-k','--apikey', help='String: LastFM api key', default="") # parser.add_argument('-k','--apikey', help='String: LastFM api key', default="")
parser.add_argument('-m', '--mode', help='new/update: Remake database or update current', default= "update") parser.add_argument('-m', '--mode', help='new/update: Remake database or update current', default= "update")
parser.add_argument('-a', '--art', help="True/False: Add art to the database using LastFm (takes minimum 0.25s per song)", default="True") parser.add_argument('-a', '--art', help="True/False: Add art to the database using LastFm (takes minimum 0.25s per song)", default="True")
parser.add_argument('-d','--directory',help="Directory of the song files", default="./sound/") parser.add_argument('-d','--directory',help="Directory of the song files", default="./sound/")
args = parser.parse_args() args = parser.parse_args()
apikeylastfm = args.apikey dotenv.load_dotenv()
apikeylastfm = os.getenv("API_KEY")
soundLocation = os.getenv("DIRECTORY")
# apikeylastfm = args.apikey
if args.directory[-1] == "/" or args.directory[-1] == "\\": if args.directory[-1] == "/" or args.directory[-1] == "\\":
soundLocation = args.directory soundLocation = args.directory
elif "/" in args.directory: elif "/" in args.directory:
soundLocation = args.directory + "/" soundLocation = args.directory + "/"
else: else:
soundLocation = args.directory + "\\" soundLocation = args.directory + "\\"
# if you want to set the api key/sound directory permenantly for your setup just uncomment the next line
# apikeylastfm = "KeyHere"
# soundLocation = "directoryHere"
songFiles = os.listdir(soundLocation) songFiles = os.listdir(soundLocation)
fileOfDB = sql.connect("songDatabase.db") fileOfDB = sql.connect("songDatabase.db")
songDatabase = fileOfDB.cursor() songDatabase = fileOfDB.cursor()
@ -54,12 +55,12 @@ elif args.mode.lower()=="new":
else: else:
raise ValueError("Must be \"new\" or \"update\"") raise ValueError("Must be \"new\" or \"update\"")
if args.art.lower() == "true" and not(args.apikey == ""): if args.art.lower() == "true" and not(apikeylastfm == ""):
x = len(songFiles)*0.25 eta = len(songFiles)*0.25
if x > 60: if eta > 60:
print("ETA "+ str(x/60) + " minutes") print(f"ETA {eta/60:.2f} minutes")
else: else:
print("ETA "+ str(x) + " seconds") print(f"ETA {eta} seconds")
# will be used soon # will be used soon
validFormats = ["mp3","flac","wav"] validFormats = ["mp3","flac","wav"]
@ -103,7 +104,8 @@ for i in songFiles:
#if the file is not formatted with an underscore or hyphen, the title is the file name #if the file is not formatted with an underscore or hyphen, the title is the file name
title = i title = i
artist = None artist = None
if args.art.lower() == "true" and not(args.apikey == ""): if args.art.lower() == "true" and not(apikeylastfm == "") and artist:
# and artist just means anything that only has the x.mp3 title won't bother to check since it'll never exist on last fm
try: try:
# get the images from last fm, try 2 different sizes # get the images from last fm, try 2 different sizes
image = ast.literal_eval(requests.post(url="http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key="+apikeylastfm+"&artist="+artist+"&track="+title+"&format=json").text)["track"]["album"]["image"][2]["#text"] image = ast.literal_eval(requests.post(url="http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key="+apikeylastfm+"&artist="+artist+"&track="+title+"&format=json").text)["track"]["album"]["image"][2]["#text"]
@ -111,7 +113,7 @@ for i in songFiles:
image = ast.literal_eval(requests.post(url="http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key="+apikeylastfm+"&artist="+artist+"&track="+title+"&format=json").text)["track"]["album"]["image"][1]["#text"] image = ast.literal_eval(requests.post(url="http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key="+apikeylastfm+"&artist="+artist+"&track="+title+"&format=json").text)["track"]["album"]["image"][1]["#text"]
if image == "": if image == "":
image = None image = None
time.sleep(0.25) time.sleep(0.01)
except: except:
image=None image=None
else: else:

3
Server/example.env Normal file
View file

@ -0,0 +1,3 @@
API_KEY=
DIRECTORY=./sound
SERVER_PORT=19054

View file

@ -2,14 +2,14 @@ from flask import Flask
from flask import request from flask import request
from flask_cors import CORS from flask_cors import CORS
import sqlite3 as sql import sqlite3 as sql
import vlc,threading,time,random, argparse import vlc,threading,time,random,argparse,dotenv,os
# 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('-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')
parser.add_argument('-a','--admin',help="Add an admin password to be used in the client. DO NOT use a password you use elsewhere",default="") parser.add_argument('-a','--admin',help="Add an admin password to be used in the client. DO NOT use a password you use elsewhere",default="")
args = parser.parse_args() args = parser.parse_args()
dotenv.load_dotenv()
portTheUserPicked=args.port 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" # 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 # 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 # I mean returning 200 when no return is necesary i think is fine but we'll see
@ -20,11 +20,11 @@ if not(ADMIN_PASS):
# True = everyone, False = admin only. Change in client while in use. # True = everyone, False = admin only. Change in client while in use.
# play-pause,skip,addsong,partymode,volume in order # play-pause,skip,addsong,partymode,volume in order
controlPerms = { controlPerms = {
"PP":True, #done "PP":True,
"SK":True, #done "SK":True,
"AS":True, #done "AS":True,
"PM":True, #done "PM":True,
"VOL":True #done "VOL":True
} }
fileofDB = sql.connect("songDatabase.db") fileofDB = sql.connect("songDatabase.db")
@ -150,8 +150,7 @@ def settingsControl():
return ERR_NO_ADMIN return ERR_NO_ADMIN
elif recieveData["setting"] == "getsettings": elif recieveData["setting"] == "getsettings":
# probably should have made this a different request type or something but it works # probably should have made this a different request type or something but it works
x = {"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms} return {"partymode":partyMode,"volume":player.audio_get_volume(),"admin":controlPerms}
return x
else: else:
return "400" return "400"

View file

@ -7,8 +7,8 @@
- [ ] Verify all if-else sequences are correct and not redundant - [ ] Verify all if-else sequences are correct and not redundant
- [x] Remove old comments - [x] Remove old comments
- [ ] Security Updates - [ ] Security Updates
- [ ] `.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
- [ ] Hashing rather than plaintext sending (that way at least the password text itself stays private) - [ ] Hashing rather than plaintext sending passwords (that way at least the password text itself isn't transmitted over the network)
- [ ] Actually use SSL, for posting (CORS seems like an issue) - [ ] Actually use SSL, for posting (CORS seems like an issue)
- [ ] Accessibility - [ ] Accessibility
- [ ] Better use of semantic HTML tags - [ ] Better use of semantic HTML tags