Implemented proper range descriptions

This commit is contained in:
Krateng 2019-03-02 22:55:22 +01:00
parent 9d0fc8e073
commit 0c42531218
12 changed files with 505 additions and 279 deletions

View File

@ -6,6 +6,7 @@ import os
import datetime
from cleanup import *
from utilities import *
from malojatime import *
import sys
dbserver = Bottle()
@ -67,6 +68,7 @@ def createScrobble(artists,title,time):
i = getTrackID(artists,title)
obj = (i,time,False)
SCROBBLES.append(obj)
register_scrobbletime(time)
def readScrobble(artists,title,time):
@ -76,6 +78,7 @@ def readScrobble(artists,title,time):
i = getTrackID(artists,title)
obj = (i,time,True)
SCROBBLES.append(obj)
register_scrobbletime(time)
def getArtistID(name):
@ -314,7 +317,7 @@ def get_pulse_external():
def get_pulse(step="month",stepn=1,trail=1,**keys):
(ts_start,ts_end) = getTimestamps(**{k:keys[k] for k in keys if k in ["since","to","within"]})
(ts_start,ts_end) = time_stamps(**{k:keys[k] for k in keys if k in ["since","to","within"]})
d_start = getStartOf(ts_start,step)
d_end = getStartOf(ts_end,step)
d_start = getNext(d_start,step,stepn) # first range should end right after the first active scrobbling week / month / whatever relevant step
@ -330,7 +333,7 @@ def get_pulse(step="month",stepn=1,trail=1,**keys):
res = len(db_query(since=d_current,to=d_current_end,**{k:keys[k] for k in keys if k in ["artists","artist","track","title","associated"]}))
results.append({"from":d_current,"to":d_current_end,"scrobbles":res})
d_current = getNext(d_current,step,stepn)
if isPast(d_current_end,d_end):
if isPast(d_current,d_end):
break
return results
@ -358,7 +361,7 @@ def get_top_artists_external():
def get_top_artists(step="month",stepn=1,trail=3,**keys):
(ts_start,ts_end) = getTimestamps(**{k:keys[k] for k in keys if k in ["since","to","within"]})
(ts_start,ts_end) = time_stamps(**{k:keys[k] for k in keys if k in ["since","to","within"]})
d_start = getStartOf(ts_start,step)
d_end = getStartOf(ts_end,step)
d_start = getNext(d_start,step,stepn) # first range should end right after the first active scrobbling week / month / whatever relevant step
@ -375,7 +378,7 @@ def get_top_artists(step="month",stepn=1,trail=3,**keys):
except:
results.append({"from":d_current,"to":d_current_end,"artist":None,"scrobbles":0})
d_current = getNext(d_current,step,stepn)
if isPast(d_current_end,d_end):
if isPast(d_current,d_end):
break
return results
@ -404,7 +407,7 @@ def get_top_tracks_external():
def get_top_tracks(step="month",stepn=1,trail=3,**keys):
(ts_start,ts_end) = getTimestamps(**{k:keys[k] for k in keys if k in ["since","to","within"]})
(ts_start,ts_end) = time_stamps(**{k:keys[k] for k in keys if k in ["since","to","within"]})
d_start = getStartOf(ts_start,step)
d_end = getStartOf(ts_end,step)
d_start = getNext(d_start,step,stepn) # first range should end right after the first active scrobbling week / month / whatever relevant step
@ -422,7 +425,7 @@ def get_top_tracks(step="month",stepn=1,trail=3,**keys):
except:
results.append({"from":d_current,"to":d_current_end,"track":None,"scrobbles":0})
d_current = getNext(d_current,step,stepn)
if isPast(d_current_end,d_end):
if isPast(d_current,d_end):
break
return results
@ -854,7 +857,7 @@ def db_query(artist=None,artists=None,title=None,track=None,since=None,to=None,w
# print(within)
# print(associated)
(since, to) = getTimestamps(since,to,within)
(since, to) = time_stamps(since,to,within)
# 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
@ -898,7 +901,7 @@ def db_query(artist=None,artists=None,title=None,track=None,since=None,to=None,w
# Queries that... well... aggregate
def db_aggregate(by=None,since=None,to=None,within=None,artist=None):
(since, to) = getTimestamps(since,to,within)
(since, to) = time_stamps(since,to,within)
if isinstance(artist, str):
artist = ARTISTS.index(artist)
@ -959,71 +962,72 @@ def db_search(query,type=None):
# Takes user inputs like YYYY/MM and returns the timestamps. Returns timestamp if timestamp was already given.
# to dates are interpreted differently (from 2010 and to 2010 both include all of 2010)
def getTimestamps(since=None,to=None,within=None):
f,t,i = since,to,within
if i is not None:
f = i
t = i
if isinstance(f, str) and f.lower() == "today":
tod = datetime.datetime.utcnow()
f = [tod.year,tod.month,tod.day]
if isinstance(t, str) and t.lower() == "today":
tod = datetime.datetime.utcnow()
t = [tod.year,tod.month,tod.day]
if isinstance(f, str) and f.lower() == "month":
tod = datetime.datetime.utcnow()
f = [tod.year,tod.month]
if isinstance(t, str) and t.lower() == "month":
tod = datetime.datetime.utcnow()
t = [tod.year,tod.month]
if isinstance(f, str) and f.lower() == "year":
tod = datetime.datetime.utcnow()
f = [tod.year]
if isinstance(t, str) and t.lower() == "year":
tod = datetime.datetime.utcnow()
t = [tod.year]
if isinstance(f, str):
f = [int(x) for x in f.split("/")]
if isinstance(t, str):
t = [int(x) for x in t.split("/")]
# this step is done if either the input is a list or the first step was done (which creates a list)
if isinstance(f, list):
date = [1970,1,1]
date[:len(f)] = f
#while len(f) < 3: f.append(1) # padding month and day
f = date
#f = int(datetime.datetime(date[0],date[1],date[2],date[3],date[4],tzinfo=datetime.timezone.utc).timestamp())
f = int(datetime.datetime(f[0],f[1],f[2],tzinfo=datetime.timezone.utc).timestamp())
if isinstance(t, list):
t = getNext(t)
#while len(t) < 3: t.append(1)
date = [1970,1,1]
date[:len(t)] = t
t = date
#t = int(datetime.datetime(date[0],date[1],date[2],date[3],date[4],tzinfo=datetime.timezone.utc).timestamp())
t = int(datetime.datetime(t[0],t[1],t[2],tzinfo=datetime.timezone.utc).timestamp())
if (f==None):
f = min(timestamps)
if (t==None):
t = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp()
return (f,t)
# NOW DONE IN THE MALOJATIME MODULE
#def getTimestamps(since=None,to=None,within=None):
#
# f,t,i = since,to,within
#
# if i is not None:
# f = i
# t = i
#
# if isinstance(f, str) and f.lower() == "today":
# tod = datetime.datetime.utcnow()
# f = [tod.year,tod.month,tod.day]
# if isinstance(t, str) and t.lower() == "today":
# tod = datetime.datetime.utcnow()
# t = [tod.year,tod.month,tod.day]
#
#
# if isinstance(f, str) and f.lower() == "month":
# tod = datetime.datetime.utcnow()
# f = [tod.year,tod.month]
# if isinstance(t, str) and t.lower() == "month":
# tod = datetime.datetime.utcnow()
# t = [tod.year,tod.month]
#
#
# if isinstance(f, str) and f.lower() == "year":
# tod = datetime.datetime.utcnow()
# f = [tod.year]
# if isinstance(t, str) and t.lower() == "year":
# tod = datetime.datetime.utcnow()
# t = [tod.year]
#
#
# if isinstance(f, str):
# f = [int(x) for x in f.split("/")]
#
# if isinstance(t, str):
# t = [int(x) for x in t.split("/")]
#
#
# # this step is done if either the input is a list or the first step was done (which creates a list)
# if isinstance(f, list):
# date = [1970,1,1]
# date[:len(f)] = f
# #while len(f) < 3: f.append(1) # padding month and day
# f = date
# #f = int(datetime.datetime(date[0],date[1],date[2],date[3],date[4],tzinfo=datetime.timezone.utc).timestamp())
# f = int(datetime.datetime(f[0],f[1],f[2],tzinfo=datetime.timezone.utc).timestamp())
#
# if isinstance(t, list):
# t = getNext(t)
# #while len(t) < 3: t.append(1)
# date = [1970,1,1]
# date[:len(t)] = t
# t = date
# #t = int(datetime.datetime(date[0],date[1],date[2],date[3],date[4],tzinfo=datetime.timezone.utc).timestamp())
# t = int(datetime.datetime(t[0],t[1],t[2],tzinfo=datetime.timezone.utc).timestamp())
#
# if (f==None):
# f = min(timestamps)
# if (t==None):
# t = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp()
#
# return (f,t)
#
#

View File

@ -61,52 +61,52 @@ def removeIdentical(*dicts):
return new
def getTimeDesc(timestamp,short=False):
tim = datetime.datetime.utcfromtimestamp(timestamp)
if short:
now = datetime.datetime.now(tz=datetime.timezone.utc)
difference = int(now.timestamp() - timestamp)
#def getTimeDesc(timestamp,short=False):
# tim = datetime.datetime.utcfromtimestamp(timestamp)
# if short:
# now = datetime.datetime.now(tz=datetime.timezone.utc)
# difference = int(now.timestamp() - timestamp)
#
# 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)
# if difference < 5: return tim.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 tim.strftime("%d. %B %Y")
# else:
# return tim.strftime("%d. %b %Y %I:%M %p")
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)
if difference < 5: return tim.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 tim.strftime("%d. %B %Y")
else:
return tim.strftime("%d. %b %Y %I:%M %p")
def getRangeDesc(timeA,timeB,inclusiveB=True):
# string to list
if isinstance(timeA,str): timeA = timeA.split("/")
if isinstance(timeB,str): timeB = timeB.split("/")
# if lists, we have it potentially much easier:
if isinstance(timeA,list) and isinstance(timeB,list):
if timeA == timeB:
date = [1970,1,1]
date[:len(timeA)] = timeA
dto = datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc)
if len(timeA) == 3:
return dto.strftime("%d. %b %Y")
if len(timeA) == 2:
return dto.strftime("%B %Y")
if len(timeA) == 1:
return dto.strftime("%Y")
from database import getTimestamps
(timeA, timeB) = getTimestamps(since=timeA, to=timeB)
return getTimeDesc(timeA) + " to " + getTimeDesc(timeB)
#def getRangeDesc(since=None,to=None,inclusiveB=True):
# # string to list
# if isinstance(timeA,str): timeA = timeA.split("/")
# if isinstance(timeB,str): timeB = timeB.split("/")
#
# # if lists, we have it potentially much easier:
# if isinstance(timeA,list) and isinstance(timeB,list):
# if timeA == timeB:
# date = [1970,1,1]
# date[:len(timeA)] = timeA
# dto = datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc)
# if len(timeA) == 3:
# return dto.strftime("%d. %b %Y")
# if len(timeA) == 2:
# return dto.strftime("%B %Y")
# if len(timeA) == 1:
# return dto.strftime("%Y")
#
#
#
# (timeA, timeB) = getTimestamps(since=timeA, to=timeB)
#
#
# return getTimeDesc(timeA) + " to " + getTimeDesc(timeB)
@ -191,10 +191,10 @@ def pickKeys(d,*keys):
return finald
# removes all duplicate keys, except artists when a title is specified
def clean(d):
if isinstance(d,dict):
return
else:
for k in d:
if (k != "artist") or "title" not in d:
d[k] = d.pop(k)
#def clean(d):
# if isinstance(d,dict):
# return
# else:
# for k in d:
# if (k != "artist") or "title" not in d:
# d[k] = d.pop(k)

View File

@ -1,6 +1,7 @@
from htmlgenerators import *
import database
from utilities import getArtistsInfo, getTracksInfo
from malojatime import *
import urllib
@ -26,7 +27,7 @@ def module_scrobblelist(max_=None,pictures=False,shortTimeDesc=False,**kwargs):
#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]
representative = scrobbles[0] if scrobbles is not [] else None
representative = scrobbles[0] if len(scrobbles) is not 0 else None
# build list
i = 0
@ -34,7 +35,7 @@ def module_scrobblelist(max_=None,pictures=False,shortTimeDesc=False,**kwargs):
for s in scrobbles:
html += "<tr>"
html += "<td class='time'>" + getTimeDesc(s["time"],short=shortTimeDesc) + "</td>"
html += "<td class='time'>" + time_desc(s["time"],short=shortTimeDesc) + "</td>"
if pictures:
html += """<td class='icon'><div style="background-image:url('""" + scrobbleimages[i] + """')"></div></td>"""
html += "<td class='artists'>" + artistLinks(s["artists"]) + "</td>"
@ -58,6 +59,13 @@ def module_pulse(max_=None,**kwargs):
ranges = database.get_pulse(**kwargs_time,**kwargs_filter)
if max_ is not None: ranges = ranges[:max_]
# 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)
@ -67,7 +75,7 @@ def module_pulse(max_=None,**kwargs):
fromstr = "/".join([str(e) for e in t["from"]])
tostr = "/".join([str(e) for e in t["to"]])
html += "<tr>"
html += "<td>" + getRangeDesc(t["from"],t["to"]) + "</td>"
html += "<td>" + range_desc(t["from"],t["to"],short=True) + "</td>"
html += "<td class='amount'>" + scrobblesLink({"since":fromstr,"to":tostr},amount=t["scrobbles"],**kwargs_filter) + "</td>"
html += "<td class='bar'>" + scrobblesLink({"since":fromstr,"to":tostr},percent=t["scrobbles"]*100/maxbar,**kwargs_filter) + "</td>"
html += "</tr>"

View File

@ -1,7 +1,16 @@
import datetime
from calendar import monthrange
from os.path import commonprefix
FIRST_SCROBBLE = int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp())
def register_scrobbletime(timestamp):
global FIRST_SCROBBLE
if timestamp < FIRST_SCROBBLE:
FIRST_SCROBBLE = int(timestamp)
# This is meant to be a time object that is aware of its own precision
# now I know what you're saying
# "This is total overengineering, Jimmy!"
@ -10,161 +19,351 @@ from calendar import monthrange
# and you are absolutely correct
# but my name isn't Jimmy
# so we're doing objects
class Time():
precision = 0
# 0 unused, no information at all, embrace eternity
# 1 year
# 2 month
# 3 day
# 4 specified by exact timestamp
def __init__(self,*time):
# time can be a int (timestamp), list or string (/-delimited list)
if len(time) == 1:
time = time[0] #otherwise we will already have a tuple and we can deal with that
if isinstance(time,int) and time < 10000: time = [time] # if we have a low number, it's not a timestamp, but a year
if isinstance(time,str):
time = time.split("/")
if isinstance(time,list) or isinstance(time,tuple):
time = [int(x) for x in time][:3]
self.precision = len(time)
if len(time) > 0: self.YEAR = time[0]
if len(time) > 1: self.MONTH = time[1]
if len(time) > 2: self.DAY = time[2]
elif isinstance(time,int):
self.precision = 4
self.TIMESTAMP = time
dt = datetime.datetime.utcfromtimestamp(time)
self.YEAR, self.MONTH, self.DAY = dt.year, dt.month, dt.day
#class Time():
#
# precision = 0
# # 0 unused, no information at all, embrace eternity
# # 1 year
# # 2 month
# # 3 day
# # 4 specified by exact timestamp
#
# def __init__(self,*time):
# # time can be a int (timestamp), list or string (/-delimited list)
#
# if len(time) == 1:
# time = time[0] #otherwise we will already have a tuple and we can deal with that
# if isinstance(time,int) and time < 10000: time = [time] # if we have a low number, it's not a timestamp, but a year
#
#
# if isinstance(time,str):
# time = time.split("/")
# if isinstance(time,list) or isinstance(time,tuple):
# time = [int(x) for x in time][:3]
# self.precision = len(time)
# if len(time) > 0: self.YEAR = time[0]
# if len(time) > 1: self.MONTH = time[1]
# if len(time) > 2: self.DAY = time[2]
# elif isinstance(time,int):
# self.precision = 4
# self.TIMESTAMP = time
# dt = datetime.datetime.utcfromtimestamp(time)
# self.YEAR, self.MONTH, self.DAY = dt.year, dt.month, dt.day
#
#
# def _array(self):
# if self.precision == 4:
# timeobject = datetime.datetime.utcfromtimestamp(self.TIMESTAMP)
# return [timeobject.year,timeobject.month,timeobject.day]
# if self.precision == 3: return [self.YEAR,self.MONTH,self.DAY]
# if self.precision == 2: return [self.YEAR,self.MONTH]
# if self.precision == 1: return [self.YEAR]
#
#
# def get(self):
# if self.precision == 4: return self.TIMESTAMP
# if self.precision == 3: return [self.YEAR,self.MONTH,self.DAY]
# if self.precision == 2: return [self.YEAR,self.MONTH]
# if self.precision == 1: return [self.YEAR]
#
# def getStartTimestamp(self):
# if self.precision == 4: return self.TIMESTAMP
# else:
# YEAR = self.YEAR if self.precision > 0 else 1970
# MONTH = self.MONTH if self.precision > 1 else 1
# DAY = self.DAY if self.precision > 2 else 1
# return int(datetime.datetime(YEAR,MONTH,DAY,tzinfo=datetime.timezone.utc).timestamp())
#
# def getEndTimestamp(self):
# if self.precision == 4: return self.TIMESTAMP
# else: return self.getNext().getStartTimestamp()-1
#
# # get next time of the same precision, e.g. next month if month of this time was defined (even if it's 1 or 12)
# def getNext(self,obj=True):
# if self.precision == 4: result = self.TIMESTAMP + 1
# else: result = _getNext(self._array())
#
# if obj: return Time(result)
# else: return result
#
#
# def pad(self,precision=3):
# arrayA, arrayB = self._array(), self._array()
# if self.precision < min(2,precision):
# arrayA.append(1)
# arrayB.append(12)
# if self.precision+1 < min(3,precision):
# arrayA.append(1)
# arrayB.append(monthrange(*arrayB)[1])
#
# return (arrayA,arrayB)
#
# def describe(self,short=False):
# if self.precision == 4:
# if short:
# now = datetime.datetime.now(tz=datetime.timezone.utc)
# difference = int(now.timestamp() - self.TIMESTAMP)
#
# 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(self.TIMESTAMP)
# 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(self.TIMESTAMP)
# return tim.strftime("%d. %b %Y %I:%M %p")
#
# else:
# YEAR = self.YEAR if self.precision > 0 else 2022
# MONTH = self.MONTH if self.precision > 1 else 5 #else numbers dont matter, just needed to create the datetime object
# DAY = self.DAY if self.precision > 2 else 4
# timeobject = datetime.datetime(YEAR,MONTH,DAY,tzinfo=datetime.timezone.utc)
# if self.precision == 3: return timeobject.strftime("%d. %B %Y")
# if self.precision == 2: return timeobject.strftime("%B %Y")
# if self.precision == 1: return timeobject.strftime("%Y")
# if self.precision == 0: return "Embrace Eternity"
def _array(self):
if self.precision == 4:
timeobject = datetime.datetime.utcfromtimestamp(self.TIMESTAMP)
return [timeobject.year,timeobject.month,timeobject.day]
if self.precision == 3: return [self.YEAR,self.MONTH,self.DAY]
if self.precision == 2: return [self.YEAR,self.MONTH]
if self.precision == 1: return [self.YEAR]
#def getRange(timeA,timeB):
# return (timeA.getStartTimestamp(),timeB.getEndTimestamp())
#
#def getRangeDesc(timeA,timeB):
# aA, aB = timeA.get(), timeB.get()
# if len(aA) != len(aB):
# prec = max(len(aA),len(aB))
# aA, aB = timeA.pad(prec)[0], timeB.pad(prec)[1]
# if aA == aB:
# return Time(aA).describe()
# if aA[:-1] == aB[:-1]:
# return " ".join(Time(aA).describe().split(" ")[:-1]) + " to " + Time(aB).describe() #what
#
# alright forget everything I've just told you
# so how bout this:
# we completely ignore times
# all singular times (only used for scrobbles) are only ever expressed in timestamps anyway and remain simple ints
# ranges specified in any kind of list are completely separated from them
# even if you specify the pulse
# holy feck this is so much better
# converts strings and stuff to lists
def time_fix(t):
if isinstance(t, str) and t.lower() == "today":
tod = datetime.datetime.utcnow()
t = [tod.year,tod.month,tod.day]
if isinstance(t, str) and t.lower() == "month":
tod = datetime.datetime.utcnow()
t = [tod.year,tod.month]
if isinstance(t, str) and t.lower() == "year":
tod = datetime.datetime.utcnow()
t = [tod.year]
if isinstance(t,str): t = t.split("/")
#if isinstance(t,tuple): t = list(t)
t = [int(p) for p in t]
return t[:3]
# makes times the same precision level
def time_pad(f,t):
f,t = time_fix(f), time_fix(t)
while len(f) < len(t):
if len(f) == 1: f.append(1)
elif len(f) == 2: f.append(1)
while len(f) > len(t):
if len(t) == 1: t.append(12)
elif len(t) == 2: t.append(monthrange(*t)[1])
return (f,t)
def get(self):
if self.precision == 4: return self.TIMESTAMP
if self.precision == 3: return [self.YEAR,self.MONTH,self.DAY]
if self.precision == 2: return [self.YEAR,self.MONTH]
if self.precision == 1: return [self.YEAR]
def getStartTimestamp(self):
if self.precision == 4: return self.TIMESTAMP
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:
YEAR = self.YEAR if self.precision > 0 else 1970
MONTH = self.MONTH if self.precision > 1 else 1
DAY = self.DAY if self.precision > 2 else 1
return int(datetime.datetime(YEAR,MONTH,DAY,tzinfo=datetime.timezone.utc).timestamp())
timeobject = datetime.datetime.utcfromtimestamp(t)
return timeobject.strftime("%d. %b %Y %I:%M %p")
else:
t = time_fix(t)
date = [1970,1,1]
date[:len(t)] = t
timeobject = datetime.datetime(date[0],date[1],date[2],tzinfo=datetime.timezone.utc)
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 getEndTimestamp(self):
if self.precision == 4: return self.TIMESTAMP
else: return self.getNext().getStartTimestamp()-1
# get next time of the same precision, e.g. next month if month of this time was defined (even if it's 1 or 12)
def getNext(self,obj=True):
if self.precision == 4: result = self.TIMESTAMP + 1
else: result = _getNext(self._array())
def range_desc(since=None,to=None,within=None,short=False):
if obj: return Time(result)
else: return result
if within is not None:
since = within
to = within
if since is None:
sincestr = ""
if to is None:
tostr = ""
def pad(self,precision=3):
arrayA, arrayB = self._array(), self._array()
if self.precision < min(2,precision):
arrayA.append(1)
arrayB.append(12)
if self.precision+1 < min(3,precision):
arrayA.append(1)
arrayB.append(monthrange(*arrayB)[1])
return (arrayA,arrayB)
def describe(self,short=False):
if self.precision == 4:
if short:
now = datetime.datetime.now(tz=datetime.timezone.utc)
difference = int(now.timestamp() - self.TIMESTAMP)
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(self.TIMESTAMP)
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")
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)
tostr = ""
else:
timeobject = datetime.datetime.utcfromtimestamp(self.TIMESTAMP)
return tim.strftime("%d. %b %Y %I:%M %p")
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:
YEAR = self.YEAR if self.precision > 0 else 2022
MONTH = self.MONTH if self.precision > 1 else 5 #else numbers dont matter, just needed to create the datetime object
DAY = self.DAY if self.precision > 2 else 4
timeobject = datetime.datetime(YEAR,MONTH,DAY,tzinfo=datetime.timezone.utc)
if self.precision == 3: return timeobject.strftime("%d. %B %Y")
if self.precision == 2: return timeobject.strftime("%B %Y")
if self.precision == 1: return timeobject.strftime("%Y")
if self.precision == 0: return "Embrace Eternity"
if since is not None:
sincestr = "since " + time_desc(since)
shortsincestr = sincestr
if to is not None:
tostr = "up until " + time_desc(to)
def getRange(timeA,timeB):
return (timeA.getStartTimestamp(),timeB.getEndTimestamp())
def getRangeDesc(timeA,timeB):
aA, aB = timeA.get(), timeB.get()
if len(aA) != len(aB):
prec = max(len(aA),len(aB))
aA, aB = timeA.pad(prec)[0], timeB.pad(prec)[1]
if aA == aB:
return Time(aA).describe()
if aA[:-1] == aB[:-1]:
return " ".join(Time(aA).describe().split(" ")[:-1]) + " to " + Time(aB).describe() #what
if short: return shortsincestr + " " + tostr
else: return sincestr + " " + tostr
def _getNext(time,unit="auto",step=1):
result = time[:]
if unit == "auto":
# see how long the list is, increment by the last specified unit
unit = [None,"year","month","day"][len(time)]
def time_stamps(since=None,to=None,within=None):
if unit == "year":
result[0] += step
return result
elif unit == "month":
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 getNext(time,"day",step * 7)
from database import getNext
if within is not None:
since = within
to = within
if (since==None): stamp1 = FIRST_SCROBBLE
else:
since = time_fix(since)
date = [1970,1,1]
date[:len(since)] = since
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:
to = time_fix(to)
to = getNext(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)
def delimit_desc(step,stepn,trail):
txt = ""
if stepn is not 1: txt += _num(stepn) + "-"
txt += {"year":"Yearly","month":"Monthly","day":"Daily"}[step.lower()]
#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
return txt
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 _getNext(time,unit="auto",step=1):
# result = time[:]
# if unit == "auto":
# # see how long the list is, increment by the last specified unit
# unit = [None,"year","month","day"][len(time)]
#
# if unit == "year":
# result[0] += step
# return result
# elif unit == "month":
# 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 getNext(time,"day",step * 7)
#

View File

@ -4,7 +4,7 @@ import database
def instructions(keys):
from utilities import getArtistInfo
from htmlgenerators import clean, artistLink, artistLinks, KeySplit
from htmlgenerators import artistLink, artistLinks, KeySplit
from htmlmodules import module_pulse, module_trackcharts
filterkeys, _, _, _ = KeySplit(keys,forceArtist=True)

View File

@ -3,7 +3,7 @@
<html>
<head>
<meta charset="UTF-8" />
<title>Maloja - Pulse</title>
<title>Maloja - KEY_PULSEDETAILS Pulse</title>
<link rel="stylesheet" href="maloja.css" />
</head>
@ -14,7 +14,7 @@
<div style="background-image:url('KEY_IMAGEURL')"></div>
</td>
<td class="text">
<h1>Pulse</h1><br/>
<h1>KEY_PULSEDETAILS Pulse</h1><br/>
<span>KEY_LIMITS</span>
<!--<p class="stats">KEY_SCROBBLES Scrobbles</p>-->

View File

@ -4,8 +4,9 @@ import database
def instructions(keys):
from utilities import getArtistInfo, getTrackInfo
from htmlgenerators import getTimeDesc, artistLink, artistLinks, trackLink, scrobblesLink, keysToUrl, getRangeDesc, KeySplit
from htmlmodules import module_pulse
from htmlgenerators import artistLink, artistLinks, trackLink, scrobblesLink, keysToUrl, KeySplit
from htmlmodules import module_pulse
from malojatime import range_desc, delimit_desc
filterkeys, timekeys, delimitkeys, _ = KeySplit(keys)
@ -26,6 +27,10 @@ def instructions(keys):
moreartists = data["associated"]
if moreartists != []:
limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>"
limitstring += " " + range_desc(**timekeys)
delimitstring = delimit_desc(**delimitkeys)
# get image
@ -42,7 +47,7 @@ def instructions(keys):
html_pulse = module_pulse(**filterkeys,**timekeys,**delimitkeys)
replace = {"KEY_PULSE_TABLE":html_pulse,"KEY_IMAGEURL":imgurl,"KEY_LIMITS":limitstring}
replace = {"KEY_PULSE_TABLE":html_pulse,"KEY_IMAGEURL":imgurl,"KEY_LIMITS":limitstring,"KEY_PULSEDETAILS":delimitstring}
return (replace,pushresources)

View File

@ -5,7 +5,8 @@ import database
def instructions(keys):
from utilities import getArtistInfo, getTrackInfo
from htmlgenerators import artistLink, artistLinks, trackLink, KeySplit
from htmlmodules import module_scrobblelist
from htmlmodules import module_scrobblelist
from malojatime import range_desc
filterkeys, timekeys, _, amountkeys = KeySplit(keys)
@ -24,6 +25,7 @@ def instructions(keys):
if moreartists != []:
limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>"
limitstring += " " + range_desc(**timekeys)
html, amount, rep = module_scrobblelist(**filterkeys,**timekeys,**amountkeys)

View File

@ -7,7 +7,7 @@ from htmlmodules import module_scrobblelist, module_pulse
def instructions(keys):
from utilities import getArtistsInfo, getTracksInfo
from htmlgenerators import artistLink, artistLinks, trackLink, scrobblesArtistLink, scrobblesLink, keysToUrl, pickKeys, clean, getTimeDesc, getRangeDesc
from htmlgenerators import artistLink, trackLink
max_show = 14
posrange = ["#" + str(i) for i in range(1,max_show+1)]

View File

@ -3,7 +3,7 @@
<html>
<head>
<meta charset="UTF-8" />
<title>Maloja - Top Artists in KEY_RANGE</title>
<title>Maloja - Top Artists KEY_RANGE</title>
<link rel="stylesheet" href="maloja.css" />
</head>
@ -15,7 +15,7 @@
</td>
<td class="text">
<h1>Top Artists</h1><br/>
<span>in KEY_RANGE</span>
<span>KEY_RANGE</span>
<!--<p class="stats">KEY_SCROBBLES Scrobbles</p>-->
</td>

View File

@ -5,10 +5,15 @@ def instructions(keys):
from utilities import getArtistInfo
from htmlgenerators import KeySplit
from htmlmodules import module_artistcharts
from malojatime import range_desc
_, timekeys, _, amountkeys = KeySplit(keys)
limitstring = range_desc(**timekeys)
html_charts, rep = module_artistcharts(**amountkeys,**timekeys)
if rep is not None:
@ -19,6 +24,6 @@ def instructions(keys):
pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else []
replace = {"KEY_TOPARTIST_IMAGEURL":imgurl,"KEY_ARTISTLIST":html_charts}
replace = {"KEY_TOPARTIST_IMAGEURL":imgurl,"KEY_ARTISTLIST":html_charts,"KEY_RANGE":limitstring}
return (replace,pushresources)

View File

@ -4,7 +4,8 @@ import urllib
def instructions(keys):
from utilities import getArtistInfo, getTrackInfo
from htmlgenerators import artistLink, KeySplit
from htmlmodules import module_trackcharts
from htmlmodules import module_trackcharts
from malojatime import range_desc
filterkeys, timekeys, _, amountkeys = KeySplit(keys)
@ -22,6 +23,8 @@ def instructions(keys):
imgurl = getTrackInfo(rep["artists"],rep["title"]).get("image")
else:
imgurl = ""
limitstring += " " + range_desc(**timekeys)
pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else []