diff --git a/maloja/htmlmodules.py b/maloja/htmlmodules.py deleted file mode 100644 index bf108ae..0000000 --- a/maloja/htmlmodules.py +++ /dev/null @@ -1,677 +0,0 @@ -from .htmlgenerators import * -from . import database -from .utilities import getArtistImage, getTrackImage -from .malojatime import * -from .urihandler import compose_querystring, internal_to_uri, uri_to_internal -import urllib -import datetime -import math - - -#def getpictures(ls,result,tracks=False): -# from utilities import getArtistsInfo, getTracksInfo -# if tracks: -# for element in getTracksInfo(ls): -# result.append(element.get("image")) -# else: -# for element in getArtistsInfo(ls): -# result.append(element.get("image")) - - -#max_ indicates that no pagination should occur (because this is not the primary module) -def module_scrobblelist(page=0,perpage=100,max_=None,pictures=False,shortTimeDesc=False,earlystop=False,**kwargs): - - kwargs_filter = pickKeys(kwargs,"artist","track","associated") - kwargs_time = pickKeys(kwargs,"timerange","since","to","within") - - if max_ is not None: perpage,page=max_,0 - - firstindex = page * perpage - lastindex = firstindex + perpage - - # if earlystop, we don't care about the actual amount and only request as many from the db - # without, we request everything and filter on site - maxkey = {"max_":lastindex} if earlystop else {} - scrobbles = database.get_scrobbles(**kwargs_time,**kwargs_filter,**maxkey) - if pictures: - scrobbleswithpictures = [""] * firstindex + scrobbles[firstindex:lastindex] - #scrobbleimages = [e.get("image") for e in getTracksInfo(scrobbleswithpictures)] #will still work with scrobble objects as they are a technically a subset of track objects - #scrobbleimages = ["/image?title=" + urllib.parse.quote(t["title"]) + "&" + "&".join(["artist=" + urllib.parse.quote(a) for a in t["artists"]]) for t in scrobbleswithpictures] - scrobbleimages = [getTrackImage(t["artists"],t["title"],fast=True) for t in scrobbleswithpictures] - - pages = math.ceil(len(scrobbles) / perpage) - - representative = scrobbles[0] if len(scrobbles) is not 0 else None - - # build list - i = 0 - html = "" - for s in scrobbles: - if i" - if pictures: - img = scrobbleimages[i] - else: img = None - html += entity_column(s,image=img) - html += "" - - i += 1 - if i>=lastindex: - break - - - html += "
" - - if max_ is None: html += module_paginate(page=page,pages=pages,perpage=perpage,**kwargs) - - return (html,len(scrobbles),representative) - - -def module_pulse(page=0,perpage=100,max_=None,**kwargs): - - from doreah.timing import clock, clockp - - kwargs_filter = pickKeys(kwargs,"artist","track","associated") - kwargs_time = pickKeys(kwargs,"since","to","within","timerange","step","stepn","trail") - - if max_ is not None: perpage,page=max_,0 - - firstindex = page * perpage - lastindex = firstindex + perpage - - - ranges = database.get_pulse(**kwargs_time,**kwargs_filter) - - pages = math.ceil(len(ranges) / perpage) - - ranges = ranges[firstindex:lastindex] - - # if time range not explicitly specified, only show from first appearance -# if "since" not in kwargs: -# while ranges[0]["scrobbles"] == 0: -# del ranges[0] - - maxbar = max([t["scrobbles"] for t in ranges]) - maxbar = max(maxbar,1) - - #build list - html = "" - for t in ranges: - range = t["range"] - html += "" - html += "" - html += "" - html += "" - html += "" - html += "
" + range.desc() + "" + scrobblesLink(range.urikeys(),amount=t["scrobbles"],**kwargs_filter) + "" + scrobblesLink(range.urikeys(),percent=t["scrobbles"]*100/maxbar,**kwargs_filter) + "
" - - if max_ is None: html += module_paginate(page=page,pages=pages,perpage=perpage,**kwargs) - - return html - - - -def module_performance(page=0,perpage=100,max_=None,**kwargs): - - kwargs_filter = pickKeys(kwargs,"artist","track") - kwargs_time = pickKeys(kwargs,"since","to","within","timerange","step","stepn","trail") - - if max_ is not None: perpage,page=max_,0 - - firstindex = page * perpage - lastindex = firstindex + perpage - - ranges = database.get_performance(**kwargs_time,**kwargs_filter) - - pages = math.ceil(len(ranges) / perpage) - - ranges = ranges[firstindex:lastindex] - - # if time range not explicitly specified, only show from first appearance -# if "since" not in kwargs: -# while ranges[0]["scrobbles"] == 0: -# del ranges[0] - - - minrank = 80 - for t in ranges: - if t["rank"] is not None and t["rank"]+20 > minrank: minrank = t["rank"]+20 - - #build list - html = "" - for t in ranges: - range = t["range"] - html += "" - html += "" - html += "" - prct = (minrank+1-t["rank"])*100/minrank if t["rank"] is not None else 0 - html += "" - html += "" - html += "
" + range.desc() + "" + ("#" + str(t["rank"]) if t["rank"] is not None else "No scrobbles") + "" + rankLink(range.urikeys(),percent=prct,**kwargs_filter,medal=t["rank"]) + "
" - - if max_ is None: html += module_paginate(page=page,pages=pages,perpage=perpage,**kwargs) - - return html - - - -def module_trackcharts(page=0,perpage=100,max_=None,**kwargs): - - kwargs_filter = pickKeys(kwargs,"artist","associated") - kwargs_time = pickKeys(kwargs,"timerange","since","to","within") - - if max_ is not None: perpage,page=max_,0 - - firstindex = page * perpage - lastindex = firstindex + perpage - - tracks = database.get_charts_tracks(**kwargs_filter,**kwargs_time) - - pages = math.ceil(len(tracks) / perpage) - - # last time range (to compare) - try: - trackslast = database.get_charts_tracks(**kwargs_filter,timerange=kwargs_time["timerange"].next(step=-1)) - # create rank association - lastrank = {} - for tl in trackslast: - lastrank[(*tl["track"]["artists"],tl["track"]["title"])] = tl["rank"] - for t in tracks: - try: - t["delta"] = lastrank[(*t["track"]["artists"],t["track"]["title"])] - t["rank"] - except: - t["delta"] = math.inf - except: - pass - - if tracks != []: - maxbar = tracks[0]["scrobbles"] - representative = tracks[0]["track"] - else: - representative = None - - - i = 0 - html = "" - for e in tracks: - if ilastindex: - break - html += "" - # rank - if i == firstindex+1 or e["scrobbles"] < prev["scrobbles"]: - html += "" - else: - html += "" - # rank change - if e.get("delta") is None: - pass - elif e["delta"] is math.inf: - html += "" - elif e["delta"] > 0: - html += "" - elif e["delta"] < 0: - html += "" - else: - html += "" - # track - html += entity_column(e["track"]) - # scrobbles - html += "" - html += "" - html += "" - prev = e - html += "
#" + str(e["rank"]) + "🆕↗↘➡" + scrobblesTrackLink(e["track"],internal_to_uri(kwargs_time),amount=e["scrobbles"]) + "" + scrobblesTrackLink(e["track"],internal_to_uri(kwargs_time),percent=e["scrobbles"]*100/maxbar) + "
" - - if max_ is None: html += module_paginate(page=page,pages=pages,perpage=perpage,**kwargs) - - return (html,representative) - - -def module_artistcharts(page=0,perpage=100,max_=None,**kwargs): - - kwargs_filter = pickKeys(kwargs,"associated") #not used right now - kwargs_time = pickKeys(kwargs,"timerange","since","to","within") - - if max_ is not None: perpage,page=max_,0 - - firstindex = page * perpage - lastindex = firstindex + perpage - - artists = database.get_charts_artists(**kwargs_filter,**kwargs_time) - - pages = math.ceil(len(artists) / perpage) - - - # last time range (to compare) - try: - #from malojatime import _get_next - artistslast = database.get_charts_artists(**kwargs_filter,timerange=kwargs_time["timerange"].next(step=-1)) - # create rank association - lastrank = {} - for al in artistslast: - lastrank[al["artist"]] = al["rank"] - for a in artists: - try: - a["delta"] = lastrank[a["artist"]] - a["rank"] - except: - a["delta"] = math.inf - except: - pass - - if artists != []: - maxbar = artists[0]["scrobbles"] - representative = artists[0]["artist"] - else: - representative = None - - i = 0 - html = "" - for e in artists: - if ilastindex: - break - html += "" - # rank - if i == firstindex+1 or e["scrobbles"] < prev["scrobbles"]: - html += "" - else: - html += "" - # rank change - #if "within" not in kwargs_time: pass - if e.get("delta") is None: - pass - elif e["delta"] is math.inf: - html += "" - elif e["delta"] > 0: - html += "" - elif e["delta"] < 0: - html += "" - else: - html += "" - # artist - html += entity_column(e["artist"],counting=e["counting"]) - # scrobbles - html += "" - html += "" - html += "" - prev = e - - html += "
#" + str(e["rank"]) + "🆕↗↘➡" + scrobblesArtistLink(e["artist"],internal_to_uri(kwargs_time),amount=e["scrobbles"],associated=True) + "" + scrobblesArtistLink(e["artist"],internal_to_uri(kwargs_time),percent=e["scrobbles"]*100/maxbar,associated=True) + "
" - - if max_ is None: html += module_paginate(page=page,pages=pages,perpage=perpage,**kwargs) - - return (html, representative) - - - -def module_toptracks(pictures=True,**kwargs): - - kwargs_filter = pickKeys(kwargs,"artist","associated") - kwargs_time = pickKeys(kwargs,"timerange","since","to","within","step","stepn","trail") - - tracks = database.get_top_tracks(**kwargs_filter,**kwargs_time) - - if tracks != []: - maxbar = max(t["scrobbles"] for t in tracks) - - - # track with most #1 positions - max_appear = 0 - representatives = list(t["track"] for t in tracks if t["track"] is not None) - for t in representatives: - max_appear = max(max_appear,representatives.count(t)) - #representatives.sort(key=lambda reftrack:len([t for t in tracks if t["track"] == reftrack["track"] and t["track"] is not None])) - representatives = [t for t in tracks if representatives.count(t["track"]) == max_appear] - # of these, track with highest scrobbles in its #1 range - representatives.sort(key=lambda t: t["scrobbles"]) - representative = representatives[-1]["track"] - else: - representative = None - - - i = 0 - html = "" - for e in tracks: - - #fromstr = "/".join([str(p) for p in e["from"]]) - #tostr = "/".join([str(p) for p in e["to"]]) - range = e["range"] - - i += 1 - html += "" - - - html += "" - if e["track"] is None: - if pictures: - html += "" - html += "" - #html += "" - html += "" - html += "" - else: - if pictures: - img = getTrackImage(e["track"]["artists"],e["track"]["title"],fast=True) - else: img = None - html += entity_column(e["track"],image=img) - html += "" - html += "" - html += "" - prev = e - html += "
" + range.desc() + "
" + "No scrobbles" + "" + "" + "" + "0" + "" + "" + "" + scrobblesTrackLink(e["track"],range.urikeys(),amount=e["scrobbles"]) + "" + scrobblesTrackLink(e["track"],range.urikeys(),percent=e["scrobbles"]*100/maxbar) + "
" - - return (html,representative) - -def module_topartists(pictures=True,**kwargs): - - kwargs_time = pickKeys(kwargs,"timerange","since","to","within","step","stepn","trail") - - artists = database.get_top_artists(**kwargs_time) - - if artists != []: - maxbar = max(a["scrobbles"] for a in artists) - - # artists with most #1 positions - max_appear = 0 - representatives = list(a["artist"] for a in artists if a["artist"] is not None) - for a in representatives: - max_appear = max(max_appear,representatives.count(a)) - representatives = [a for a in artists if representatives.count(a["artist"]) == max_appear] - # of these, artist with highest scrobbles in their #1 range - representatives.sort(key=lambda a: a["scrobbles"]) - - representative = representatives[-1]["artist"] - else: - representative = None - - - i = 0 - html = "" - for e in artists: - - #fromstr = "/".join([str(p) for p in e["from"]]) - #tostr = "/".join([str(p) for p in e["to"]]) - range = e["range"] - - i += 1 - html += "" - - - html += "" - - if e["artist"] is None: - if pictures: - html += "" - html += "" - html += "" - html += "" - else: - if pictures: - img = getArtistImage(e["artist"],fast=True) - else: img = None - html += entity_column(e["artist"],image=img) - html += "" - html += "" - html += "" - prev = e - html += "
" + range.desc() + "
" + "No scrobbles" + "" + "0" + "" + "" + "" + scrobblesArtistLink(e["artist"],range.urikeys(),amount=e["scrobbles"],associated=True) + "" + scrobblesArtistLink(e["artist"],range.urikeys(),percent=e["scrobbles"]*100/maxbar,associated=True) + "
" - - return (html,representative) - - -def module_artistcharts_tiles(**kwargs): - - kwargs_filter = pickKeys(kwargs,"associated") #not used right now - kwargs_time = pickKeys(kwargs,"timerange","since","to","within") - - artists = database.get_charts_artists(**kwargs_filter,**kwargs_time)[:14] - while len(artists)<14: artists.append(None) - - i = 1 - - bigpart = [0,1,2,6,15] - smallpart = [0,1,2,4,6,9,12,15] - #rnk = (0,0) #temporary store so entries with the same scrobble amount get the same rank - - html = """""" - - for e in artists: - - - if i in bigpart: - n = bigpart.index(i) - html += """" - - html += """
""" - - if i in smallpart: - html += "" - - - if e is not None: - html += "" - else: - html += "" - - i += 1 - - if i in smallpart: - html += "" - - if i in bigpart: - html += "
" \ - + "" + "#" + str(e["rank"]) + " " + html_link(e["artist"]) + "
""" - - return html - - -def module_trackcharts_tiles(**kwargs): - - kwargs_filter = pickKeys(kwargs,"artist","associated") - kwargs_time = pickKeys(kwargs,"timerange","since","to","within") - - tracks = database.get_charts_tracks(**kwargs_filter,**kwargs_time)[:14] - while len(tracks)<14: tracks.append(None) #{"track":{"title":"","artists":[]}} - - i = 1 - - bigpart = [0,1,2,6,15] - smallpart = [0,1,2,4,6,9,12,15] - #rnk = (0,0) #temporary store so entries with the same scrobble amount get the same rank - - - html = """""" - - for e in tracks: - - - if i in bigpart: - n = bigpart.index(i) - html += """" - - html += """
""" - - if i in smallpart: - html += "" - - - if e is not None: - html += "" - else: - html += "" - - i += 1 - - if i in smallpart: - html += "" - - if i in bigpart: - html += "
" \ - + "" + "#" + str(e["rank"]) + " " + html_link(e["track"]) + "
""" - - return html - - - -def module_paginate(page,pages,perpage,**keys): - - unchangedkeys = internal_to_uri({**keys,"perpage":perpage}) - - html = "
" - - if page > 1: - html += "" + "1" + "" - html += " | " - - if page > 2: - html += " ... | " - - if page > 0: - html += "" + str(page) + "" - html += " « " - - html += "" + str(page+1) + "" - - if page < pages-1: - html += " » " - html += "" + str(page+2) + "" - - if page < pages-3: - html += " | ... " - - if page < pages-2: - html += " | " - html += "" + str(pages) + "" - - - html += "
" - - return html - - - -# THIS FUNCTION USES THE ORIGINAL URI KEYS!!! -def module_filterselection(keys,time=True,delimit=False): - - from .malojatime import today, thisweek, thismonth, thisyear, alltime - - filterkeys, timekeys, delimitkeys, extrakeys = uri_to_internal(keys) - # drop keys that are not relevant so they don't clutter the URI - if not time: timekeys = {} - if not delimit: delimitkeys = {} - if "page" in extrakeys: del extrakeys["page"] - internalkeys = {**filterkeys,**timekeys,**delimitkeys,**extrakeys} - - html = "" - - - if time: - - # wonky selector for precise date range - -# fromdate = start_of_scrobbling() -# todate = end_of_scrobbling() -# if keys.get("since") is not None: fromdate = keys.get("since") -# if keys.get("to") is not None: todate = keys.get("to") -# if keys.get("in") is not None: fromdate, todate = keys.get("in"), keys.get("in") -# fromdate = time_fix(fromdate) -# todate = time_fix(todate) -# fromdate, todate = time_pad(fromdate,todate,full=True) -# fromdate = [str(e) if e>9 else "0" + str(e) for e in fromdate] -# todate = [str(e) if e>9 else "0" + str(e) for e in todate] -# -# html += "
" -# html += "from " -# html += "to " -# html += "
" - - # relative to current range - html += "
" - - thisrange = timekeys.get("timerange") - prevrange = thisrange.next(-1) - nextrange = thisrange.next(1) - - if prevrange is not None: - link = compose_querystring(internal_to_uri({**internalkeys,"timerange":prevrange})) - html += "" + prevrange.desc() + "" - html += " « " - if prevrange is not None or nextrange is not None: - html += "" + thisrange.desc() + "" - if nextrange is not None: - html += " » " - link = compose_querystring(internal_to_uri({**internalkeys,"timerange":nextrange})) - html += "" + nextrange.desc() + "" - - html += "
" - - - - - categories = [ - { - "active":time, - "options":{ - "Today":{"timerange":today()}, - "This Week":{"timerange":thisweek()}, - "This Month":{"timerange":thismonth()}, - "This Year":{"timerange":thisyear()}, - "All Time":{"timerange":alltime()} - } - }, - { - "active":delimit, - "options":{ - "Daily":{"step":"day","stepn":1}, - "Weekly":{"step":"week","stepn":1}, - "Fortnightly":{"step":"week","stepn":2}, - "Monthly":{"step":"month","stepn":1}, - "Quarterly":{"step":"month","stepn":3}, - "Yearly":{"step":"year","stepn":1} - } - }, - { - "active":delimit, - "options":{ - "Standard":{"trail":1}, - "Trailing":{"trail":2}, - "Long Trailing":{"trail":3}, - "Inert":{"trail":10}, - "Cumulative":{"trail":math.inf} - } - } - - ] - - for c in categories: - - if c["active"]: - - optionlist = [] - for option in c["options"]: - values = c["options"][option] - link = "?" + compose_querystring(internal_to_uri({**internalkeys,**values})) - - if all(internalkeys.get(k) == values[k] for k in values): - optionlist.append("" + option + "") - else: - optionlist.append("" + option + "") - - html += "
" + " | ".join(optionlist) + "
" - - return html diff --git a/maloja/jinjaenv/context.py b/maloja/jinjaenv/context.py index 01e8c1b..40d3148 100644 --- a/maloja/jinjaenv/context.py +++ b/maloja/jinjaenv/context.py @@ -1,7 +1,7 @@ from .. import database_packed from . import filters -from .. import database, database_packed, htmlmodules, htmlgenerators, malojatime, utilities, urihandler, malojauri +from .. import database, database_packed, htmlgenerators, malojatime, utilities, urihandler, malojauri from doreah import settings import urllib @@ -16,7 +16,6 @@ JINJA_CONTEXT = { # maloja "db": database, "dbp":dbp, - "htmlmodules": htmlmodules, "htmlgenerators": htmlgenerators, "malojatime": malojatime, "utilities": utilities, diff --git a/maloja/malojauri.py b/maloja/malojauri.py index 6dbd657..249f416 100644 --- a/maloja/malojauri.py +++ b/maloja/malojauri.py @@ -1,6 +1,7 @@ from .malojatime import get_range_object - - +from bottle import FormsDict +import urllib +import math # this also sets defaults! def uri_to_internal(keys,forceTrack=False,forceArtist=False): @@ -58,3 +59,99 @@ def uri_to_internal(keys,forceTrack=False,forceArtist=False): return filterkeys, limitkeys, delimitkeys, amountkeys, specialkeys + + + +def create_uri(path,*keydicts): + keyd = {} + for kd in keydicts: + keyd.update(kd) + + return path + "?" + compose_querystring(internal_to_uri(keyd)) + + +def internal_to_uri(keys): + urikeys = FormsDict() + + #filter + if "artist" in keys: + urikeys.append("artist",keys["artist"]) + if keys.get("associated"): urikeys.append("associated","yes") + elif "track" in keys: + for a in keys["track"]["artists"]: + urikeys.append("artist",a) + urikeys.append("title",keys["track"]["title"]) + + #time + if "timerange" in keys: + keydict = keys["timerange"].urikeys() + for k in keydict: + urikeys.append(k,keydict[k]) + elif "within" in keys: + urikeys.append("in",time_str(keys["within"])) + else: + if "since" in keys and keys["since"] is not None: + urikeys.append("since",time_str(keys["since"])) + if "to" in keys and keys["to"] is not None: + urikeys.append("to",time_str(keys["to"])) + + # delimit + if "step" in keys: + urikeys.append("step",keys["step"]) + if "stepn" in keys: + urikeys.append("stepn",str(keys["stepn"])) + if "trail" in keys: + if keys["trail"] == math.inf: + urikeys.append("cumulative","yes") + else: + urikeys.append("trail",str(keys["trail"])) + + # stuff + #if "max_" in keys: + # urikeys.append("max",str(keys["max_"])) + if "page" in keys: + urikeys.append("page",str(keys["page"])) + if "perpage" in keys: + urikeys.append("perpage",str(keys["perpage"])) + + + return urikeys + + + + + +# necessary because urllib.parse.urlencode doesnt handle multidicts +def compose_querystring(*dicts,exclude=[]): + + st = "" + keys = remove_identical(*dicts) + for k in keys: + if k in exclude: continue + values = keys.getall(k) + st += "&".join([urllib.parse.urlencode({k:v},safe="/") for v in values]) + st += "&" + return st + + +# takes any number of multidicts and normal dicts and creates a formsdict with duplicate values removed +def remove_identical(*dicts): + #combine multiple dicts + keys = FormsDict() + for d in dicts: + for k in d: + try: #multidicts + for v in d.getall(k): + keys.append(k,v) + except: #normaldicts + v = d.get(k) + keys.append(k,v) + + new = FormsDict() + for k in keys: + #values = set(keys.getall(k)) + values = keys.getall(k) # NO IDENTICAL REMOVAL FOR NOW + for v in values: + new.append(k,v) + + return new diff --git a/maloja/server.py b/maloja/server.py index 2d1d6e5..1478e3e 100755 --- a/maloja/server.py +++ b/maloja/server.py @@ -11,7 +11,6 @@ import waitress from . import monkey # rest of the project from . import database -from . import htmlmodules from . import htmlgenerators from . import malojatime from . import utilities