1
0
mirror of https://github.com/krateng/maloja.git synced 2023-08-10 21:12:55 +03:00

Merge branch 'timeobjects'

This commit is contained in:
Krateng 2019-04-11 12:13:39 +02:00
commit 2935236f42
13 changed files with 737 additions and 428 deletions

View File

@ -15,6 +15,7 @@ import datetime
import sys import sys
import unicodedata import unicodedata
import json import json
import pickle
from collections import namedtuple from collections import namedtuple
from threading import Lock from threading import Lock
# url handling # url handling
@ -210,7 +211,7 @@ def get_scrobbles_external():
return {"list":result} return {"list":result}
def get_scrobbles(**keys): def get_scrobbles(**keys):
r = db_query(**{k:keys[k] for k in keys if k in ["artist","artists","title","since","to","within","associated","track","max_"]}) r = db_query(**{k:keys[k] for k in keys if k in ["artist","artists","title","since","to","within","timerange","associated","track","max_"]})
#if keys.get("max_") is not None: #if keys.get("max_") is not None:
# return r[:int(keys.get("max_"))] # return r[:int(keys.get("max_"))]
#else: #else:
@ -240,7 +241,7 @@ def get_scrobbles_num_external():
return {"amount":result} return {"amount":result}
def get_scrobbles_num(**keys): def get_scrobbles_num(**keys):
r = db_query(**{k:keys[k] for k in keys if k in ["artist","track","artists","title","since","to","within","associated"]}) r = db_query(**{k:keys[k] for k in keys if k in ["artist","track","artists","title","since","to","within","timerange","associated"]})
return len(r) return len(r)
@ -343,7 +344,7 @@ def get_charts_artists_external():
return {"list":result} return {"list":result}
def get_charts_artists(**keys): def get_charts_artists(**keys):
return db_aggregate(by="ARTIST",**{k:keys[k] for k in keys if k in ["since","to","within"]}) return db_aggregate(by="ARTIST",**{k:keys[k] for k in keys if k in ["since","to","within","timerange"]})
@ -360,7 +361,7 @@ def get_charts_tracks_external():
return {"list":result} return {"list":result}
def get_charts_tracks(**keys): def get_charts_tracks(**keys):
return db_aggregate(by="TRACK",**{k:keys[k] for k in keys if k in ["since","to","within","artist"]}) return db_aggregate(by="TRACK",**{k:keys[k] for k in keys if k in ["since","to","within","timerange","artist"]})
@ -381,12 +382,11 @@ def get_pulse_external():
def get_pulse(**keys): def get_pulse(**keys):
rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","step","stepn","trail"]}) rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","timerange","step","stepn","trail"]})
results = [] results = []
for rng in rngs:
for (a,b) in rngs: res = len(db_query(timerange=rng,**{k:keys[k] for k in keys if k in ["artists","artist","track","title","associated"]}))
res = len(db_query(since=a,to=b,**{k:keys[k] for k in keys if k in ["artists","artist","track","title","associated"]})) results.append({"range":rng,"scrobbles":res})
results.append({"from":a,"to":b,"scrobbles":res})
return results return results
@ -405,25 +405,25 @@ def get_performance_external():
def get_performance(**keys): def get_performance(**keys):
rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","step","stepn","trail"]}) rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","timerange","step","stepn","trail"]})
results = [] results = []
for (a,b) in rngs: for rng in rngs:
if "track" in keys: if "track" in keys:
charts = get_charts_tracks(since=a,to=b) charts = get_charts_tracks(timerange=rng)
rank = None rank = None
for c in charts: for c in charts:
if c["track"] == keys["track"]: if c["track"] == keys["track"]:
rank = c["rank"] rank = c["rank"]
break break
elif "artist" in keys: elif "artist" in keys:
charts = get_charts_artists(since=a,to=b) charts = get_charts_artists(timerange=rng)
rank = None rank = None
for c in charts: for c in charts:
if c["artist"] == keys["artist"]: if c["artist"] == keys["artist"]:
rank = c["rank"] rank = c["rank"]
break break
results.append({"from":a,"to":b,"rank":rank}) results.append({"range":rng,"rank":rank})
return results return results
@ -446,15 +446,15 @@ def get_top_artists_external():
def get_top_artists(**keys): def get_top_artists(**keys):
rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","step","stepn","trail"]}) rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","timerange","step","stepn","trail"]})
results = [] results = []
for (a,b) in rngs: for rng in rngs:
try: try:
res = db_aggregate(since=a,to=b,by="ARTIST")[0] res = db_aggregate(timerange=rng,by="ARTIST")[0]
results.append({"since":a,"to":b,"artist":res["artist"],"counting":res["counting"],"scrobbles":res["scrobbles"]}) results.append({"range":rng,"artist":res["artist"],"counting":res["counting"],"scrobbles":res["scrobbles"]})
except: except:
results.append({"since":a,"to":b,"artist":None,"scrobbles":0}) results.append({"range":rng,"artist":None,"scrobbles":0})
return results return results
@ -480,15 +480,15 @@ def get_top_tracks_external():
def get_top_tracks(**keys): def get_top_tracks(**keys):
rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","step","stepn","trail"]}) rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","timerange","step","stepn","trail"]})
results = [] results = []
for (a,b) in rngs: for (a,b) in rngs:
try: try:
res = db_aggregate(since=a,to=b,by="TRACK")[0] res = db_aggregate(timerange=rng,by="TRACK")[0]
results.append({"since":a,"to":b,"track":res["track"],"scrobbles":res["scrobbles"]}) results.append({"range":rng,"track":res["track"],"scrobbles":res["scrobbles"]})
except: except:
results.append({"since":a,"to":b,"track":None,"scrobbles":0}) results.append({"range":rng,"track":None,"scrobbles":0})
return results return results
@ -900,7 +900,7 @@ cacheday = (0,0,0)
def db_query(**kwargs): def db_query(**kwargs):
check_cache_age() check_cache_age()
global cache_query global cache_query
key = json.dumps(kwargs) key = pickle.dumps(kwargs)
if key in cache_query: return copy.copy(cache_query[key]) if key in cache_query: return copy.copy(cache_query[key])
result = db_query_full(**kwargs) result = db_query_full(**kwargs)
@ -911,7 +911,7 @@ cache_aggregate = {}
def db_aggregate(**kwargs): def db_aggregate(**kwargs):
check_cache_age() check_cache_age()
global cache_aggregate global cache_aggregate
key = json.dumps(kwargs) key = pickle.dumps(kwargs)
if key in cache_aggregate: return copy.copy(cache_aggregate[key]) if key in cache_aggregate: return copy.copy(cache_aggregate[key])
result = db_aggregate_full(**kwargs) result = db_aggregate_full(**kwargs)
@ -942,9 +942,9 @@ def check_cache_age():
# Queries the database # Queries the database
def db_query_full(artist=None,artists=None,title=None,track=None,since=None,to=None,within=None,associated=False,max_=None): def db_query_full(artist=None,artists=None,title=None,track=None,since=None,to=None,within=None,timerange=None,associated=False,max_=None):
(since, to) = time_stamps(since,to,within) (since, to) = time_stamps(since=since,to=to,within=within,range=timerange)
# this is not meant as a search function. we *can* query the db with a string, but it only works if it matches exactly # this is not meant as a search function. we *can* query the db with a string, but it only works if it matches exactly
# if a title is specified, we assume that a specific track (with the exact artist combination) is requested # if a title is specified, we assume that a specific track (with the exact artist combination) is requested
@ -993,8 +993,10 @@ def db_query_full(artist=None,artists=None,title=None,track=None,since=None,to=N
# Queries that... well... aggregate # Queries that... well... aggregate
def db_aggregate_full(by=None,since=None,to=None,within=None,artist=None): def db_aggregate_full(by=None,since=None,to=None,within=None,timerange=None,artist=None):
(since, to) = time_stamps(since,to,within)
(since, to) = time_stamps(since=since,to=to,within=within,range=timerange)
if isinstance(artist, str): if isinstance(artist, str):
artist = ARTISTS.index(artist) artist = ARTISTS.index(artist)

View File

@ -5,6 +5,7 @@ from malojatime import *
from urihandler import compose_querystring, internal_to_uri, uri_to_internal from urihandler import compose_querystring, internal_to_uri, uri_to_internal
import urllib import urllib
import datetime import datetime
import math
#def getpictures(ls,result,tracks=False): #def getpictures(ls,result,tracks=False):
@ -21,7 +22,7 @@ import datetime
def module_scrobblelist(max_=None,pictures=False,shortTimeDesc=False,earlystop=False,**kwargs): def module_scrobblelist(max_=None,pictures=False,shortTimeDesc=False,earlystop=False,**kwargs):
kwargs_filter = pickKeys(kwargs,"artist","track","associated") kwargs_filter = pickKeys(kwargs,"artist","track","associated")
kwargs_time = pickKeys(kwargs,"since","to","within") kwargs_time = pickKeys(kwargs,"timerange","since","to","within")
# if earlystop, we don't care about the actual amount and only request as many from the db # if earlystop, we don't care about the actual amount and only request as many from the db
@ -42,7 +43,7 @@ def module_scrobblelist(max_=None,pictures=False,shortTimeDesc=False,earlystop=F
for s in scrobbles: for s in scrobbles:
html += "<tr>" html += "<tr>"
html += "<td class='time'>" + time_desc(s["time"],short=shortTimeDesc) + "</td>" html += "<td class='time'>" + timestamp_desc(s["time"],short=shortTimeDesc) + "</td>"
if pictures: if pictures:
img = scrobbleimages[i] img = scrobbleimages[i]
else: img = None else: img = None
@ -63,11 +64,15 @@ def module_scrobblelist(max_=None,pictures=False,shortTimeDesc=False,earlystop=F
def module_pulse(max_=None,**kwargs): def module_pulse(max_=None,**kwargs):
from doreah.timing import clock, clockp
kwargs_filter = pickKeys(kwargs,"artist","track","associated") kwargs_filter = pickKeys(kwargs,"artist","track","associated")
kwargs_time = pickKeys(kwargs,"since","to","within","step","stepn","trail") kwargs_time = pickKeys(kwargs,"since","to","within","timerange","step","stepn","trail")
ranges = database.get_pulse(**kwargs_time,**kwargs_filter) ranges = database.get_pulse(**kwargs_time,**kwargs_filter)
if max_ is not None: ranges = ranges[:max_] if max_ is not None: ranges = ranges[:max_]
# if time range not explicitly specified, only show from first appearance # if time range not explicitly specified, only show from first appearance
@ -81,12 +86,11 @@ def module_pulse(max_=None,**kwargs):
#build list #build list
html = "<table class='list'>" html = "<table class='list'>"
for t in ranges: for t in ranges:
fromstr = "/".join([str(e) for e in t["from"]]) range = t["range"]
tostr = "/".join([str(e) for e in t["to"]])
html += "<tr>" html += "<tr>"
html += "<td>" + range_desc(t["from"],t["to"],short=True) + "</td>" html += "<td>" + range.desc() + "</td>"
html += "<td class='amount'>" + scrobblesLink({"since":fromstr,"to":tostr},amount=t["scrobbles"],**kwargs_filter) + "</td>" html += "<td class='amount'>" + scrobblesLink(range.urikeys(),amount=t["scrobbles"],**kwargs_filter) + "</td>"
html += "<td class='bar'>" + scrobblesLink({"since":fromstr,"to":tostr},percent=t["scrobbles"]*100/maxbar,**kwargs_filter) + "</td>" html += "<td class='bar'>" + scrobblesLink(range.urikeys(),percent=t["scrobbles"]*100/maxbar,**kwargs_filter) + "</td>"
html += "</tr>" html += "</tr>"
html += "</table>" html += "</table>"
@ -98,7 +102,7 @@ def module_pulse(max_=None,**kwargs):
def module_performance(max_=None,**kwargs): def module_performance(max_=None,**kwargs):
kwargs_filter = pickKeys(kwargs,"artist","track") kwargs_filter = pickKeys(kwargs,"artist","track")
kwargs_time = pickKeys(kwargs,"since","to","within","step","stepn","trail") kwargs_time = pickKeys(kwargs,"since","to","within","timerange","step","stepn","trail")
ranges = database.get_performance(**kwargs_time,**kwargs_filter) ranges = database.get_performance(**kwargs_time,**kwargs_filter)
@ -117,13 +121,12 @@ def module_performance(max_=None,**kwargs):
#build list #build list
html = "<table class='list'>" html = "<table class='list'>"
for t in ranges: for t in ranges:
fromstr = "/".join([str(e) for e in t["from"]]) range = t["range"]
tostr = "/".join([str(e) for e in t["to"]])
html += "<tr>" html += "<tr>"
html += "<td>" + range_desc(t["from"],t["to"],short=True) + "</td>" html += "<td>" + range.desc() + "</td>"
html += "<td class='rank'>" + ("#" + str(t["rank"]) if t["rank"] is not None else "No scrobbles") + "</td>" html += "<td class='rank'>" + ("#" + str(t["rank"]) if t["rank"] is not None else "No scrobbles") + "</td>"
prct = (minrank+1-t["rank"])*100/minrank if t["rank"] is not None else 0 prct = (minrank+1-t["rank"])*100/minrank if t["rank"] is not None else 0
html += "<td class='chart'>" + rankLink({"since":fromstr,"to":tostr},percent=prct,**kwargs_filter,medal=t["rank"]) + "</td>" html += "<td class='chart'>" + rankLink(range.urikeys(),percent=prct,**kwargs_filter,medal=t["rank"]) + "</td>"
html += "</tr>" html += "</tr>"
html += "</table>" html += "</table>"
@ -135,14 +138,13 @@ def module_performance(max_=None,**kwargs):
def module_trackcharts(max_=None,**kwargs): def module_trackcharts(max_=None,**kwargs):
kwargs_filter = pickKeys(kwargs,"artist","associated") kwargs_filter = pickKeys(kwargs,"artist","associated")
kwargs_time = pickKeys(kwargs,"since","to","within") kwargs_time = pickKeys(kwargs,"timerange","since","to","within")
tracks = database.get_charts_tracks(**kwargs_filter,**kwargs_time) tracks = database.get_charts_tracks(**kwargs_filter,**kwargs_time)
# last time range (to compare) # last time range (to compare)
if "within" in kwargs_time: try:
from malojatime import _get_next trackslast = database.get_charts_tracks(**kwargs_filter,timerange=kwargs_time["timerange"].next(step=-1))
trackslast = database.get_charts_tracks(**kwargs_filter,within=_get_next(kwargs_time["within"],step=-1))
# create rank association # create rank association
lastrank = {} lastrank = {}
for tl in trackslast: for tl in trackslast:
@ -151,7 +153,9 @@ def module_trackcharts(max_=None,**kwargs):
try: try:
t["delta"] = lastrank[(*t["track"]["artists"],t["track"]["title"])] - t["rank"] t["delta"] = lastrank[(*t["track"]["artists"],t["track"]["title"])] - t["rank"]
except: except:
t["delta"] = None t["delta"] = math.inf
except:
pass
if tracks != []: if tracks != []:
maxbar = tracks[0]["scrobbles"] maxbar = tracks[0]["scrobbles"]
@ -173,8 +177,9 @@ def module_trackcharts(max_=None,**kwargs):
else: else:
html += "<td class='rank'></td>" html += "<td class='rank'></td>"
# rank change # rank change
if "within" not in kwargs_time: pass if e.get("delta") is None:
elif e["delta"] is None: pass
elif e["delta"] is math.inf:
html += "<td class='rankup' title='New'>🆕</td>" html += "<td class='rankup' title='New'>🆕</td>"
elif e["delta"] > 0: elif e["delta"] > 0:
html += "<td class='rankup' title='up from #" + str(e["rank"]+e["delta"]) + "'>↗</td>" html += "<td class='rankup' title='up from #" + str(e["rank"]+e["delta"]) + "'>↗</td>"
@ -197,14 +202,14 @@ def module_trackcharts(max_=None,**kwargs):
def module_artistcharts(max_=None,**kwargs): def module_artistcharts(max_=None,**kwargs):
kwargs_filter = pickKeys(kwargs,"associated") #not used right now kwargs_filter = pickKeys(kwargs,"associated") #not used right now
kwargs_time = pickKeys(kwargs,"since","to","within") kwargs_time = pickKeys(kwargs,"timerange","since","to","within")
artists = database.get_charts_artists(**kwargs_filter,**kwargs_time) artists = database.get_charts_artists(**kwargs_filter,**kwargs_time)
# last time range (to compare) # last time range (to compare)
if "within" in kwargs_time: try:
from malojatime import _get_next #from malojatime import _get_next
artistslast = database.get_charts_artists(**kwargs_filter,within=_get_next(kwargs_time["within"],step=-1)) artistslast = database.get_charts_artists(**kwargs_filter,timerange=kwargs_time["timerange"].next(step=-1))
# create rank association # create rank association
lastrank = {} lastrank = {}
for al in artistslast: for al in artistslast:
@ -213,7 +218,9 @@ def module_artistcharts(max_=None,**kwargs):
try: try:
a["delta"] = lastrank[a["artist"]] - a["rank"] a["delta"] = lastrank[a["artist"]] - a["rank"]
except: except:
a["delta"] = None a["delta"] = math.inf
except:
pass
if artists != []: if artists != []:
maxbar = artists[0]["scrobbles"] maxbar = artists[0]["scrobbles"]
@ -234,8 +241,10 @@ def module_artistcharts(max_=None,**kwargs):
else: else:
html += "<td class='rank'></td>" html += "<td class='rank'></td>"
# rank change # rank change
if "within" not in kwargs_time: pass #if "within" not in kwargs_time: pass
elif e["delta"] is None: if e.get("delta") is None:
pass
elif e["delta"] is math.inf:
html += "<td class='rankup' title='New'>🆕</td>" html += "<td class='rankup' title='New'>🆕</td>"
elif e["delta"] > 0: elif e["delta"] > 0:
html += "<td class='rankup' title='up from #" + str(e["rank"]+e["delta"]) + "'>↗</td>" html += "<td class='rankup' title='up from #" + str(e["rank"]+e["delta"]) + "'>↗</td>"
@ -260,7 +269,7 @@ def module_artistcharts(max_=None,**kwargs):
def module_toptracks(pictures=True,**kwargs): def module_toptracks(pictures=True,**kwargs):
kwargs_filter = pickKeys(kwargs,"artist","associated") kwargs_filter = pickKeys(kwargs,"artist","associated")
kwargs_time = pickKeys(kwargs,"since","to","within","step","stepn","trail") kwargs_time = pickKeys(kwargs,"timerange","since","to","within","step","stepn","trail")
tracks = database.get_top_tracks(**kwargs_filter,**kwargs_time) tracks = database.get_top_tracks(**kwargs_filter,**kwargs_time)
@ -288,13 +297,13 @@ def module_toptracks(pictures=True,**kwargs):
#fromstr = "/".join([str(p) for p in e["from"]]) #fromstr = "/".join([str(p) for p in e["from"]])
#tostr = "/".join([str(p) for p in e["to"]]) #tostr = "/".join([str(p) for p in e["to"]])
limits = pickKeys(e,"since","to") range = e["range"]
i += 1 i += 1
html += "<tr>" html += "<tr>"
html += "<td>" + range_desc(e["since"],e["to"],short=True) + "</td>" html += "<td>" + range.desc() + "</td>"
if e["track"] is None: if e["track"] is None:
if pictures: if pictures:
html += "<td><div></div></td>" html += "<td><div></div></td>"
@ -307,8 +316,8 @@ def module_toptracks(pictures=True,**kwargs):
img = getTrackImage(e["track"]["artists"],e["track"]["title"],fast=True) img = getTrackImage(e["track"]["artists"],e["track"]["title"],fast=True)
else: img = None else: img = None
html += entity_column(e["track"],image=img) html += entity_column(e["track"],image=img)
html += "<td class='amount'>" + scrobblesTrackLink(e["track"],internal_to_uri(limits),amount=e["scrobbles"]) + "</td>" html += "<td class='amount'>" + scrobblesTrackLink(e["track"],range.urikeys(),amount=e["scrobbles"]) + "</td>"
html += "<td class='bar'>" + scrobblesTrackLink(e["track"],internal_to_uri(limits),percent=e["scrobbles"]*100/maxbar) + "</td>" html += "<td class='bar'>" + scrobblesTrackLink(e["track"],range.urikeys(),percent=e["scrobbles"]*100/maxbar) + "</td>"
html += "</tr>" html += "</tr>"
prev = e prev = e
html += "</table>" html += "</table>"
@ -317,7 +326,7 @@ def module_toptracks(pictures=True,**kwargs):
def module_topartists(pictures=True,**kwargs): def module_topartists(pictures=True,**kwargs):
kwargs_time = pickKeys(kwargs,"since","to","within","step","stepn","trail") kwargs_time = pickKeys(kwargs,"timerange","since","to","within","step","stepn","trail")
artists = database.get_top_artists(**kwargs_time) artists = database.get_top_artists(**kwargs_time)
@ -344,13 +353,13 @@ def module_topartists(pictures=True,**kwargs):
#fromstr = "/".join([str(p) for p in e["from"]]) #fromstr = "/".join([str(p) for p in e["from"]])
#tostr = "/".join([str(p) for p in e["to"]]) #tostr = "/".join([str(p) for p in e["to"]])
limits = pickKeys(e,"since","to") range = e["range"]
i += 1 i += 1
html += "<tr>" html += "<tr>"
html += "<td>" + range_desc(e["since"],e["to"],short=True) + "</td>" html += "<td>" + range.desc() + "</td>"
if e["artist"] is None: if e["artist"] is None:
if pictures: if pictures:
@ -363,8 +372,8 @@ def module_topartists(pictures=True,**kwargs):
img = getArtistImage(e["artist"],fast=True) img = getArtistImage(e["artist"],fast=True)
else: img = None else: img = None
html += entity_column(e["artist"],image=img) html += entity_column(e["artist"],image=img)
html += "<td class='amount'>" + scrobblesArtistLink(e["artist"],internal_to_uri(limits),amount=e["scrobbles"],associated=True) + "</td>" html += "<td class='amount'>" + scrobblesArtistLink(e["artist"],range.urikeys(),amount=e["scrobbles"],associated=True) + "</td>"
html += "<td class='bar'>" + scrobblesArtistLink(e["artist"],internal_to_uri(limits),percent=e["scrobbles"]*100/maxbar,associated=True) + "</td>" html += "<td class='bar'>" + scrobblesArtistLink(e["artist"],range.urikeys(),percent=e["scrobbles"]*100/maxbar,associated=True) + "</td>"
html += "</tr>" html += "</tr>"
prev = e prev = e
html += "</table>" html += "</table>"
@ -375,7 +384,7 @@ def module_topartists(pictures=True,**kwargs):
def module_artistcharts_tiles(**kwargs): def module_artistcharts_tiles(**kwargs):
kwargs_filter = pickKeys(kwargs,"associated") #not used right now kwargs_filter = pickKeys(kwargs,"associated") #not used right now
kwargs_time = pickKeys(kwargs,"since","to","within") kwargs_time = pickKeys(kwargs,"timerange","since","to","within")
artists = database.get_charts_artists(**kwargs_filter,**kwargs_time)[:14] artists = database.get_charts_artists(**kwargs_filter,**kwargs_time)[:14]
while len(artists)<14: artists.append(None) while len(artists)<14: artists.append(None)
@ -423,7 +432,7 @@ def module_artistcharts_tiles(**kwargs):
def module_trackcharts_tiles(**kwargs): def module_trackcharts_tiles(**kwargs):
kwargs_filter = pickKeys(kwargs,"artist","associated") kwargs_filter = pickKeys(kwargs,"artist","associated")
kwargs_time = pickKeys(kwargs,"since","to","within") kwargs_time = pickKeys(kwargs,"timerange","since","to","within")
tracks = database.get_charts_tracks(**kwargs_filter,**kwargs_time)[:14] tracks = database.get_charts_tracks(**kwargs_filter,**kwargs_time)[:14]
while len(tracks)<14: tracks.append(None) #{"track":{"title":"","artists":[]}} while len(tracks)<14: tracks.append(None) #{"track":{"title":"","artists":[]}}
@ -501,47 +510,44 @@ def module_filterselection(keys,time=True,delimit=False):
# html += "to <input id='dateselect_to' onchange='datechange()' type='date' value='" + "-".join(todate) + "'/>" # html += "to <input id='dateselect_to' onchange='datechange()' type='date' value='" + "-".join(todate) + "'/>"
# html += "</div>" # html += "</div>"
from malojatime import today, thisweek, thismonth, thisyear
now = datetime.datetime.utcnow()
today = [now.year,now.month,now.day]
thismonth = today[:2]
thisyear = thismonth[:1]
### temp!!! this will not allow weekly rank changes ### temp!!! this will not allow weekly rank changes
weekday = ((now.isoweekday()) % 7) # weekday = ((now.isoweekday()) % 7)
weekbegin = now - datetime.timedelta(days=weekday) # weekbegin = now - datetime.timedelta(days=weekday)
weekend = weekbegin + datetime.timedelta(days=6) # weekend = weekbegin + datetime.timedelta(days=6)
weekbegin = [weekbegin.year,weekbegin.month,weekbegin.day] # weekbegin = [weekbegin.year,weekbegin.month,weekbegin.day]
weekend = [weekend.year,weekend.month,weekend.day] # weekend = [weekend.year,weekend.month,weekend.day]
weekbeginstr = "/".join((str(num) for num in weekbegin)) # weekbeginstr = "/".join((str(num) for num in weekbegin))
weekendstr = "/".join((str(num) for num in weekend)) # weekendstr = "/".join((str(num) for num in weekend))
html += "<div>" html += "<div>"
if timekeys.get("since") == today or timekeys.get("within") == today: if timekeys.get("timerange") == today():
html += "<span class='stat_selector' style='opacity:0.5;'>Today</span>" html += "<span class='stat_selector' style='opacity:0.5;'>Today</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys,{"in":"today"}) + "'><span class='stat_selector'>Today</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,{"in":"today"}) + "'><span class='stat_selector'>Today</span></a>"
html += " | " html += " | "
if timekeys.get("since") == weekbegin and timekeys.get("to") == weekend: if timekeys.get("timerange") == thisweek():
html += "<span class='stat_selector' style='opacity:0.5;'>This Week</span>" html += "<span class='stat_selector' style='opacity:0.5;'>This Week</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys,{"since":weekbeginstr,"to":weekendstr}) + "'><span class='stat_selector'>This Week</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,{"in":"week"}) + "'><span class='stat_selector'>This Week</span></a>"
html += " | " html += " | "
if timekeys.get("since") == thismonth or timekeys.get("within") == thismonth: if timekeys.get("timerange") == thismonth():
html += "<span class='stat_selector' style='opacity:0.5;'>This Month</span>" html += "<span class='stat_selector' style='opacity:0.5;'>This Month</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys,{"in":"month"}) + "'><span class='stat_selector'>This Month</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,{"in":"month"}) + "'><span class='stat_selector'>This Month</span></a>"
html += " | " html += " | "
if timekeys.get("since") == thisyear or timekeys.get("within") == thisyear: if timekeys.get("timerange") == thisyear():
html += "<span class='stat_selector' style='opacity:0.5;'>This Year</span>" html += "<span class='stat_selector' style='opacity:0.5;'>This Year</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys,{"in":"year"}) + "'><span class='stat_selector'>This Year</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,{"in":"year"}) + "'><span class='stat_selector'>This Year</span></a>"
html += " | " html += " | "
if timekeys.get("since") is None and timekeys.get("within") is None: if timekeys.get("timerange") is None or timekeys.get("timerange").unlimited():
html += "<span class='stat_selector' style='opacity:0.5;'>All Time</span>" html += "<span class='stat_selector' style='opacity:0.5;'>All Time</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys) + "'><span class='stat_selector'>All Time</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys) + "'><span class='stat_selector'>All Time</span></a>"
@ -563,7 +569,13 @@ def module_filterselection(keys,time=True,delimit=False):
html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"step":"day"}) + "'><span class='stat_selector'>Daily</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"step":"day"}) + "'><span class='stat_selector'>Daily</span></a>"
html += " | " html += " | "
if (delimitkeys.get("step") == "month" or delimitkeys.get("step") is None) and delimitkeys.get("stepn") == 1: if delimitkeys.get("step") == "week" and delimitkeys.get("stepn") == 1:
html += "<span class='stat_selector' style='opacity:0.5;'>Weekly</span>"
else:
html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"step":"week"}) + "'><span class='stat_selector'>Weekly</span></a>"
html += " | "
if delimitkeys.get("step") == "month" and delimitkeys.get("stepn") == 1:
html += "<span class='stat_selector' style='opacity:0.5;'>Monthly</span>" html += "<span class='stat_selector' style='opacity:0.5;'>Monthly</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"step":"month"}) + "'><span class='stat_selector'>Monthly</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"step":"month"}) + "'><span class='stat_selector'>Monthly</span></a>"
@ -581,7 +593,7 @@ def module_filterselection(keys,time=True,delimit=False):
unchangedkeys_sub = internal_to_uri({k:delimitkeys[k] for k in delimitkeys if k != "trail"}) unchangedkeys_sub = internal_to_uri({k:delimitkeys[k] for k in delimitkeys if k != "trail"})
html += "<div>" html += "<div>"
if delimitkeys.get("trail") == 1 or delimitkeys.get("trail") is None: if delimitkeys.get("trail") == 1:
html += "<span class='stat_selector' style='opacity:0.5;'>Standard</span>" html += "<span class='stat_selector' style='opacity:0.5;'>Standard</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"trail":"1"}) + "'><span class='stat_selector'>Standard</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"trail":"1"}) + "'><span class='stat_selector'>Standard</span></a>"
@ -597,6 +609,12 @@ def module_filterselection(keys,time=True,delimit=False):
html += "<span class='stat_selector' style='opacity:0.5;'>Long Trailing</span>" html += "<span class='stat_selector' style='opacity:0.5;'>Long Trailing</span>"
else: else:
html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"trail":"3"}) + "'><span class='stat_selector'>Long Trailing</span></a>" html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"trail":"3"}) + "'><span class='stat_selector'>Long Trailing</span></a>"
html += " | "
if delimitkeys.get("trail") == math.inf:
html += "<span class='stat_selector' style='opacity:0.5;'>Cumulative</span>"
else:
html += "<a href='?" + compose_querystring(unchangedkeys,unchangedkeys_sub,{"cumulative":"yes"}) + "'><span class='stat_selector'>Cumulative</span></a>"
html += "</div>" html += "</div>"

View File

@ -1,6 +1,7 @@
import datetime import datetime
from calendar import monthrange from calendar import monthrange
from os.path import commonprefix from os.path import commonprefix
import math
FIRST_SCROBBLE = int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp()) FIRST_SCROBBLE = int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp())
@ -32,12 +33,337 @@ def end_of_scrobbling():
# return str(t) # return str(t)
### helpers
# adjusting to sunday-first calendar
# damn iso heathens
class expandeddate(datetime.date):
def chrweekday(self):
return self.isoweekday() + 1 % 7
def chrcalendar(self):
tomorrow = self + datetime.timedelta(days=1)
cal = tomorrow.isocalendar()
return (cal[0],cal[1],cal[2] % 7)
date = expandeddate
### EVERYTHING NEW AGAIN
# only for ranges, timestamps are separate
class MRangeDescriptor:
def __eq__(self,other):
if not isinstance(other,MRangeDescriptor): return False
return (self.first_stamp() == other.first_stamp() and self.last_stamp() == other.last_stamp())
def __hash__(self):
return hash((self.first_stamp(),self.last_stamp()))
def info(self):
return {
"fromstring":self.fromstr(),
"tostr":self.tostr(),
"uri":self.uri(),
"fromstamp":self.first_stamp(),
"tostamp":self.last_stamp(),
"description":self.desc()
}
def uri(self):
return "&".join(k + "=" + self.urikeys[k] for k in self.urikeys)
def unlimited(self):
return False
# a range that is exactly a gregorian calendar unit (year, month or day)
class MTime(MRangeDescriptor):
def __init__(self,*ls):
# in case we want to call with non-unpacked arguments
if isinstance(ls[0],tuple) or isinstance(ls[0],list):
ls = ls[0]
self.tup = tuple(ls)
self.precision = len(ls)
self.year = ls[0]
if len(ls)>1: self.month = ls[1]
if len(ls)>2: self.day = ls[2]
dt = [1970,1,1]
dt[:len(ls)] = ls
self.dateobject = date(dt[0],dt[1],dt[2])
def __str__(self):
return "/".join(str(part) for part in self.tup)
def fromstr(self):
return str(self)
def tostr(self):
return str(self)
def urikeys(self):
return {"in":str(self)}
def desc(self,prefix=False):
if self.precision == 3:
if prefix:
return "on " + self.dateobject.strftime("%d. %B %Y")
else:
return self.dateobject.strftime("%d. %B %Y")
if self.precision == 2:
if prefix:
return "in " + self.dateobject.strftime("%B %Y")
else:
return self.dateobject.strftime("%B %Y")
if self.precision == 1:
if prefix:
return "in " + self.dateobject.strftime("%Y")
else:
return self.dateobject.strftime("%Y")
def informal_desc(self):
now = datetime.datetime.now(tz=datetime.timezone.utc)
today = date(now.year,now.month,now.day)
if self.precision == 3:
diff = (today - dateobject).days
if diff == 0: return "Today"
if diff == 1: return "Yesterday"
if diff < 7 and diff > 1: return timeobject.strftime("%A")
#elif len(t) == 2:
return self.desc()
# describes only the parts that are different than another range object
def contextual_desc(self,other):
if isinstance(other,MTime):
relevant = self.desc().split(" ")
if self.year == other.year:
relevant.pop()
if self.precision > 1 and other.precision > 1 and self.month == other.month:
relevant.pop()
if self.precision > 2 and other.precision > 2 and self.day == other.day:
relevant.pop()
return " ".join(relevant)
return self.desc()
# gets object with one higher precision that starts this one
def start(self):
if self.precision == 1: return MTime(self.tup + (1,))
elif self.precision == 2: return MTime(self.tup + (1,))
# gets object with one higher precision that ends this one
def end(self):
if self.precision == 1: return MTime(self.tup + (12,))
elif self.precision == 2: return MTime(self.tup + (monthrange(self.year,self.month)[1],))
def first_day(self):
if self.precision == 3: return self
else: return self.start().first_day()
def last_day(self):
if self.precision == 3: return self
else: return self.end().last_day()
def first_stamp(self):
day = self.first_day().dateobject
return int(datetime.datetime.combine(day,datetime.time(tzinfo=datetime.timezone.utc)).timestamp())
def last_stamp(self):
day = self.last_day().dateobject + datetime.timedelta(days=1)
return int(datetime.datetime.combine(day,datetime.time(tzinfo=datetime.timezone.utc)).timestamp() - 1)
# next range of equal length (not exactly same amount of days, but same precision level)
def next(self,step=1):
if abs(step) == math.inf: return None
if self.precision == 1:
return MTime(self.year + step)
elif self.precision == 2:
dt = [self.year,self.month]
dt[1] += step
while dt[1] > 12:
dt[1] -= 12
dt[0] += 1
while dt[1] < 1:
dt[1] += 12
dt[0] -= 1
return MTime(*dt)
elif self.precision == 3:
dt = self.dateobject
d = datetime.timedelta(days=step)
newdate = dt + d
return MTime(newdate.year,newdate.month,newdate.day)
# a range that is exactly one christian week (starting on sunday)
class MTimeWeek(MRangeDescriptor):
def __init__(self,year=None,week=None):
self.year = year
self.week = week
# assume the first day of the first week of this year is 1/1
firstday = date(year,1,1)
y,w,d = firstday.chrcalendar()
if y == self.year:
firstday -= datetime.timedelta(days=(d-1))
else:
firstday += datetime.timedelta(days=8-d)
# now we know the real first day, add the weeks we need
firstday = firstday + datetime.timedelta(days=7*(week-1))
lastday = firstday + datetime.timedelta(days=6)
# turn them into local overwritten date objects
self.firstday = date(firstday.year,firstday.month,firstday.day)
self.lastday = date(lastday.year,lastday.month,lastday.day)
# now check if we're still in the same year
y,w,_ = self.firstday.chrcalendar()
self.year,self.week = y,w
# firstday and lastday are already correct
def __str__(self):
return str(self.year) + "/W" + str(self.week)
def fromstr(self):
return str(self)
def tostr(self):
return str(self)
def urikeys(self):
return {"in":str(self)}
def desc(self,prefix=False):
if prefix:
return "in " + "Week " + str(self.week) + " " + str(self.year)
else:
return "Week " + str(self.week) + " " + str(self.year)
def informal_desc(self):
now = datetime.datetime.now(tz=datetime.timezone.utc)
if now.year == self.year: return "Week " + str(self.week)
return self.desc()
def contextual_desc(self,other):
if isinstance(other,MTimeWeek):
if other.year == self.year: return "Week " + str(self.week)
return self.desc()
def start(self):
return self.first_day()
def end(self):
return self.last_day()
def first_day(self):
return MTime(self.firstday.year,self.firstday.month,self.firstday.day)
def last_day(self):
return MTime(self.lastday.year,self.lastday.month,self.lastday.day)
def first_stamp(self):
day = self.firstday
return int(datetime.datetime.combine(day,datetime.time(tzinfo=datetime.timezone.utc)).timestamp())
def last_stamp(self):
day = self.lastday + datetime.timedelta(days=1)
return int(datetime.datetime.combine(day,datetime.time(tzinfo=datetime.timezone.utc)).timestamp() - 1)
def next(self,step=1):
if abs(step) == math.inf: return None
return MTimeWeek(self.year,self.week + step)
# a range that is defined by separate start and end
class MRange(MRangeDescriptor):
def __init__(self,since=None,to=None):
since,to = time_pad(since,to)
self.since = since
self.to = to
if isinstance(self.since,MRange): self.since = self.since.start()
if isinstance(self.to,MRange): self.to = self.to.end()
def __str__(self):
return str(self.since) + " - " + str(self.to)
def fromstr(self):
return str(self.since)
def tostr(self):
return str(self.to)
def unlimited(self):
return (self.since is None and self.to is None)
def urikeys(self):
keys = {}
if self.since is not None: keys["since"] = str(self.since)
if self.to is not None: keys["to"] = str(self.to)
return keys
def desc(self,prefix=False):
if self.since is not None and self.to is not None:
if prefix:
return "from " + self.since.contextual_desc(self.to) + " to " + self.to.desc()
else:
return self.since.contextual_desc(self.to) + " to " + self.to.desc()
if self.since is not None and self.to is None:
return "since " + self.since.desc()
if self.since is None and self.to is not None:
return "until " + self.to.desc()
if self.since is None and self.to is None:
return ""
def informal_desc(self):
# dis gonna be hard
return "Not implemented"
def start(self):
return self.since
def end(self):
return self.to
def first_day(self):
return self.since.first_day()
def last_day(self):
return self.to.last_day()
def first_stamp(self):
if self.since is None: return FIRST_SCROBBLE
else: return self.since.first_stamp()
def last_stamp(self):
if self.to is None: return int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp())
else: return self.to.last_stamp()
def next(self,step=1):
if abs(step) == math.inf: return None
# hop from the start element by one until we reach the end element
diff = 1
nxt = self.since
while (nxt != self.to):
diff += 1
nxt = nxt.next(step=1)
newstart = self.since.next(step=diff*step)
newend = self.to.next(step=diff*step)
return MRange(newstart,newend)
## test
w = MTimeWeek(2018,40)
d = MTime(2019,4,9)
m = MTime(2019,7)
y = MTime(2020)
def range_desc(r,**kwargs):
if r is None: return ""
return r.desc(**kwargs)
def time_str(t): def time_str(t):
return "/".join(str(tp) for tp in t) obj = time_fix(t)
return obj.desc()
# converts strings and stuff to lists # converts strings and stuff to objects
def time_fix(t): def time_fix(t):
if t is None: return None
if isinstance(t,MRangeDescriptor): return t
if isinstance(t, str): if isinstance(t, str):
tod = datetime.datetime.utcnow() tod = datetime.datetime.utcnow()
@ -45,11 +371,13 @@ def time_fix(t):
weekdays = ["sunday","monday","tuesday","wednesday","thursday","friday","saturday"] weekdays = ["sunday","monday","tuesday","wednesday","thursday","friday","saturday"]
if t.lower() in ["today","day"]: if t.lower() in ["today","day"]:
t = [tod.year,tod.month,tod.day] return today()
elif t.lower() == "month": elif t.lower() in ["month","thismonth"]:
t = [tod.year,tod.month] return thismonth()
elif t.lower() == "year": elif t.lower() in ["year","thisyear"]:
t = [tod.year] return thisyear()
elif t.lower() in ["week","thisweek"]:
return thisweek()
elif t.lower() in months: elif t.lower() in months:
@ -67,192 +395,125 @@ def time_fix(t):
#if isinstance(t,tuple): t = list(t) #if isinstance(t,tuple): t = list(t)
try: try:
t = [int(p) for p in t] t = [int(p) for p in t]
return t[:3] return MTime(t[:3])
except: except:
pass pass
if isinstance(t[1],str) and t[1].startswith("W"): if isinstance(t[1],str) and t[1].startswith("W"):
try: try:
year = int(t[0])
weeknum = int(t[1][1:]) weeknum = int(t[1][1:])
return [t[0],"W",t[1]] return MTimeWeek(year=year,week=weeknum)
except: except:
pass raise
def get_range_object(since=None,to=None,within=None):
since,to,within = time_fix(since),time_fix(to),time_fix(within)
# check if we can simplify
if since is not None and to is not None and since == to: within = since
# TODO
if within is not None:
return within
else:
return MRange(since,to)
# checks if time is a week
def is_week(t):
return ((len(t) == 3) and (t[1] == "W"))
def week_to_days(t):
pass
# makes times the same precision level # makes times the same precision level
def time_pad(f,t,full=False): def time_pad(f,t,full=False):
f,t = time_fix(f), time_fix(t)
if f is None or t is None: return f,t
# week handling # week handling
if isinstance(f,MTimeWeek) and isinstance(t,MTimeWeek):
if full: return f.start(),t.end()
else: return f,t
if not isinstance(f,MTimeWeek) and isinstance(t,MTimeWeek):
t = t.end()
if isinstance(f,MTimeWeek) and not isinstance(t,MTimeWeek):
f = f.start()
while (f.precision < t.precision) or (full and f.precision < 3):
f = f.start()
while (f.precision > t.precision) or (full and t.precision < 3):
t = t.end()
return f,t
while (len(f) < len(t)) or (full and len(f) < 3):
if len(f) == 1: f.append(1)
elif len(f) == 2: f.append(1)
while (len(f) > len(t)) or (full and len(t) < 3):
if len(t) == 1: t.append(12)
elif len(t) == 2: t.append(monthrange(*t)[1])
return (f,t)
def time_desc(t,short=False):
if isinstance(t,int):
if short:
now = datetime.datetime.now(tz=datetime.timezone.utc)
difference = int(now.timestamp() - t)
if difference < 10: return "just now"
if difference < 60: return str(difference) + " seconds ago"
difference = int(difference/60)
if difference < 60: return str(difference) + " minutes ago" if difference>1 else str(difference) + " minute ago"
difference = int(difference/60)
if difference < 24: return str(difference) + " hours ago" if difference>1 else str(difference) + " hour ago"
difference = int(difference/24)
timeobject = datetime.datetime.utcfromtimestamp(t)
if difference < 5: return timeobject.strftime("%A")
if difference < 31: return str(difference) + " days ago" if difference>1 else str(difference) + " day ago"
#if difference < 300 and tim.year == now.year: return tim.strftime("%B")
#if difference < 300: return tim.strftime("%B %Y")
return timeobject.strftime("%d. %B %Y")
else:
timeobject = datetime.datetime.utcfromtimestamp(t)
return timeobject.strftime("%d. %b %Y %I:%M %p")
### TIMESTAMPS
def timestamp_desc(t,short=False):
if short:
now = datetime.datetime.now(tz=datetime.timezone.utc)
difference = int(now.timestamp() - t)
if difference < 10: return "just now"
if difference < 60: return str(difference) + " seconds ago"
difference = int(difference/60)
if difference < 60: return str(difference) + " minutes ago" if difference>1 else str(difference) + " minute ago"
difference = int(difference/60)
if difference < 24: return str(difference) + " hours ago" if difference>1 else str(difference) + " hour ago"
difference = int(difference/24)
timeobject = datetime.datetime.utcfromtimestamp(t)
if difference < 5: return timeobject.strftime("%A")
if difference < 31: return str(difference) + " days ago" if difference>1 else str(difference) + " day ago"
#if difference < 300 and tim.year == now.year: return tim.strftime("%B")
#if difference < 300: return tim.strftime("%B %Y")
return timeobject.strftime("%d. %B %Y")
else: else:
t = time_fix(t) timeobject = datetime.datetime.utcfromtimestamp(t)
date = [1970,1,1] return timeobject.strftime("%d. %b %Y %I:%M %p")
date[:len(t)] = t
timeobject = datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc)
nowdate = [1970,1,1]
nowobject = datetime.datetime.now(tz=datetime.timezone.utc)
nowdate[:len(t)] = [nowobject.year, nowobject.month, nowobject.day][:len(t)]
nowobject = datetime.datetime(nowdate[0],nowdate[1],nowdate[2],tzinfo=datetime.timezone.utc)
if short:
if len(t) == 3:
diff = (nowobject - timeobject).days
if diff == 0: return "Today"
if diff == 1: return "Yesterday"
if diff < 7 and diff > 1: return timeobject.strftime("%A")
#elif len(t) == 2:
if len(t) == 3: return timeobject.strftime("%d. %B %Y")
if len(t) == 2: return timeobject.strftime("%B %Y")
if len(t) == 1: return timeobject.strftime("%Y")
def range_desc(since=None,to=None,within=None,short=False):
# the 'short' var we pass down to some of the time_desc calls is a different one than the one here
# the function-wide one indicates whether we want the 'in' 'from' etc at the start
# the other one is if we want exact dates or weekdays etc
# but we still hand it down because it makes sense
if within is not None:
since = within
to = within
if since is None:
sincestr = ""
if to is None:
tostr = ""
if isinstance(since,int) and to is None:
sincestr = "since " + time_desc(since)
shortsincestr = sincestr
elif isinstance(to,int) and since is None:
tostr = "up until " + time_desc(to)
elif isinstance(since,int) and not isinstance(to,int):
sincestr = "from " + time_desc(since)
shortsincestr = time_desc(since)
tostr = "to the end of " + time_desc(to)
elif isinstance(to,int) and not isinstance(since,int):
sincestr = "from the start of " + time_desc(since)
shortsincestr = time_desc(since)
tostr = "to " + time_desc(to)
# if isinstance(since,int) and isinstance(to,int): result = "from " + time_desc(since) + " to " + time_desc(to)
# elif isinstance(since,int): result = "from " + time_desc(since) + " to the end of " + time_desc(to)
# elif isinstance(to,int): result = "from the start of " + time_desc(since) + " to " + time_desc(to)
else:
if since is not None and to is not None:
since,to = time_pad(since,to)
if since == to:
if len(since) == 3:
sincestr = "on " + time_desc(since)
else:
sincestr = "in " + time_desc(since)
shortsincestr = time_desc(since,short=True)
tostr = ""
elif _week(since,to):
sincestr = "in " + _week(since,to)
shortsincestr = _week(since,to)
tostr = ""
else:
fparts = time_desc(since).split(" ")
tparts = time_desc(to).split(" ")
fparts.reverse()
tparts.reverse()
fparts = fparts[len(commonprefix([fparts,tparts])):]
fparts.reverse()
tparts.reverse()
sincestr = "from " + " ".join(fparts)
shortsincestr = " ".join(fparts)
tostr = "to " + " ".join(tparts)
else:
if since is not None:
sincestr = "since " + time_desc(since)
shortsincestr = sincestr
if to is not None:
tostr = "up until " + time_desc(to)
if short: return shortsincestr + " " + tostr
else: return sincestr + " " + tostr
def time_stamps(since=None,to=None,within=None):
if within is not None:
since = within
to = within
def time_stamps(since=None,to=None,within=None,range=None):
if (since==None): stamp1 = FIRST_SCROBBLE if range is None: range = get_range_object(since=since,to=to,within=within)
else: return range.first_stamp(),range.last_stamp()
since = time_fix(since) #print(range.desc())
date = [1970,1,1] # if (since==None): stamp1 = FIRST_SCROBBLE
date[:len(since)] = since # else: stamp1 = range.first_stamp()
stamp1 = int(datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc).timestamp()) # if (to==None): stamp2 = int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp())
# else: stamp2 = range.last_stamp()
if (to==None): stamp2 = int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp()) # return stamp1,stamp2
else: # if (since==None): stamp1 = FIRST_SCROBBLE
to = time_fix(to) # else:
to = _get_next(to) # stamp1 = since1
date = [1970,1,1] # since = time_fix(since)
date[:len(to)] = to # date = [1970,1,1]
stamp2 = int(datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc).timestamp()) # date[:len(since)] = since
# stamp1 = int(datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc).timestamp())
#
return (stamp1,stamp2-1) # if (to==None): stamp2 = int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp())
# else:
# to = time_fix(to)
# to = _get_next(to)
# date = [1970,1,1]
# date[:len(to)] = to
# stamp2 = int(datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc).timestamp())
#
#
# return (stamp1,stamp2-1)
@ -260,118 +521,142 @@ def time_stamps(since=None,to=None,within=None):
def delimit_desc(step="month",stepn=1,trail=1): def delimit_desc(step="month",stepn=1,trail=1):
txt = "" txt = ""
if stepn is not 1: txt += _num(stepn) + "-" if stepn is not 1: txt += _num(stepn) + "-"
txt += {"year":"Yearly","month":"Monthly","day":"Daily"}[step.lower()] txt += {"year":"Yearly","month":"Monthly","week":"Weekly","day":"Daily"}[step.lower()]
#if trail is not 1: txt += " " + _num(trail) + "-Trailing" #if trail is not 1: txt += " " + _num(trail) + "-Trailing"
if trail is not 1: txt += " Trailing" #we don't need all the info in the title if trail is math.inf: txt += " Cumulative"
elif trail is not 1: txt += " Trailing" #we don't need all the info in the title
return txt return txt
def _week(since,to):
if len(since) != 3 or len(to) != 3: return False
dt_since, dt_to = datetime.datetime(*since,tzinfo=datetime.timezone.utc), datetime.datetime(*to,tzinfo=datetime.timezone.utc)
if (dt_to - dt_since).days != 6: return False
if dt_since.weekday() != 6: return False
c = dt_to.isocalendar()[:2]
return str("Week " + str(c[1]) + " " + str(c[0]))
def _num(i):
names = ["Zero","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven","Twelve"]
if i < len(names): return names[i]
else: return str(i)
def day_from_timestamp(stamp):
dt = datetime.datetime.utcfromtimestamp(stamp)
return MTime(dt.year,dt.month,dt.day)
def month_from_timestamp(stamp):
dt = datetime.datetime.utcfromtimestamp(stamp)
return MTime(dt.year,dt.month)
def year_from_timestamp(stamp):
dt = datetime.datetime.utcfromtimestamp(stamp)
return MTime(dt.year)
def week_from_timestamp(stamp):
dt = datetime.datetime.utcfromtimestamp(stamp)
d = date(dt.year,dt.month,dt.day)
y,w,_ = d.chrcalendar()
return MTimeWeek(y,w)
def from_timestamp(stamp,unit):
if unit == "day": return day_from_timestamp(stamp)
if unit == "week": return week_from_timestamp(stamp)
if unit == "month": return month_from_timestamp(stamp)
if unit == "year": return year_from_timestamp(stamp)
# since, to and within can accept old notations or objects. timerange can only be a new object.
def ranges(since=None,to=None,within=None,timerange=None,step="month",stepn=1,trail=1,max_=None):
(firstincluded,lastincluded) = time_stamps(since=since,to=to,within=within,range=timerange)
def ranges(since=None,to=None,within=None,step="month",stepn=1,trail=1,max_=None): d_start = from_timestamp(firstincluded,step)
d_start = d_start.next(stepn-1) #last part of first included range
(firstincluded,lastincluded) = time_stamps(since=since,to=to,within=within)
d_start = _get_start_of(firstincluded,step)
d_end = _get_start_of(lastincluded,step)
d_start = _get_next(d_start,step,stepn) # first range should end right after the first active scrobbling week / month / whatever relevant step
d_start = _get_next(d_start,step,stepn * trail * -1) # go one range back to begin
i = 0 i = 0
d_current = d_start current_end = d_start
while not _is_past(d_current,d_end) and (max_ is None or i < max_): while current_end.first_stamp() <= lastincluded and (max_ is None or i < max_):
d_current_end = _get_end(d_current,step,stepn * trail) current_start = current_end.next((stepn*trail-1)*-1)
yield (d_current,d_current_end) if current_start == current_end:
d_current = _get_next(d_current,step,stepn) yield current_start
else:
yield MRange(current_start,current_end)
current_end = current_end.next(stepn)
i += 1 i += 1
def _get_start_of(timestamp,unit):
date = datetime.datetime.utcfromtimestamp(timestamp)
if unit == "year":
#return [date.year,1,1]
return [date.year]
elif unit == "month":
#return [date.year,date.month,1]
return [date.year,date.month]
elif unit == "day":
return [date.year,date.month,date.day]
elif unit == "week":
change = (date.weekday() + 1) % 7
d = datetime.timedelta(days=change)
newdate = date - d
return [newdate.year,newdate.month,newdate.day]
def _get_next(time,unit="auto",step=1): def today():
result = time[:] tod = date.today()
if unit == "auto": return MTime(tod.year,tod.month,tod.day)
# see how long the list is, increment by the last specified unit def thisweek():
unit = [None,"year","month","day"][len(time)] tod = date.today()
#while len(time) < 3: y,w,_ = tod.chrcalendar()
# time.append(1) return MTimeWeek(y,w)
def thismonth():
if unit == "year": tod = date.today()
#return [time[0] + step,time[1],time[2]] return MTime(tod.year,tod.month)
result[0] += step def thisyear():
return result tod = date.today()
elif unit == "month": return MTime(tod.year)
#result = [time[0],time[1] + step,time[2]]
result[1] += step
while result[1] > 12:
result[1] -= 12
result[0] += 1
while result[1] < 1:
result[1] += 12
result[0] -= 1
return result
elif unit == "day":
dt = datetime.datetime(time[0],time[1],time[2])
d = datetime.timedelta(days=step)
newdate = dt + d
return [newdate.year,newdate.month,newdate.day]
#eugh
elif unit == "week":
return _get_next(time,"day",step * 7)
#def _get_start_of(timestamp,unit):
# date = datetime.datetime.utcfromtimestamp(timestamp)
# if unit == "year":
# #return [date.year,1,1]
# return [date.year]
# elif unit == "month":
# #return [date.year,date.month,1]
# return [date.year,date.month]
# elif unit == "day":
# return [date.year,date.month,date.day]
# elif unit == "week":
# change = (date.weekday() + 1) % 7
# d = datetime.timedelta(days=change)
# newdate = date - d
# return [newdate.year,newdate.month,newdate.day]
#
#def _get_next(time,unit="auto",step=1):
# result = time[:]
# if unit == "auto":
# if is_week(time): unit = "week"
# # see how long the list is, increment by the last specified unit
# else: unit = [None,"year","month","day"][len(time)]
# #while len(time) < 3:
# # time.append(1)
#
# if unit == "year":
# #return [time[0] + step,time[1],time[2]]
# result[0] += step
# return result
# elif unit == "month":
# #result = [time[0],time[1] + step,time[2]]
# result[1] += step
# while result[1] > 12:
# result[1] -= 12
# result[0] += 1
# while result[1] < 1:
# result[1] += 12
# result[0] -= 1
# return result
# elif unit == "day":
# dt = datetime.datetime(time[0],time[1],time[2])
# d = datetime.timedelta(days=step)
# newdate = dt + d
# return [newdate.year,newdate.month,newdate.day]
# #eugh
# elif unit == "week":
# return _get_next(time,"day",step * 7)
#
# like _get_next(), but gets the last INCLUDED day / month whatever # like _get_next(), but gets the last INCLUDED day / month whatever
def _get_end(time,unit="auto",step=1): #def _get_end(time,unit="auto",step=1):
if step == 1: # if step == 1:
if unit == "auto": return time[:] # if unit == "auto": return time[:]
if unit == "year" and len(time) == 1: return time[:] # if unit == "year" and len(time) == 1: return time[:]
if unit == "month" and len(time) == 2: return time[:] # if unit == "month" and len(time) == 2: return time[:]
if unit == "day" and len(time) == 3: return time[:] # if unit == "day" and len(time) == 3: return time[:]
exc = _get_next(time,unit,step) # exc = _get_next(time,unit,step)
inc = _get_next(exc,"auto",-1) # inc = _get_next(exc,"auto",-1)
return inc # return inc
#
#def _is_past(date,limit):
def _is_past(date,limit): # date_, limit_ = date[:], limit[:]
date_, limit_ = date[:], limit[:] # while len(date_) != 3: date_.append(1)
while len(date_) != 3: date_.append(1) # while len(limit_) != 3: limit_.append(1)
while len(limit_) != 3: limit_.append(1) # if not date_[0] == limit_[0]:
if not date_[0] == limit_[0]: # return date_[0] > limit_[0]
return date_[0] > limit_[0] # if not date_[1] == limit_[1]:
if not date_[1] == limit_[1]: # return date_[1] > limit_[1]
return date_[1] > limit_[1] # return (date_[2] > limit_[2])
return (date_[2] > limit_[2]) ##

View File

@ -1,7 +1,7 @@
import urllib import urllib
from bottle import FormsDict from bottle import FormsDict
from malojatime import time_fix, time_str from malojatime import time_fix, time_str, get_range_object
import math
# necessary because urllib.parse.urlencode doesnt handle multidicts # necessary because urllib.parse.urlencode doesnt handle multidicts
def compose_querystring(*dicts,exclude=[]): def compose_querystring(*dicts,exclude=[]):
@ -39,7 +39,7 @@ def remove_identical(*dicts):
return new return new
# this also sets defaults!
def uri_to_internal(keys,forceTrack=False,forceArtist=False): def uri_to_internal(keys,forceTrack=False,forceArtist=False):
# output: # output:
@ -59,41 +59,54 @@ def uri_to_internal(keys,forceTrack=False,forceArtist=False):
# 2 # 2
resultkeys2 = {} resultkeys2 = {}
if "since" in keys: resultkeys2["since"] = time_fix(keys.get("since")) # if "since" in keys: resultkeys2["since"] = time_fix(keys.get("since"))
elif "from" in keys: resultkeys2["since"] = time_fix(keys.get("from")) # elif "from" in keys: resultkeys2["since"] = time_fix(keys.get("from"))
elif "start" in keys: resultkeys2["since"] = time_fix(keys.get("start")) # elif "start" in keys: resultkeys2["since"] = time_fix(keys.get("start"))
# # #
if "to" in keys: resultkeys2["to"] = time_fix(keys.get("to")) # if "to" in keys: resultkeys2["to"] = time_fix(keys.get("to"))
elif "until" in keys: resultkeys2["to"] = time_fix(keys.get("until")) # elif "until" in keys: resultkeys2["to"] = time_fix(keys.get("until"))
elif "end" in keys: resultkeys2["to"] = time_fix(keys.get("end")) # elif "end" in keys: resultkeys2["to"] = time_fix(keys.get("end"))
# # #
if "since" in resultkeys2 and "to" in resultkeys2 and resultkeys2["since"] == resultkeys2["to"]: # if "since" in resultkeys2 and "to" in resultkeys2 and resultkeys2["since"] == resultkeys2["to"]:
resultkeys2["within"] = resultkeys2["since"] # resultkeys2["within"] = resultkeys2["since"]
del resultkeys2["since"] # del resultkeys2["since"]
del resultkeys2["to"] # del resultkeys2["to"]
# # #
if "in" in keys: resultkeys2["within"] = time_fix(keys.get("in")) # if "in" in keys: resultkeys2["within"] = time_fix(keys.get("in"))
elif "within" in keys: resultkeys2["within"] = time_fix(keys.get("within")) # elif "within" in keys: resultkeys2["within"] = time_fix(keys.get("within"))
elif "during" in keys: resultkeys2["within"] = time_fix(keys.get("during")) # elif "during" in keys: resultkeys2["within"] = time_fix(keys.get("during"))
if "within" in resultkeys2: # if "within" in resultkeys2:
if "since" in resultkeys2: # if "since" in resultkeys2:
del resultkeys2["since"] # del resultkeys2["since"]
if "to" in resultkeys2: # if "to" in resultkeys2:
del resultkeys2["to"] # del resultkeys2["to"]
since,to,within = None,None,None
if "since" in keys: since = keys.get("since")
elif "from" in keys: since = keys.get("from")
elif "start" in keys: since = keys.get("start")
if "to" in keys: to = keys.get("to")
elif "until" in keys: to = keys.get("until")
elif "end" in keys: to = keys.get("end")
if "in" in keys: within = keys.get("in")
elif "within" in keys: within = keys.get("within")
elif "during" in keys: within = keys.get("during")
resultkeys2["timerange"] = get_range_object(since=since,to=to,within=within)
#3 #3
resultkeys3 = {} resultkeys3 = {"step":"month","stepn":1,"trail":1}
if "step" in keys: [resultkeys3["step"],resultkeys3["stepn"]] = (keys["step"].split("-") + [1])[:2] if "step" in keys: [resultkeys3["step"],resultkeys3["stepn"]] = (keys["step"].split("-") + [1])[:2]
if "stepn" in keys: resultkeys3["stepn"] = keys["stepn"] #overwrite if explicitly given if "stepn" in keys: resultkeys3["stepn"] = keys["stepn"] #overwrite if explicitly given
if "stepn" in resultkeys3: resultkeys3["stepn"] = int(resultkeys3["stepn"]) #in both cases, convert it here if "stepn" in resultkeys3: resultkeys3["stepn"] = int(resultkeys3["stepn"]) #in both cases, convert it here
if "trail" in keys: resultkeys3["trail"] = int(keys["trail"]) if "trail" in keys: resultkeys3["trail"] = int(keys["trail"])
if "cumulative" in keys: resultkeys3["trail"] = math.inf
#4 #4
resultkeys4 = {} resultkeys4 = {"max_":300}
if "max" in keys: resultkeys4["max_"] = int(keys["max"]) if "max" in keys: resultkeys4["max_"] = int(keys["max"])
return resultkeys1, resultkeys2, resultkeys3, resultkeys4 return resultkeys1, resultkeys2, resultkeys3, resultkeys4
def internal_to_uri(keys): def internal_to_uri(keys):
@ -109,12 +122,16 @@ def internal_to_uri(keys):
urikeys.append("title",keys["track"]["title"]) urikeys.append("title",keys["track"]["title"])
#time #time
if "within" in keys: 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"])) urikeys.append("in",time_str(keys["within"]))
else: else:
if "since" in keys: if "since" in keys and keys["since"] is not None:
urikeys.append("since",time_str(keys["since"])) urikeys.append("since",time_str(keys["since"]))
if "to" in keys: if "to" in keys and keys["to"] is not None:
urikeys.append("to",time_str(keys["to"])) urikeys.append("to",time_str(keys["to"]))
# delimit # delimit
@ -123,7 +140,10 @@ def internal_to_uri(keys):
if "stepn" in keys: if "stepn" in keys:
urikeys.append("stepn",str(keys["stepn"])) urikeys.append("stepn",str(keys["stepn"]))
if "trail" in keys: if "trail" in keys:
urikeys.append("trail",str(keys["trail"])) if keys["trail"] == math.inf:
urikeys.append("cumulative","yes")
else:
urikeys.append("trail",str(keys["trail"]))
# stuff # stuff
if "max_" in keys: if "max_" in keys:

View File

@ -10,7 +10,7 @@ def instructions(keys):
_, timekeys, _, amountkeys = uri_to_internal(keys) _, timekeys, _, amountkeys = uri_to_internal(keys)
limitstring = range_desc(**timekeys) limitstring = timekeys["timerange"].desc(prefix=True)
html_filterselector = module_filterselection(keys) html_filterselector = module_filterselection(keys)

View File

@ -26,7 +26,7 @@ def instructions(keys):
else: else:
imgurl = "" imgurl = ""
limitstring += " " + range_desc(**timekeys) limitstring += " " + timekeys["timerange"].desc(prefix=True)
pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else [] pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else []

View File

@ -24,7 +24,7 @@ def instructions(keys):
#limitkey["artist"], limitkey["associated"] = keys.get("artist"), (keys.get("associated")!=None) #limitkey["artist"], limitkey["associated"] = keys.get("artist"), (keys.get("associated")!=None)
limitstring += "of " + artistLink(filterkeys.get("artist")) limitstring += "of " + artistLink(filterkeys.get("artist"))
limitstring += " " + range_desc(**timekeys) limitstring += " " + timekeys["timerange"].desc(prefix=True)
delimitstring = delimit_desc(**delimitkeys) delimitstring = delimit_desc(**delimitkeys)

View File

@ -29,7 +29,7 @@ def instructions(keys):
if moreartists != []: if moreartists != []:
limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>" limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>"
limitstring += " " + range_desc(**timekeys) limitstring += " " + range_desc(timekeys["timerange"],prefix=True)
delimitstring = delimit_desc(**delimitkeys) delimitstring = delimit_desc(**delimitkeys)

View File

@ -26,7 +26,7 @@ def instructions(keys):
if moreartists != []: if moreartists != []:
limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>" limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>"
limitstring += " " + range_desc(**timekeys) limitstring += " " + timekeys["timerange"].desc(prefix=True)
html_filterselector = module_filterselection(keys) html_filterselector = module_filterselection(keys)

View File

@ -77,6 +77,7 @@
<div class="sidelist"> <div class="sidelist">
<h1><a href="/scrobbles?max=100">Last Scrobbles</a></h1> <h1><a href="/scrobbles?max=100">Last Scrobbles</a></h1>
<span class="stats">Today</span> KEY_SCROBBLE_NUM_TODAY <span class="stats">Today</span> KEY_SCROBBLE_NUM_TODAY
<span class="stats">This Week</span> KEY_SCROBBLE_NUM_WEEK
<span class="stats">This month</span> KEY_SCROBBLE_NUM_MONTH <span class="stats">This month</span> KEY_SCROBBLE_NUM_MONTH
<span class="stats">This year</span> KEY_SCROBBLE_NUM_YEAR <span class="stats">This year</span> KEY_SCROBBLE_NUM_YEAR
<span class="stats">All Time</span> KEY_SCROBBLE_NUM_TOTAL <span class="stats">All Time</span> KEY_SCROBBLE_NUM_TOTAL

View File

@ -14,33 +14,29 @@ def instructions(keys):
js_command += "showRange('toptracks','" + get_settings("DEFAULT_RANGE_CHARTS_TRACKS") + "');" js_command += "showRange('toptracks','" + get_settings("DEFAULT_RANGE_CHARTS_TRACKS") + "');"
js_command += "showRange('pulse','" + get_settings("DEFAULT_RANGE_PULSE") + "');" js_command += "showRange('pulse','" + get_settings("DEFAULT_RANGE_PULSE") + "');"
# get start of week
tod = datetime.utcnow()
change = (tod.weekday() + 1) % 7
d = timedelta(days=change)
newdate = tod - d
weekstart = [newdate.year,newdate.month,newdate.day]
#clock() clock()
from malojatime import today,thisweek,thismonth,thisyear
# artists # artists
topartists_total = module_artistcharts_tiles() topartists_total = module_artistcharts_tiles()
topartists_year = module_artistcharts_tiles(since="year") topartists_year = module_artistcharts_tiles(timerange=thisyear())
topartists_month = module_artistcharts_tiles(since="month") topartists_month = module_artistcharts_tiles(timerange=thismonth())
topartists_week = module_artistcharts_tiles(since=weekstart) topartists_week = module_artistcharts_tiles(timerange=thisweek())
#clockp("Artists") clockp("Artists")
# tracks # tracks
toptracks_total = module_trackcharts_tiles() toptracks_total = module_trackcharts_tiles()
toptracks_year = module_trackcharts_tiles(since="year") toptracks_year = module_trackcharts_tiles(timerange=thisyear())
toptracks_month = module_trackcharts_tiles(since="month") toptracks_month = module_trackcharts_tiles(timerange=thismonth())
toptracks_week = module_trackcharts_tiles(since=weekstart) toptracks_week = module_trackcharts_tiles(timerange=thisweek())
#clockp("Tracks") clockp("Tracks")
@ -48,63 +44,50 @@ def instructions(keys):
# scrobbles # scrobbles
html_scrobbles, _, _ = module_scrobblelist(max_=15,shortTimeDesc=True,pictures=True,earlystop=True) html_scrobbles, _, _ = module_scrobblelist(max_=15,shortTimeDesc=True,pictures=True,earlystop=True)
#clockp("Scrobbles") clockp("Scrobbles")
# stats # stats
#(amount_day,amount_month,amount_year,amount_total) = database.get_scrobbles_num_multiple(("today","month","year",None)) amount_day = database.get_scrobbles_num(timerange=today())
#amount_month += amount_day scrobbles_today = "<a href='/scrobbles?in=today'>" + str(amount_day) + "</a>"
#amount_year += amount_month
#amount_total += amount_year
amount_day = database.get_scrobbles_num(since="today") amount_week = database.get_scrobbles_num(timerange=thisweek())
scrobbles_today = "<a href='/scrobbles?since=today'>" + str(amount_day) + "</a>" scrobbles_week = "<a href='/scrobbles?in=week'>" + str(amount_week) + "</a>"
amount_month = database.get_scrobbles_num(since="month") amount_month = database.get_scrobbles_num(timerange=thismonth())
scrobbles_month = "<a href='/scrobbles?since=month'>" + str(amount_month) + "</a>" scrobbles_month = "<a href='/scrobbles?in=month'>" + str(amount_month) + "</a>"
amount_year = database.get_scrobbles_num(since="year") amount_year = database.get_scrobbles_num(timerange=thisyear())
scrobbles_year = "<a href='/scrobbles?since=year'>" + str(amount_year) + "</a>" scrobbles_year = "<a href='/scrobbles?in=year'>" + str(amount_year) + "</a>"
amount_total = database.get_scrobbles_num() amount_total = database.get_scrobbles_num()
scrobbles_total = "<a href='/scrobbles'>" + str(amount_total) + "</a>" scrobbles_total = "<a href='/scrobbles'>" + str(amount_total) + "</a>"
#clockp("Amounts") clockp("Amounts")
# pulse # pulse
dt = datetime.utcnow()
first_month = [dt.year-1,dt.month+1]
dt_firstweek = dt - timedelta(11*7) - timedelta((tod.weekday() + 1) % 7)
first_week = [dt_firstweek.year,dt_firstweek.month,dt_firstweek.day]
dt_firstday = dt - timedelta(6)
first_day = [dt_firstday.year,dt_firstday.month,dt_firstday.day]
first_year = [dt.year - 9]
if first_month[1] > 12: first_month = [first_month[0]+1,first_month[1]-12]
html_pulse_days = module_pulse(max_=7,since=first_day,step="day",trail=1)
html_pulse_weeks = module_pulse(max_=12,since=first_week,step="week",trail=1) html_pulse_days = module_pulse(max_=7,since=today().next(-6),step="day",trail=1)
html_pulse_months = module_pulse(max_=12,since=first_month,step="month",trail=1) html_pulse_weeks = module_pulse(max_=12,since=thisweek().next(-11),step="week",trail=1)
html_pulse_years = module_pulse(max_=10,since=first_year,step="year",trail=1) html_pulse_months = module_pulse(max_=12,since=thismonth().next(-11),step="month",trail=1)
html_pulse_years = module_pulse(max_=10,since=thisyear().next(-9),step="year",trail=1)
#html_pulse_week = module_pulse(max_=7,since=weekstart,step="day",trail=1) #html_pulse_week = module_pulse(max_=7,since=weekstart,step="day",trail=1)
#html_pulse_month = module_pulse(max_=30,since=[dt.year,dt.month],step="day",trail=1) #html_pulse_month = module_pulse(max_=30,since=[dt.year,dt.month],step="day",trail=1)
#html_pulse_year = module_pulse(max_=12,since=[dt.year],step="month",trail=1) #html_pulse_year = module_pulse(max_=12,since=[dt.year],step="month",trail=1)
#clockp("Pulse") clockp("Pulse")
#pushresources = [{"file":img,"type":"image"} for img in artistimages + trackimages] #can't push scrobble images as we don't get them from the module function, need to think about that #pushresources = [{"file":img,"type":"image"} for img in artistimages + trackimages] #can't push scrobble images as we don't get them from the module function, need to think about that
pushresources = [] pushresources = []
replace = { replace = {
# "KEY_ARTISTIMAGE":artistimages,"KEY_ARTISTNAME":artisttitles,"KEY_ARTISTLINK":artistlinks,"KEY_POSITION_ARTIST":posrange,
# "KEY_TRACKIMAGE":trackimages,"KEY_TRACKNAME":tracktitles,"KEY_TRACKLINK":tracklinks,"KEY_POSITION_TRACK":posrange,
# "KEY_SCROBBLE_TIME":scrobbletimes,"KEY_SCROBBLE_ARTISTS":scrobbleartists,"KEY_SCROBBLE_TITLE":scrobbletracklinks,"KEY_SCROBBLE_IMAGE":scrobbleimages,
# "KEY_PULSE_TERM":pulse_rangedescs,"KEY_PULSE_AMOUNT":pulse_amounts,"KEY_PULSE_BAR":pulse_bars
"KEY_TOPARTISTS_TOTAL":topartists_total,"KEY_TOPARTISTS_YEAR":topartists_year,"KEY_TOPARTISTS_MONTH":topartists_month,"KEY_TOPARTISTS_WEEK":topartists_week, "KEY_TOPARTISTS_TOTAL":topartists_total,"KEY_TOPARTISTS_YEAR":topartists_year,"KEY_TOPARTISTS_MONTH":topartists_month,"KEY_TOPARTISTS_WEEK":topartists_week,
"KEY_TOPTRACKS_TOTAL":toptracks_total,"KEY_TOPTRACKS_YEAR":toptracks_year,"KEY_TOPTRACKS_MONTH":toptracks_month,"KEY_TOPTRACKS_WEEK":toptracks_week, "KEY_TOPTRACKS_TOTAL":toptracks_total,"KEY_TOPTRACKS_YEAR":toptracks_year,"KEY_TOPTRACKS_MONTH":toptracks_month,"KEY_TOPTRACKS_WEEK":toptracks_week,
"KEY_JS_INIT_RANGES":js_command, "KEY_JS_INIT_RANGES":js_command,
"KEY_SCROBBLE_NUM_TODAY":scrobbles_today,"KEY_SCROBBLE_NUM_MONTH":scrobbles_month,"KEY_SCROBBLE_NUM_YEAR":scrobbles_year,"KEY_SCROBBLE_NUM_TOTAL":scrobbles_total, "KEY_SCROBBLE_NUM_TODAY":scrobbles_today,"KEY_SCROBBLE_NUM_WEEK":scrobbles_week,"KEY_SCROBBLE_NUM_MONTH":scrobbles_month,"KEY_SCROBBLE_NUM_YEAR":scrobbles_year,"KEY_SCROBBLE_NUM_TOTAL":scrobbles_total,
"KEY_SCROBBLES":html_scrobbles, "KEY_SCROBBLES":html_scrobbles,
"KEY_PULSE_MONTHS":html_pulse_months,"KEY_PULSE_YEARS":html_pulse_years,"KEY_PULSE_DAYS":html_pulse_days,"KEY_PULSE_WEEKS":html_pulse_weeks, "KEY_PULSE_MONTHS":html_pulse_months,"KEY_PULSE_YEARS":html_pulse_years,"KEY_PULSE_DAYS":html_pulse_days,"KEY_PULSE_WEEKS":html_pulse_weeks,
#"KEY_PULSE_YEAR":html_pulse_year,"KEY_PULSE_MONTH":html_pulse_month,"KEY_PULSE_WEEK":html_pulse_week #"KEY_PULSE_YEAR":html_pulse_year,"KEY_PULSE_MONTH":html_pulse_month,"KEY_PULSE_WEEK":html_pulse_week

View File

@ -26,7 +26,7 @@ def instructions(keys):
else: else:
imgurl = "" imgurl = ""
limitstring += " " + range_desc(**timekeys) limitstring += " " + timekeys["timerange"].desc(prefix=True)
pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else [] pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else []

View File

@ -26,7 +26,7 @@ def instructions(keys):
else: else:
imgurl = "" imgurl = ""
limitstring += " " + range_desc(**timekeys) limitstring += " " + timekeys["timerange"].desc(prefix=True)
pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else [] pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else []