def play_track(id: int, seconds: int, time: int): track = db.get(id) while seconds > 5: track.timesplayed += 1 track.lastplayed = time if seconds > (track.length / 2) and get_settings("MALOJA_SCROBBLE"): starttime = time - seconds endtime = starttime + min(track.length, seconds) server = get_settings("MALOJA_SERVER") key = get_settings("MALOJA_KEY") url = server + "/api/newscrobble" data = { "artist": "/".join(a.name for a in track.artists), "title": track.title, "duration": max(seconds, track.length), "time": endtime, "key": key } requests.post(url, data=data) seconds -= track.length
def send_stats(): if settings.get_settings("SEND_STATS"): log("Sending daily stats report...") from .database import ARTISTS, TRACKS, SCROBBLES keys = { "url": "https://myrcella.krateng.ch/malojastats", "method": "POST", "headers": { "Content-Type": "application/json" }, "data": json.dumps({ "name": settings.get_settings("NAME"), "url": settings.get_settings("PUBLIC_URL"), "version": ".".join(str(d) for d in version), "artists": len(ARTISTS), "tracks": len(TRACKS), "scrobbles": len(SCROBBLES) }).encode("utf-8") } try: req = urllib.request.Request(**keys) response = urllib.request.urlopen(req) log("Sent daily report!") except: log("Could not send daily report!")
def instructions(keys): authenticated = False if "Cookie" in request.headers: cookies = request.headers["Cookie"].split(";") for c in cookies: if c.strip().startswith("apikey="): authenticated = checkAPIkey(c.strip()[7:]) if "token" in keys and authenticated: token = keys.get("token") parameters = { "method": "auth.getSession", "token": token, "api_key": get_settings("LASTFM_API_KEY") } response = urllib.request.urlopen( "http://ws.audioscrobbler.com/2.0/?" + lfmbuild(parameters)) xml = response.read() data = ET.fromstring(xml) if data.attrib.get("status") == "ok": username = data.find("session").find("name").text sessionkey = data.find("session").find("key").text update_settings("settings/settings.ini", { "LASTFM_API_SK": sessionkey, "LASTFM_USERNAME": username }, create_new=True) return "/proxy" else: key, secret, sessionkey, name = get_settings("LASTFM_API_KEY", "LASTFM_API_SECRET", "LASTFM_API_SK", "LASTFM_USERNAME") if key is None: lastfm = "<td>No Last.fm key provided</td>" elif secret is None: lastfm = "<td>No Last.fm secret provided</td>" elif sessionkey is None and authenticated: url = "http://www.last.fm/api/auth/?api_key=" + key + "&cb=" lastfm = "<td class='button'><a id='lastfmlink' href='" + url + "'><div>Connect</div></a></td>" elif sessionkey is None: lastfm = "<td>Not active</td>" else: lastfm = "<td>Account: " + name + "</td>" return {"KEY_STATUS_LASTFM": lastfm}, []
def start(): setup() try: p = subprocess.Popen(["python3", "-m", "maloja.server"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) sp = subprocess.Popen(["python3", "-m", "maloja.supervisor"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) print(col["green"]("Maloja started!") + " PID: " + str(p.pid)) from doreah import settings port = settings.get_settings("WEB_PORT") print("Visit your server address (Port " + str(port) + ") to see your web interface. Visit /setup to get started.") print( "If you're installing this on your local machine, these links should get you there:" ) print("\t" + col["blue"]("http://localhost:" + str(port))) print("\t" + col["blue"]("http://localhost:" + str(port) + "/setup")) return True except: print("Error while starting Maloja.") return False
def trackInfo(track): charts = db_aggregate(by="TRACK") #scrobbles = len(db_query(artists=artists,title=title)) #chart entry of track always has right scrobble number, no countas rules here #c = [e for e in charts if set(e["track"]["artists"]) == set(artists) and e["track"]["title"] == title][0] c = [e for e in charts if e["track"] == track][0] scrobbles = c["scrobbles"] position = c["rank"] cert = None threshold_gold, threshold_platinum, threshold_diamond = settings.get_settings( "SCROBBLES_GOLD", "SCROBBLES_PLATINUM", "SCROBBLES_DIAMOND") if scrobbles >= threshold_diamond: cert = "diamond" elif scrobbles >= threshold_platinum: cert = "platinum" elif scrobbles >= threshold_gold: cert = "gold" return { "scrobbles": scrobbles, "position": position, "medals": MEDALS_TRACKS.get((frozenset(track["artists"]), track["title"])), "certification": cert, "topweeks": WEEKLY_TOPTRACKS.get(((frozenset(track["artists"]), track["title"])), 0) }
def trackSearchLink(track): searchProvider = get_settings("TRACK_SEARCH_PROVIDER") if searchProvider is None: return "" link = "<a class='trackProviderSearch' href='" if searchProvider == "YouTube": link += "https://www.youtube.com/results?search_query=" elif searchProvider == "YouTube Music": link += "https://music.youtube.com/search?q=" elif searchProvider == "Google Play Music": link += "https://play.google.com/music/listen#/srs/" elif searchProvider == "Spotify": link += "https://open.spotify.com/search/results/" elif searchProvider == "Tidal": link += "https://listen.tidal.com/search/tracks?q=" elif searchProvider == "SoundCloud": link += "https://soundcloud.com/search?q=" elif searchProvider == "Amazon Music": link += "https://music.amazon.com/search/" elif searchProvider == "Deezer": link += "https://www.deezer.com/search/" else: link += "https://www.google.com/search?q=" # ¯\_(ツ)_/¯ link += urllib.parse.quote(", ".join(track["artists"]) + " " + track["title"]) + "'>🎵</a>" return link
def static_html(name): if name in aliases: redirect(aliases[name]) linkheaders = ["</style.css>; rel=preload; as=style"] keys = remove_identical(FormsDict.decode(request.query)) adminmode = request.cookies.get("adminmode") == "true" and auth.check( request) clock = Clock() clock.start() LOCAL_CONTEXT = { "adminmode": adminmode, "apikey": request.cookies.get("apikey") if adminmode else None, "_urikeys": keys, #temporary! } lc = LOCAL_CONTEXT lc["filterkeys"], lc["limitkeys"], lc["delimitkeys"], lc["amountkeys"], lc[ "specialkeys"] = uri_to_internal(keys) template = jinja_environment.get_template(name + '.jinja') try: res = template.render(**LOCAL_CONTEXT) except ValueError as e: abort(404, "Entity does not exist") if settings.get_settings("DEV_MODE"): jinja_environment.cache.clear() log("Generated page {name} in {time:.5f}s".format(name=name, time=clock.stop()), module="debug_performance") return clean_html(res)
def lfmbuild(parameters): m = hashlib.md5() keys = sorted(str(k) for k in parameters) m.update(utf("".join(str(k) + str(parameters[k]) for k in keys))) m.update(utf(get_settings("LASTFM_API_SECRET"))) sig = m.hexdigest() return urllib.parse.urlencode(parameters) + "&api_sig=" + sig
def getArtistImage(artist, fast=False): # obj = artist # filename = re.sub("[^a-zA-Z0-9]","",artist) # if filename == "": filename = str(hash(obj)) # filepath = "images/artists/" + filename # #filepath_cache = "info/artists_cache/" + filename if settings.get_settings("USE_LOCAL_IMAGES"): try: return local_artist_cache.get(artist) except: images = local_files(artist=artist) if len(images) != 0: #return random.choice(images) res = random.choice(images) local_artist_cache.add(artist, res) return urllib.parse.quote(res) # check if custom image exists # if os.path.exists(filepath + ".png"): # imgurl = "/" + filepath + ".png" # return imgurl # elif os.path.exists(filepath + ".jpg"): # imgurl = "/" + filepath + ".jpg" # return imgurl # elif os.path.exists(filepath + ".jpeg"): # imgurl = "/" + filepath + ".jpeg" # return imgurl # elif os.path.exists(filepath + ".gif"): # imgurl = "/" + filepath + ".gif" # return imgurl try: #result = cachedArtists[artist] result = artist_cache.get(artist) #artist_from_cache(artist) if result is not None: return result else: return "" 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?artist=" + urllib.parse.quote(artist) # non-fast lookup (esentially only the resolver lookup) result = api_request_artist(artist=artist) # cache results (even negative ones) #cachedArtists[artist] = result artist_cache.add(artist, result) #cache_artist(artist,result) if result is not None: return result else: return ""
def instructions(keys): from ..utilities import getArtistImage, getTrackImage from ..htmlgenerators import artistLink from ..urihandler import compose_querystring, uri_to_internal from ..htmlmodules import module_trackcharts, module_filterselection, module_trackcharts_tiles from ..malojatime import range_desc from doreah.settings import get_settings filterkeys, timekeys, _, amountkeys = uri_to_internal(keys) if len(filterkeys) == 0: toptrackslink = "<a href='/top_tracks'><span>View #1 Tracks</span></a>" else: toptrackslink = "" limitstring = "" html_filterselector = module_filterselection(keys) html_charts, rep = module_trackcharts(**amountkeys,**timekeys,**filterkeys) html_tiles = "" if filterkeys.get("artist") is not None: imgurl = getArtistImage(filterkeys.get("artist")) limitstring = "by " + artistLink(filterkeys.get("artist")) elif rep is not None: imgurl = getTrackImage(rep["artists"],rep["title"]) else: imgurl = "" html_tiles = "" if get_settings("CHARTS_DISPLAY_TILES"): html_tiles = module_trackcharts_tiles(timerange=timekeys["timerange"]) imgurl = "favicon.png" imgdiv = '<div style="background-image:url('+imgurl+')"></div>' limitstring += " " + timekeys["timerange"].desc(prefix=True) pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else [] replace = { "KEY_TOPARTIST_IMAGEDIV":imgdiv, "KEY_TRACKCHART":html_tiles, "KEY_TRACKLIST":html_charts, "KEY_LIMITS":limitstring, "KEY_FILTERSELECTOR":html_filterselector, "TOP_TRACKS_LINK":toptrackslink, } return (replace,pushresources)
def __init__(self): # populate from settings file once on creation # avoid constant disk access, restart on adding services is acceptable for key in self.settings: self.settings[key] = get_settings(self.settings[key]) try: self.authorize() except: pass
def refresh_metadata(audio_ids=None): if audio_ids is None: audios = db.getall(Audio) else: audios = [db.get(id) for id in audio_ids] dirs = get_settings("MUSIC_DIRECTORIES") trees = scan(dirs) build_metadata(audios, trees)
def getTrackImage(artists, title, fast=False): if settings.get_settings("USE_LOCAL_IMAGES"): try: return local_track_cache.get((frozenset(artists), title)) except: images = local_files(artists=artists, title=title) if len(images) != 0: #return random.choice(images) res = random.choice(images) local_track_cache.add((frozenset(artists), title), res) return urllib.parse.quote(res) 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 # (even if we're not in a fast lookup right now) #result = cachedTracks[(frozenset(artists),title)] result = track_cache.get( (frozenset(artists), title)) #track_from_cache(artists,title) if result is not None: return result else: for a in artists: res = getArtistImage(artist=a, fast=True) if res != "": return res return "" 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]) # non-fast lookup (esentially only the resolver lookup) result = api_request_track((artists, title)) # cache results (even negative ones) #cachedTracks[(frozenset(artists),title)] = result track_cache.add((frozenset(artists), title), result) #cache_track(artists,title,result) # return either result or redirect to artist if result is not None: return result else: for a in artists: res = getArtistImage(artist=a, fast=False) if res != "": return res return ""
def server_info(): response.set_header("Access-Control-Allow-Origin", "*") response.set_header("Content-Type", "application/json") return { "name": settings.get_settings("NAME"), "version": version, "versionstring": ".".join(str(n) for n in version) }
def parseArtists(self,a): if isinstance(a,list): res = [self.parseArtists(art) for art in a] return [a for group in res for a in group] if a.strip() in settings.get_settings("INVALID_ARTISTS"): return [] if a.strip().lower() in self.rules_ignoreartist: return [] if a.strip() == "": return [] if a.strip() in self.rules_notanartist: return [] if " performing " in a.lower(): return self.parseArtists(re.split(" [Pp]erforming",a)[0]) if a.strip() in self.rules_belongtogether: return [a.strip()] if a.strip().lower() in self.rules_replaceartist: return self.rules_replaceartist[a.strip().lower()].split("␟") for d in self.delimiters_feat: if re.match(r"(.*) \(" + d + " (.*)\)",a) is not None: return self.parseArtists(re.sub(r"(.*) \(" + d + " (.*)\)",r"\1",a)) + \ self.parseArtists(re.sub(r"(.*) \(" + d + " (.*)\)",r"\2",a)) for d in (self.delimiters_feat + self.delimiters): if ((" " + d + " ") in a): ls = [] for i in a.split(" " + d + " "): ls += self.parseArtists(i) return ls for d in self.delimiters_formal: if (d in a): ls = [] for i in a.split(d): ls += self.parseArtists(i) return ls return [a.strip()]
def info(): totalscrobbles = get_scrobbles_num() artists = {} return { "name":settings.get_settings("NAME"), "artists":{ chartentry["artist"]:round(chartentry["scrobbles"] * 100 / totalscrobbles,3) for chartentry in get_charts_artists() if chartentry["scrobbles"]/totalscrobbles >= 0 }, "known_servers":list(KNOWN_SERVERS) }
def post_endpoint(endpoint): data = request.json log("Received request to endpoint " + endpoint) try: cls = db._getclassbyname(endpoint) log("Mapped to class " + str(cls)) except: log("Does not exist!") return 404 # instantiate a new object of this class if settings.get_settings("ACCEPT_STATS"): cls(**data) db.save() else: log("Not accepting any stats right now.")
def getArtistImage(artist, fast=False): if settings.get_settings("USE_LOCAL_IMAGES"): try: return thumborize(local_artist_cache.get(artist)) # Local cached image except: # Get all local images, select one if present images = local_files(artist=artist) if len(images) != 0: #return random.choice(images) res = random.choice(images) local_artist_cache.add(artist, res) return thumborize(urllib.parse.quote(res)) # if no local images (or setting to not use them) try: # check cache for foreign image result = artist_cache.get(artist) if result is not None: return thumborize(result) else: return "" # none means non-existence is cached, return empty except: pass # no cache entry, go on # 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) # non-fast lookup (esentially only the resolver lookup) result = api_request_artist(artist=artist) # cache results (even negative ones) #cachedArtists[artist] = result artist_cache.add(artist, result) #cache_artist(artist,result) if result is not None: return thumborize(result) else: return ""
def parseTitle(self, t): if t.strip().lower() in self.rules_replacetitle: return self.rules_replacetitle[t.strip().lower()] t = t.replace("[", "(").replace("]", ")") t = re.sub(r" \(as made famous by .*?\)", "", t) t = re.sub(r" \(originally by .*?\)", "", t) t = re.sub(r" \(.*?Remaster.*?\)", "", t) for s in settings.get_settings("REMOVE_FROM_TITLE"): if s in t: t = t.replace(s, "") t = t.strip() #for p in self.plugin_titleparsers: # t = p(t).strip() return t
def start(): if getInstanceSupervisor() is not None: print("Maloja is already running.") else: setup() try: #p = subprocess.Popen(["python3","-m","maloja.server"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) sp = subprocess.Popen(["python3","-m","maloja.proccontrol.supervisor"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) print(col["green"]("Maloja started!")) port = settings.get_settings("WEB_PORT") print("Visit your server address (Port " + str(port) + ") to see your web interface. Visit /setup to get started.") print("If you're installing this on your local machine, these links should get you there:") print("\t" + col["blue"]("http://localhost:" + str(port))) print("\t" + col["blue"]("http://localhost:" + str(port) + "/setup")) return True except: print("Error while starting Maloja.") return False
def subsonicauth(request): try: token = request.query.get("t") salt = request.query.get("s") key = settings.get_settings("SUBSONIC_KEY") m = hashlib.md5() m.update(key.encode()) m.update(salt.encode()) if m.hexdigest() == token: # print("Success!") return True assert False except: raise return False
def instructions(keys): from ..utilities import getArtistImage from ..urihandler import compose_querystring, uri_to_internal from ..htmlmodules import module_artistcharts, module_filterselection, module_artistcharts_tiles from ..malojatime import range_desc from doreah.settings import get_settings _, timekeys, _, amountkeys = uri_to_internal(keys) limitstring = timekeys["timerange"].desc(prefix=True) html_filterselector = module_filterselection(keys) html_charts, rep = module_artistcharts(**amountkeys, **timekeys) if rep is not None: imgurl = getArtistImage(rep) else: imgurl = "" html_tiles = "" if get_settings("CHARTS_DISPLAY_TILES"): html_tiles = module_artistcharts_tiles(timerange=timekeys["timerange"]) imgurl = "favicon.png" imgdiv = '<div style="background-image:url(' + imgurl + ')"></div>' pushresources = [{ "file": imgurl, "type": "image" }] if imgurl.startswith("/") else [] replace = { "KEY_TOPARTIST_IMAGEDIV": imgdiv, "KEY_ARTISTCHART": html_tiles, "KEY_ARTISTLIST": html_charts, "KEY_RANGE": limitstring, "KEY_FILTERSELECTOR": html_filterselector } return (replace, pushresources)
def get_scrobbles(tracks): tracks = {(frozenset(a.name.lower() for a in t.artists), t.title.lower()): t for t in tracks} matched_tracks = {} malserver = get_settings("MALOJA_SERVER") if malserver is None: malserver = input("Please enter the URL of your Maloja server: ") # list of tracks url = malserver + "/api/tracks" result = requests.get(url) result = result.json()["list"] for r in result: tr = (frozenset(a.lower() for a in r["artists"]), r["title"].lower()) if tr in tracks: matched_tracks[tracks[tr]] = r #print(matched_tracks) url = malserver + "/api/trackinfo" i = 0 tracknumber = len(matched_tracks) for t in matched_tracks: i += 1 trackinfo = matched_tracks[t] info = [] for a in trackinfo["artists"]: info.append(("artist", a)) info.append(("title", trackinfo["title"])) # trackurl = url + "?" + "&".join(["artist=" + a for a in trackinfo["artists"]]) + "&title=" + trackinfo["title"] trackurl = url + "?" + urllib.parse.urlencode(info) # print("Making request",trackurl) result = requests.get(trackurl) result = result.json() #print(t,"has",result["scrobbles"],"scrobbles") print_progress_bar(num=(i, tracknumber), prefix="Importing scrobbles ") t.timesplayed = result["scrobbles"]
def scan_dir(dir, progressbar): d = Directory(name=dir.split("/")[-1]) dirlist = os.listdir(dir) progressbar.godeeper(len(dirlist)) for f in dirlist: fullpath = os.path.join(dir, f) if f in get_settings("IGNORE_FILES"): break if f.startswith("."): progressbar.progress(step=f) continue if os.path.isdir(fullpath): d.subdirs.append(scan_dir(fullpath, progressbar)) else: ext = f.split(".")[-1].lower() if ext in AUDIOFORMATS: d.add_file(Audio(path=fullpath)) elif ext in IMAGEFORMATS: d.add_file(Artwork(path=fullpath)) elif f in ["artist.yml", "artist.yaml"]: with open(fullpath, "r") as fil: #files.append({**yaml.safe_load(fil),"type":"artist"}) info = yaml.safe_load(fil) d.artist = Artist(name=info["name"]) elif f in ["album.yml", "album.yaml"]: with open(fullpath, "r") as fil: #files.append({**yaml.safe_load(fil),"type":"album"}) info = yaml.safe_load(fil) d.album = Album(name=info["name"], albumartists=[ Artist(name=a) for a in info["albumartists"] ]) #else: print("File",f,"has unknown format") progressbar.progress(step=f) progressbar.done() return d
def validate_challenge(challenge,response): update() lock.acquire() if challenge not in [challenge_current, challenge_old]: lock.release() print("Invalid challenge") return False pub = str(get_settings("PUBLIC_KEY")) if combine(pub,challenge) == combine(response,COMMON): # invalidate challenges stop_issue = 0 expire = 0 update() lock.release() return True else: print("Invalid response") lock.release() return False
def scan(dirs): old_audiofiles = db.getall(Audio) for a in old_audiofiles: if not os.path.exists(a.path): a.track.audiofiles.remove(a) db.delete(a) scan_dir_prog = NestedProgressBar(len(dirs), prefix="Scanning directories", manual=True) trees = [] new_audiofiles = [] for dir in dirs: d = scan_dir(dir, progressbar=scan_dir_prog) trees.append(d) new_audiofiles = [a for a in db.getall(Audio) if a not in old_audiofiles] old_tracks = db.getall(Track) #when scanning, also call metadata refresher for newly added files from ..dbbuild.parser import build_metadata build_metadata(new_audiofiles, trees) new_tracks = [t for t in db.getall(Track) if t not in old_tracks] # import maloja data for new tracks malserver = get_settings("MALOJA_SERVER") if malserver is not None: from ..dbbuild.malojareader import get_scrobbles get_scrobbles(new_tracks) from ..dbbuild.pruner import prune_database prune_database() return trees
def static_html(name): linkheaders = ["</style.css>; rel=preload; as=style"] keys = remove_identical(FormsDict.decode(request.query)) pyhp_file = os.path.exists(pthjoin(WEBFOLDER, "pyhp", name + ".pyhp")) html_file = os.path.exists(pthjoin(WEBFOLDER, name + ".html")) jinja_file = os.path.exists(pthjoin(WEBFOLDER, "jinja", name + ".jinja")) pyhp_pref = settings.get_settings("USE_PYHP") jinja_pref = settings.get_settings("USE_JINJA") adminmode = request.cookies.get( "adminmode") == "true" and database.checkAPIkey( request.cookies.get("apikey")) is not False clock = Clock() clock.start() # if a jinja file exists, use this if (jinja_file and jinja_pref) or (jinja_file and not html_file and not pyhp_file): LOCAL_CONTEXT = { "adminmode": adminmode, "apikey": request.cookies.get("apikey") if adminmode else None, "_urikeys": keys, #temporary! } LOCAL_CONTEXT["filterkeys"], LOCAL_CONTEXT["limitkeys"], LOCAL_CONTEXT[ "delimitkeys"], LOCAL_CONTEXT["amountkeys"] = uri_to_internal(keys) template = jinjaenv.get_template(name + '.jinja') res = template.render(**LOCAL_CONTEXT) log("Generated page {name} in {time:.5f}s (Jinja)".format( name=name, time=clock.stop()), module="debug") return res # if a pyhp file exists, use this elif (pyhp_file and pyhp_pref) or (pyhp_file and not html_file): #things we expose to the pyhp pages environ = { "adminmode": adminmode, "apikey": request.cookies.get("apikey") if adminmode else None, # maloja "db": database, "htmlmodules": htmlmodules, "htmlgenerators": htmlgenerators, "malojatime": malojatime, "utilities": utilities, "urihandler": urihandler, "settings": settings.get_settings, # external "urllib": urllib } # request environ["filterkeys"], environ["limitkeys"], environ[ "delimitkeys"], environ["amountkeys"] = uri_to_internal(keys) environ["_urikeys"] = keys #temporary! #response.set_header("Content-Type","application/xhtml+xml") res = pyhpfile(pthjoin(WEBFOLDER, "pyhp", name + ".pyhp"), environ) log("Generated page {name} in {time:.5f}s (PYHP)".format( name=name, time=clock.stop()), module="debug") return res # if not, use the old way else: with open(pthjoin(WEBFOLDER, name + ".html")) as htmlfile: html = htmlfile.read() # apply global substitutions with open(pthjoin(WEBFOLDER, "common/footer.html")) as footerfile: footerhtml = footerfile.read() with open(pthjoin(WEBFOLDER, "common/header.html")) as headerfile: headerhtml = headerfile.read() html = html.replace("</body>", footerhtml + "</body>").replace( "</head>", headerhtml + "</head>") # If a python file exists, it provides the replacement dict for the html file if os.path.exists(pthjoin(WEBFOLDER, name + ".py")): #txt_keys = SourceFileLoader(name,"web/" + name + ".py").load_module().replacedict(keys,DATABASE_PORT) try: module = importlib.import_module(".web." + name, package="maloja") txt_keys, resources = module.instructions(keys) except Exception as e: log("Error in website generation: " + str(sys.exc_info()), module="error") raise # add headers for server push for resource in resources: if all(ord(c) < 128 for c in resource["file"]): # we can only put ascii stuff in the http header linkheaders.append("<" + resource["file"] + ">; rel=preload; as=" + resource["type"]) # apply key substitutions for k in txt_keys: if isinstance(txt_keys[k], list): # if list, we replace each occurence with the next item for element in txt_keys[k]: html = html.replace(k, element, 1) else: html = html.replace(k, txt_keys[k]) response.set_header("Link", ",".join(linkheaders)) log("Generated page {name} in {time:.5f}s (Python+HTML)".format( name=name, time=clock.stop()), module="debug") return html
# technical #from importlib.machinery import SourceFileLoader import importlib import _thread import sys import signal import os import setproctitle import pkg_resources import math # url handling import urllib #settings.config(files=["settings/default.ini","settings/settings.ini"]) #settings.update("settings/default.ini","settings/settings.ini") MAIN_PORT = settings.get_settings("WEB_PORT") HOST = settings.get_settings("HOST") THREADS = 24 BaseRequest.MEMFILE_MAX = 15 * 1024 * 1024 WEBFOLDER = pkg_resources.resource_filename(__name__, "web") STATICFOLDER = pkg_resources.resource_filename(__name__, "static") DATAFOLDER = DATA_DIR webserver = Bottle() pthjoin = os.path.join def generate_css(): import lesscpy
import urllib.parse, urllib.request import json import base64 from doreah.settings import get_settings from doreah.logging import log import hashlib import xml.etree.ElementTree as ET ### PICTURES apis_artists = [] if get_settings("LASTFM_API_KEY") not in [ None, "ASK" ] and get_settings("FANARTTV_API_KEY") not in [None, "ASK"]: apis_artists.append({ "name": "LastFM + Fanart.tv", #"check":get_settings("LASTFM_API_KEY") not in [None,"ASK"] and get_settings("FANARTTV_API_KEY") not in [None,"ASK"], "steps": [("get", "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist={artiststring}&api_key=" + str(get_settings("LASTFM_API_KEY")) + "&format=json"), ("parse", ["artist", "mbid"]), ("get", "http://webservice.fanart.tv/v3/music/{var}?api_key=" + str(get_settings("FANARTTV_API_KEY"))), ("parse", ["artistthumb", 0, "url"])] }) if get_settings("SPOTIFY_API_ID") not in [ None, "ASK"
def clean_html(inp): if settings.get_settings("DEV_MODE"): return inp else: return html_minify(inp)