diff --git a/.gitignore b/.gitignore index 57a03e3..57879ab 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ apikey *.txt nohup.out screenshot*.png +/settings/settings.ini diff --git a/doreah/settings.py b/doreah/settings.py new file mode 100644 index 0000000..43ac4bf --- /dev/null +++ b/doreah/settings.py @@ -0,0 +1,187 @@ +import os +import shutil + +# set configuration +# defaultextension unused +# files list of all files that will be used for configuration. high indicies overwrite low indicies +# comment symbols that indicate comments. careful! +# category symbols that indicate start and end of category name. only works at start of line +# onlytext interpret everything as a string. if False, strings can be put into quotes to avoid confusion +def config(defaultextension=".ini",files=["settings.ini","settings.conf","configuration.ini","configuration.conf"], + comment=["#","//"],category=("[","]"),onlytext=False): + global _defaultextension, _files, _comment, _category, _onlytext + _defaultextension = defaultextension + _files = files + _comment = comment + _category = category + _onlytext = onlytext + + + global Settings, get_settings, set_settings, update + + + # manager object so we can read settings once and retain them + class Settings: + def __init__(self,**kwargs): + self.settings = get_settings(**kwargs) + + def get(self,*keys): + result = (self.settings.get(k) for k in keys) + if len(result) == 1: result = result[0] + return result + + + + + def _interpret(text): + if _onlytext: return text + + if text.lower() in ["true","yes"]: return True + if text.lower() in ["false","no"]: return False + if text.lower() in ["none","nan","n/a",""]: return None + if text.startswith("'") and text.endswith("'"): return text[1:-1] + if text.startswith('"') and text.endswith('"'): return text[1:-1] + try: + return int(text) + except: + pass + try: + return float(text) + except: + pass + return text + + + # get settings + # keys list of requested keys. if present, will return list of according values, if not, will return dict of key-value pairs + # files which files to parse. later files (higher indicies) will overload earlier ones + # prefix only request keys with a certain prefix. key filter will still be applied if present + # cut_prefix return keys without the prefix + # category return only keys of specific category + # raw do not interpret data type, only return strings + def get_settings(*keys,files=_files,prefix="",cut_prefix=False,category=None,raw=False): + + allsettings = {} + + for f in files: + if not os.path.exists(f): continue + + # if category is specified, ignore all entries by default and switch when we encounter the right heading + ignore = False if category is None else True + + with open(f) as file: + lines = file.readlines() + + + for l in lines: + # clean up line + l = l.replace("\n","") + for symbol in _comment: + l = l.split(symbol)[0] + l = l.strip() + + # check if valid settings entry + if l == "": continue + if l.startswith(_category[0]): + # ignore category headers if we don't care + if category is None: continue + # otherwise, find out if this is the category we want + else: + if l.endswith(_category[1]): + cat = l[len(_category[0]):-len(_category[1])] + ignore = not (cat == category) #if this is the right heading, set ignore to false + continue + + if ignore: continue + + if "=" not in l: continue + + # read + (key,val) = l.split("=") + key = key.strip() + val = val.strip() if raw else _interpret(val.strip()) + + if key.startswith(prefix): + # return keys without the common prefix + if cut_prefix: + allsettings[key[len(prefix):]] = val + + # return full keys + else: + allsettings[key] = val + + # no arguments means all settings + if len(keys) == 0: + return allsettings + + # specific keys requested + else: + if len(keys) == 1: return allsettings[keys[0]] + else: return [allsettings[k] for k in keys] + + + def set_settings(file,settings): + + if not os.path.exists(file): return + + with open(file,"r") as origfile: + lines = origfile.readlines() + + newlines = [] + + for origline in lines: + l = origline + # clean up line + l = l.replace("\n","") + for symbol in _comment: + l = l.split(symbol)[0] + l = l.strip() + + # check if valid settings entry + if l == "": + newlines.append(origline) + continue + if l.startswith(_category[0]): + newlines.append(origline) + continue + if "=" not in l: + newlines.append(origline) + continue + + # read + (key,val) = l.split("=") + key = key.strip() + val = val.strip() + + + if key not in settings: + newlines.append(origline) + continue + + else: + #print("Found key") + newline = origline.split("=",1) + #print({"linepart":newline[1],"keytoreplace":val,"new":settings[key]}) + newline[1] = newline[1].replace(val,str(settings[key])) + newline = "=".join(newline) + newlines.append(newline) + + with open(file,"w") as newfile: + newfile.write("".join(newlines)) + + + + + # updates a user settings file to a newer format from a default file without overwriting user's settings + def update(source="default_settings.ini",target="settings.ini"): + + if not os.path.exists(target): + shutil.copyfile(source,target) + else: + usersettings = get_settings(files=[target],raw=True) + shutil.copyfile(source,target) + set_settings(target,usersettings) + + +# initial config on import, set everything to default +config() diff --git a/server.py b/server.py index 9a49cad..897a6dc 100755 --- a/server.py +++ b/server.py @@ -8,6 +8,8 @@ import database from htmlgenerators import removeIdentical from utilities import * from htmlgenerators import KeySplit +# doreah toolkit +from doreah import settings # technical from importlib.machinery import SourceFileLoader import _thread @@ -22,8 +24,9 @@ from urllib.error import * -MAIN_PORT = 42010 -DATABASE_PORT = 42011 +settings.config(files=["settings/default.ini","settings/settings.ini"]) +MAIN_PORT, DATABASE_PORT = settings.get_settings("WEB_PORT","API_PORT") + webserver = Bottle() diff --git a/settings/default.ini b/settings/default.ini new file mode 100644 index 0000000..b11bca1 --- /dev/null +++ b/settings/default.ini @@ -0,0 +1,8 @@ +[HTTP] + +WEB_PORT = 42010 +API_PORT = 42011 + +[Third Party Services] + +LASTFM_API_KEY = None diff --git a/utilities.py b/utilities.py index 0da15d9..918a41e 100644 --- a/utilities.py +++ b/utilities.py @@ -5,6 +5,7 @@ from threading import Thread import pickle import urllib import datetime +from doreah import settings ### TSV files @@ -195,13 +196,14 @@ def apirequest(artists=None,artist=None,title=None): import urllib.parse, urllib.request import json - try: - with open("apikey","r") as keyfile: - apikey = keyfile.read().replace("\n","") + #try: + #with open("apikey","r") as keyfile: + # apikey = keyfile.read().replace("\n","") - if apikey == "NONE": return None - except: - return None + apikey = settings.get_settings("LASTFM_API_KEY") + if apikey is None: return None + #except: + # return None sites = [ @@ -315,6 +317,7 @@ def getTrackImage(artists,title,fast=False): imgurl = "/" + filepath + ".jpeg" return imgurl + try: # check our cache # if we have cached the nonexistence of that image, we immediately return the redirect to the artist and let the resolver handle it @@ -329,6 +332,10 @@ def getTrackImage(artists,title,fast=False): except: pass + # do we have an api key? + apikey = settings.get_settings("LASTFM_API_KEY") + if apikey is None: return "" # DO NOT CACHE THAT + # fast request only retuns cached and local results, generates redirect link for rest if fast: return "/image?title=" + urllib.parse.quote(title) + "&" + "&".join(["artist=" + urllib.parse.quote(a) for a in artists]) @@ -377,6 +384,10 @@ def getArtistImage(artist,fast=False): pass + # do we have an api key? + apikey = settings.get_settings("LASTFM_API_KEY") + if apikey is None: return "" # DO NOT CACHE THAT + # fast request only retuns cached and local results, generates redirect link for rest if fast: return "/image?artist=" + urllib.parse.quote(artist)