mirror of
				https://github.com/krateng/maloja.git
				synced 2023-08-10 21:12:55 +03:00 
			
		
		
		
	Complete rework of time descriptors, Part II
This commit is contained in:
		
							
								
								
									
										29
									
								
								database.py
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								database.py
									
									
									
									
									
								
							| @@ -15,6 +15,7 @@ import datetime | ||||
| import sys | ||||
| import unicodedata | ||||
| import json | ||||
| import pickle | ||||
| from collections import namedtuple | ||||
| from threading import Lock | ||||
| # url handling | ||||
| @@ -384,9 +385,9 @@ def get_pulse(**keys): | ||||
| 	rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","step","stepn","trail"]}) | ||||
| 	results = [] | ||||
|  | ||||
| 	for (a,b) in rngs: | ||||
| 		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({"from":a,"to":b,"scrobbles":res}) | ||||
| 	for rng in rngs: | ||||
| 		res = len(db_query(timerange=rng,**{k:keys[k] for k in keys if k in ["artists","artist","track","title","associated"]})) | ||||
| 		results.append({"range":rng,"scrobbles":res}) | ||||
|  | ||||
| 	return results | ||||
|  | ||||
| @@ -408,22 +409,22 @@ def get_performance(**keys): | ||||
| 	rngs = ranges(**{k:keys[k] for k in keys if k in ["since","to","within","step","stepn","trail"]}) | ||||
| 	results = [] | ||||
|  | ||||
| 	for (a,b) in rngs: | ||||
| 	for rng in rngs: | ||||
| 		if "track" in keys: | ||||
| 			charts = get_charts_tracks(since=a,to=b) | ||||
| 			charts = get_charts_tracks(timerange=rng) | ||||
| 			rank = None | ||||
| 			for c in charts: | ||||
| 				if c["track"] == keys["track"]: | ||||
| 					rank = c["rank"] | ||||
| 					break | ||||
| 		elif "artist" in keys: | ||||
| 			charts = get_charts_artists(since=a,to=b) | ||||
| 			charts = get_charts_artists(timerange=rng) | ||||
| 			rank = None | ||||
| 			for c in charts: | ||||
| 				if c["artist"] == keys["artist"]: | ||||
| 					rank = c["rank"] | ||||
| 					break | ||||
| 		results.append({"from":a,"to":b,"rank":rank}) | ||||
| 		results.append({"range":rng,"rank":rank}) | ||||
|  | ||||
| 	return results | ||||
|  | ||||
| @@ -900,7 +901,7 @@ cacheday = (0,0,0) | ||||
| def db_query(**kwargs): | ||||
| 	check_cache_age() | ||||
| 	global cache_query | ||||
| 	key = json.dumps(kwargs) | ||||
| 	key = pickle.dumps(kwargs) | ||||
| 	if key in cache_query: return copy.copy(cache_query[key]) | ||||
|  | ||||
| 	result = db_query_full(**kwargs) | ||||
| @@ -911,7 +912,7 @@ cache_aggregate = {} | ||||
| def db_aggregate(**kwargs): | ||||
| 	check_cache_age() | ||||
| 	global cache_aggregate | ||||
| 	key = json.dumps(kwargs) | ||||
| 	key = pickle.dumps(kwargs) | ||||
| 	if key in cache_aggregate: return copy.copy(cache_aggregate[key]) | ||||
|  | ||||
| 	result = db_aggregate_full(**kwargs) | ||||
| @@ -942,9 +943,9 @@ def check_cache_age(): | ||||
|  | ||||
|  | ||||
| # 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 | ||||
| 	# if a title is specified, we assume that a specific track (with the exact artist combination) is requested | ||||
| @@ -993,8 +994,10 @@ def db_query_full(artist=None,artists=None,title=None,track=None,since=None,to=N | ||||
|  | ||||
|  | ||||
| # Queries that... well... aggregate | ||||
| def db_aggregate_full(by=None,since=None,to=None,within=None,artist=None): | ||||
| 	(since, to) = time_stamps(since,to,within) | ||||
| def db_aggregate_full(by=None,since=None,to=None,within=None,timerange=None,artist=None): | ||||
|  | ||||
|  | ||||
| 	(since, to) = time_stamps(since=since,to=to,within=within,range=timerange) | ||||
|  | ||||
| 	if isinstance(artist, str): | ||||
| 		artist = ARTISTS.index(artist) | ||||
|   | ||||
| @@ -42,7 +42,7 @@ def module_scrobblelist(max_=None,pictures=False,shortTimeDesc=False,earlystop=F | ||||
| 	for s in scrobbles: | ||||
|  | ||||
| 		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: | ||||
| 			img = scrobbleimages[i] | ||||
| 		else: img = None | ||||
| @@ -81,12 +81,11 @@ def module_pulse(max_=None,**kwargs): | ||||
| 	#build list | ||||
| 	html = "<table class='list'>" | ||||
| 	for t in ranges: | ||||
| 		fromstr = "/".join([str(e) for e in t["from"]]) | ||||
| 		tostr = "/".join([str(e) for e in t["to"]]) | ||||
| 		range = t["range"] | ||||
| 		html += "<tr>" | ||||
| 		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 += "<td>" + range.desc() + "</td>" | ||||
| 		html += "<td class='amount'>" + scrobblesLink({"since":range.fromstr(),"to":range.tostr()},amount=t["scrobbles"],**kwargs_filter) + "</td>" | ||||
| 		html += "<td class='bar'>" + scrobblesLink({"since":range.fromstr(),"to":range.tostr()},percent=t["scrobbles"]*100/maxbar,**kwargs_filter) + "</td>" | ||||
| 		html += "</tr>" | ||||
| 	html += "</table>" | ||||
|  | ||||
| @@ -117,13 +116,12 @@ def module_performance(max_=None,**kwargs): | ||||
| 	#build list | ||||
| 	html = "<table class='list'>" | ||||
| 	for t in ranges: | ||||
| 		fromstr = "/".join([str(e) for e in t["from"]]) | ||||
| 		tostr = "/".join([str(e) for e in t["to"]]) | ||||
| 		range = t["range"] | ||||
| 		html += "<tr>" | ||||
| 		html += "<td>" + range_desc(t["from"],t["to"],short=True) + "</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 | ||||
| 		html += "<td class='chart'>" + rankLink({"since":fromstr,"to":tostr},percent=prct,**kwargs_filter,medal=t["rank"]) + "</td>" | ||||
| 		html += "<td class='chart'>" + rankLink({"since":range.fromstr(),"to":range.tostr()},percent=prct,**kwargs_filter,medal=t["rank"]) + "</td>" | ||||
| 		html += "</tr>" | ||||
| 	html += "</table>" | ||||
|  | ||||
| @@ -288,13 +286,13 @@ def module_toptracks(pictures=True,**kwargs): | ||||
|  | ||||
| 		#fromstr = "/".join([str(p) for p in e["from"]]) | ||||
| 		#tostr = "/".join([str(p) for p in e["to"]]) | ||||
| 		limits = pickKeys(e,"since","to") | ||||
| 		range = e["range"] | ||||
|  | ||||
| 		i += 1 | ||||
| 		html += "<tr>" | ||||
|  | ||||
|  | ||||
| 		html += "<td>" + range_desc(e["since"],e["to"],short=True) + "</td>" | ||||
| 		html += "<td>" + range.desc() + "</td>" | ||||
| 		if e["track"] is None: | ||||
| 			if pictures: | ||||
| 				html += "<td><div></div></td>" | ||||
| @@ -307,8 +305,8 @@ def module_toptracks(pictures=True,**kwargs): | ||||
| 				img = getTrackImage(e["track"]["artists"],e["track"]["title"],fast=True) | ||||
| 			else: img = None | ||||
| 			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='bar'>" + scrobblesTrackLink(e["track"],internal_to_uri(limits),percent=e["scrobbles"]*100/maxbar) + "</td>" | ||||
| 			html += "<td class='amount'>" + scrobblesTrackLink(e["track"],{"since":range.fromstr(),"to":range.tostr()},amount=e["scrobbles"]) + "</td>" | ||||
| 			html += "<td class='bar'>" + scrobblesTrackLink(e["track"],{"since":range.fromstr(),"to":range.tostr()},percent=e["scrobbles"]*100/maxbar) + "</td>" | ||||
| 		html += "</tr>" | ||||
| 		prev = e | ||||
| 	html += "</table>" | ||||
| @@ -344,13 +342,13 @@ def module_topartists(pictures=True,**kwargs): | ||||
|  | ||||
| 		#fromstr = "/".join([str(p) for p in e["from"]]) | ||||
| 		#tostr = "/".join([str(p) for p in e["to"]]) | ||||
| 		limits = pickKeys(e,"since","to") | ||||
| 		range = e["range"] | ||||
|  | ||||
| 		i += 1 | ||||
| 		html += "<tr>" | ||||
|  | ||||
|  | ||||
| 		html += "<td>" + range_desc(e["since"],e["to"],short=True) + "</td>" | ||||
| 		html += "<td>" + range.desc() + "</td>" | ||||
|  | ||||
| 		if e["artist"] is None: | ||||
| 			if pictures: | ||||
| @@ -363,8 +361,8 @@ def module_topartists(pictures=True,**kwargs): | ||||
| 				img = getArtistImage(e["artist"],fast=True) | ||||
| 			else: img = None | ||||
| 			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='bar'>" + scrobblesArtistLink(e["artist"],internal_to_uri(limits),percent=e["scrobbles"]*100/maxbar,associated=True) + "</td>" | ||||
| 			html += "<td class='amount'>" + scrobblesArtistLink(e["artist"],{"since":range.fromstr(),"to":range.tostr()},amount=e["scrobbles"],associated=True) + "</td>" | ||||
| 			html += "<td class='bar'>" + scrobblesArtistLink(e["artist"],{"since":range.fromstr(),"to":range.tostr()},percent=e["scrobbles"]*100/maxbar,associated=True) + "</td>" | ||||
| 		html += "</tr>" | ||||
| 		prev = e | ||||
| 	html += "</table>" | ||||
|   | ||||
							
								
								
									
										363
									
								
								malojatime.py
									
									
									
									
									
								
							
							
						
						
									
										363
									
								
								malojatime.py
									
									
									
									
									
								
							| @@ -55,7 +55,30 @@ date = expandeddate | ||||
|  | ||||
| # only for ranges, timestamps are separate | ||||
|  | ||||
| class MTime: | ||||
| class MRangeDescriptor: | ||||
|  | ||||
| 	def __eq__(self,other): | ||||
| 		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) | ||||
|  | ||||
|  | ||||
| # 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): | ||||
| @@ -72,9 +95,13 @@ class MTime: | ||||
|  | ||||
| 	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 uri(self): | ||||
| 		return "in=" + str(self) | ||||
| 	def urikeys(self): | ||||
| 		return {"in":str(self)} | ||||
|  | ||||
| 	def desc(self,prefix=False): | ||||
| 		if self.precision == 3: | ||||
| @@ -140,9 +167,30 @@ class MTime: | ||||
| 		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 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) | ||||
|  | ||||
|  | ||||
| class MTimeWeek: | ||||
|  | ||||
| # 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 | ||||
| @@ -158,9 +206,13 @@ class MTimeWeek: | ||||
|  | ||||
| 	def __str__(self): | ||||
| 		return str(self.year) + "/W" + str(self.week) | ||||
| 	def fromstr(self): | ||||
| 		return str(self) | ||||
| 	def tostr(self): | ||||
| 		return str(self) | ||||
|  | ||||
| 	def uri(self): | ||||
| 		return "in=" + str(self) | ||||
| 	def urikeys(self): | ||||
| 		return {"in":str(self)} | ||||
|  | ||||
| 	def desc(self,prefix=False): | ||||
| 		if prefix: | ||||
| @@ -195,8 +247,15 @@ class MTimeWeek: | ||||
| 		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): | ||||
| 		try: | ||||
| 			return MTimeWeek(self.year,self.week + step) | ||||
| 		except: | ||||
| 			pass | ||||
| 			# TODO | ||||
|  | ||||
| class MRange: | ||||
| # 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) | ||||
| @@ -205,12 +264,17 @@ class MRange: | ||||
|  | ||||
| 	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 uri(self): | ||||
| 		keys = [] | ||||
| 		if self.since is not None: keys.append("since=" + uri(self.since)) | ||||
| 		if self.to is not None: keys.append("&to=" + uri(self.to)) | ||||
| 		return "&".join(keys) | ||||
|  | ||||
| 	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: | ||||
| @@ -239,9 +303,25 @@ class MRange: | ||||
| 		return self.to.last_day() | ||||
|  | ||||
| 	def first_stamp(self): | ||||
| 		return self.since.first_stamp() | ||||
| 		if self.since is None: return FIRST_SCROBBLE | ||||
| 		else: return self.since.first_stamp() | ||||
| 	def last_stamp(self): | ||||
| 		return self.to.last_stamp() | ||||
| 		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): | ||||
| 		# 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 | ||||
|  | ||||
| @@ -258,7 +338,8 @@ def time_str(t): | ||||
|  | ||||
| # converts strings and stuff to objects | ||||
| def time_fix(t): | ||||
|  | ||||
| 	if t is None: return None | ||||
| 	if isinstance(t,MRangeDescriptor): return t | ||||
|  | ||||
| 	if isinstance(t, str): | ||||
| 		tod = datetime.datetime.utcnow() | ||||
| @@ -294,13 +375,28 @@ def time_fix(t): | ||||
|  | ||||
| 	if isinstance(t[1],str) and t[1].startswith("W"): | ||||
| 		try: | ||||
| 			year = int(t[0]) | ||||
| 			weeknum = int(t[1][1:]) | ||||
| 			return MTimeWeek(year=t[0],week=t[1]) | ||||
| 			return MTimeWeek(year=year,week=weeknum) | ||||
| 		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) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # makes times the same precision level | ||||
| @@ -325,6 +421,8 @@ def time_pad(f,t,full=False): | ||||
| 	return f,t | ||||
|  | ||||
|  | ||||
| def range_desc(f,t,short=False): | ||||
| 	return MRange(time_fix(f),time_fix(t)).desc() | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -363,33 +461,34 @@ def timestamp_desc(t,short=False): | ||||
|  | ||||
|  | ||||
|  | ||||
| def time_stamps(since=None,to=None,within=None): | ||||
| def time_stamps(since=None,to=None,within=None,range=None): | ||||
|  | ||||
|  | ||||
| 	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 = _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) | ||||
| 	if range is None: range = get_range_object(since=since,to=to,within=within) | ||||
| 	return range.first_stamp(),range.last_stamp() | ||||
| 	#print(range.desc()) | ||||
| #	if (since==None): stamp1 = FIRST_SCROBBLE | ||||
| #	else: stamp1 = range.first_stamp() | ||||
| #	if (to==None): stamp2 = int(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).timestamp()) | ||||
| #	else: stamp2 = range.last_stamp() | ||||
| #	return stamp1,stamp2 | ||||
| #	if (since==None): stamp1 = FIRST_SCROBBLE | ||||
| #	else: | ||||
| #		stamp1 = since1 | ||||
| #		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 = _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) | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -406,93 +505,115 @@ def delimit_desc(step="month",stepn=1,trail=1): | ||||
|  | ||||
|  | ||||
|  | ||||
| def ranges(since=None,to=None,within=None,step="month",stepn=1,trail=1,max_=None): | ||||
| 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) | ||||
|  | ||||
| 	(firstincluded,lastincluded) = time_stamps(since=since,to=to,within=within) | ||||
| 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) | ||||
|  | ||||
| 	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 | ||||
|  | ||||
| def ranges(since=None,to=None,within=None,superrange=None,step="month",stepn=1,trail=1,max_=None): | ||||
|  | ||||
| 	(firstincluded,lastincluded) = time_stamps(since=since,to=to,within=within,range=superrange) | ||||
|  | ||||
| 	d_start = from_timestamp(firstincluded,step) | ||||
| 	d_start = d_start.next(stepn) | ||||
| 	d_start = d_start.next(stepn*trail*-1) | ||||
| 	first_range = MRange(d_start,d_start.next(stepn*trail-1)) | ||||
|  | ||||
| 	i = 0 | ||||
| 	d_current = d_start | ||||
| 	while not _is_past(d_current,d_end) and (max_ is None or i < max_): | ||||
| 		d_current_end = _get_end(d_current,step,stepn * trail) | ||||
| 		yield (d_current,d_current_end) | ||||
| 		d_current = _get_next(d_current,step,stepn) | ||||
| 	current = d_start | ||||
| 	while current.first_stamp() <= lastincluded and (max_ is None or i < max_): | ||||
| 		current_end = current.next(stepn*trail-1) | ||||
| 		yield MRange(current,current_end) | ||||
| 		current = current.next(stepn) | ||||
| 		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): | ||||
| 	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) | ||||
|  | ||||
| #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 | ||||
| def _get_end(time,unit="auto",step=1): | ||||
| 	if step == 1: | ||||
| 		if unit == "auto": return time[:] | ||||
| 		if unit == "year" and len(time) == 1: return time[:] | ||||
| 		if unit == "month" and len(time) == 2: return time[:] | ||||
| 		if unit == "day" and len(time) == 3: return time[:] | ||||
| 	exc = _get_next(time,unit,step) | ||||
| 	inc = _get_next(exc,"auto",-1) | ||||
| 	return inc | ||||
| #def _get_end(time,unit="auto",step=1): | ||||
| #	if step == 1: | ||||
| #		if unit == "auto": return time[:] | ||||
| #		if unit == "year" and len(time) == 1: return time[:] | ||||
| #		if unit == "month" and len(time) == 2: return time[:] | ||||
| #		if unit == "day" and len(time) == 3: return time[:] | ||||
| #	exc = _get_next(time,unit,step) | ||||
| #	inc = _get_next(exc,"auto",-1) | ||||
| #	return inc | ||||
| # | ||||
|  | ||||
|  | ||||
|  | ||||
| def _is_past(date,limit): | ||||
| 	date_, limit_ = date[:], limit[:] | ||||
| 	while len(date_) != 3: date_.append(1) | ||||
| 	while len(limit_) != 3: limit_.append(1) | ||||
| 	if not date_[0] == limit_[0]: | ||||
| 		return date_[0] > limit_[0] | ||||
| 	if not date_[1] == limit_[1]: | ||||
| 		return date_[1] > limit_[1] | ||||
| 	return (date_[2] > limit_[2]) | ||||
| #def _is_past(date,limit): | ||||
| #	date_, limit_ = date[:], limit[:] | ||||
| #	while len(date_) != 3: date_.append(1) | ||||
| #	while len(limit_) != 3: limit_.append(1) | ||||
| #	if not date_[0] == limit_[0]: | ||||
| #		return date_[0] > limit_[0] | ||||
| #	if not date_[1] == limit_[1]: | ||||
| #		return date_[1] > limit_[1] | ||||
| #	return (date_[2] > limit_[2]) | ||||
| ## | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import urllib | ||||
| from bottle import FormsDict | ||||
| from malojatime import time_fix, time_str | ||||
| from malojatime import time_fix, time_str, get_range_object | ||||
|  | ||||
|  | ||||
| # necessary because urllib.parse.urlencode doesnt handle multidicts | ||||
| @@ -59,28 +59,39 @@ def uri_to_internal(keys,forceTrack=False,forceArtist=False): | ||||
|  | ||||
| 	# 2 | ||||
| 	resultkeys2 = {} | ||||
| 	if "since" in keys: resultkeys2["since"] = time_fix(keys.get("since")) | ||||
| 	elif "from" in keys: resultkeys2["since"] = time_fix(keys.get("from")) | ||||
| 	elif "start" in keys: resultkeys2["since"] = time_fix(keys.get("start")) | ||||
| 	# | ||||
| 	if "to" in keys: resultkeys2["to"] = time_fix(keys.get("to")) | ||||
| 	elif "until" in keys: resultkeys2["to"] = time_fix(keys.get("until")) | ||||
| 	elif "end" in keys: resultkeys2["to"] = time_fix(keys.get("end")) | ||||
| 	# | ||||
| 	if "since" in resultkeys2 and "to" in resultkeys2 and resultkeys2["since"] == resultkeys2["to"]: | ||||
| 		resultkeys2["within"] = resultkeys2["since"] | ||||
| 		del resultkeys2["since"] | ||||
| 		del resultkeys2["to"] | ||||
| 	# | ||||
| 	if "in" in keys: resultkeys2["within"] = time_fix(keys.get("in")) | ||||
| 	elif "within" in keys: resultkeys2["within"] = time_fix(keys.get("within")) | ||||
| 	elif "during" in keys: resultkeys2["within"] = time_fix(keys.get("during")) | ||||
| 	if "within" in resultkeys2: | ||||
| 		if "since" in resultkeys2: | ||||
| 			del resultkeys2["since"] | ||||
| 		if "to" in resultkeys2: | ||||
| 			del resultkeys2["to"] | ||||
|  | ||||
| #	if "since" in keys: resultkeys2["since"] = time_fix(keys.get("since")) | ||||
| #	elif "from" in keys: resultkeys2["since"] = time_fix(keys.get("from")) | ||||
| #	elif "start" in keys: resultkeys2["since"] = time_fix(keys.get("start")) | ||||
| #	# | ||||
| #	if "to" in keys: resultkeys2["to"] = time_fix(keys.get("to")) | ||||
| #	elif "until" in keys: resultkeys2["to"] = time_fix(keys.get("until")) | ||||
| #	elif "end" in keys: resultkeys2["to"] = time_fix(keys.get("end")) | ||||
| #	# | ||||
| #	if "since" in resultkeys2 and "to" in resultkeys2 and resultkeys2["since"] == resultkeys2["to"]: | ||||
| #		resultkeys2["within"] = resultkeys2["since"] | ||||
| #		del resultkeys2["since"] | ||||
| #		del resultkeys2["to"] | ||||
| #	# | ||||
| #	if "in" in keys: resultkeys2["within"] = time_fix(keys.get("in")) | ||||
| #	elif "within" in keys: resultkeys2["within"] = time_fix(keys.get("within")) | ||||
| #	elif "during" in keys: resultkeys2["within"] = time_fix(keys.get("during")) | ||||
| #	if "within" in resultkeys2: | ||||
| #		if "since" in resultkeys2: | ||||
| #			del resultkeys2["since"] | ||||
| #		if "to" in resultkeys2: | ||||
| #			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) | ||||
| 	print(resultkeys2["timerange"].desc()) | ||||
|  | ||||
| 	#3 | ||||
| 	resultkeys3 = {} | ||||
| @@ -94,6 +105,7 @@ def uri_to_internal(keys,forceTrack=False,forceArtist=False): | ||||
| 	resultkeys4 = {} | ||||
| 	if "max" in keys: resultkeys4["max_"] = int(keys["max"]) | ||||
|  | ||||
|  | ||||
| 	return resultkeys1, resultkeys2, resultkeys3, resultkeys4 | ||||
|  | ||||
| def internal_to_uri(keys): | ||||
| @@ -109,7 +121,11 @@ def internal_to_uri(keys): | ||||
| 		urikeys.append("title",keys["track"]["title"]) | ||||
|  | ||||
| 	#time | ||||
| 	if "within" in keys: | ||||
| 	if "range" in keys: | ||||
| 		keydict = keys["range"].urikeys() | ||||
| 		for k in keydict: | ||||
| 			urikeys.append(k,keydict[k]) | ||||
| 	elif "within" in keys: | ||||
| 		urikeys.append("in",time_str(keys["within"])) | ||||
| 	else: | ||||
| 		if "since" in keys: | ||||
|   | ||||
| @@ -10,7 +10,7 @@ def instructions(keys): | ||||
|  | ||||
| 	_, timekeys, _, amountkeys = uri_to_internal(keys) | ||||
|  | ||||
| 	limitstring = range_desc(**timekeys) | ||||
| 	limitstring = timekeys["timerange"].desc(prefix=True) | ||||
|  | ||||
| 	html_filterselector = module_filterselection(keys) | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ def instructions(keys): | ||||
| 	else: | ||||
| 		imgurl = "" | ||||
|  | ||||
| 	limitstring += " " + range_desc(**timekeys) | ||||
| 	limitstring += " " + timekeys["timerange"].desc(prefix=True) | ||||
|  | ||||
| 	pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else [] | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ def instructions(keys): | ||||
| 		#limitkey["artist"], limitkey["associated"] = keys.get("artist"), (keys.get("associated")!=None) | ||||
| 		limitstring += "of " + artistLink(filterkeys.get("artist")) | ||||
|  | ||||
| 	limitstring += " " + range_desc(**timekeys) | ||||
| 	limitstring += " " + timekeys["timerange"].desc(prefix=True) | ||||
|  | ||||
| 	delimitstring = delimit_desc(**delimitkeys) | ||||
|  | ||||
|   | ||||
| @@ -29,7 +29,7 @@ def instructions(keys): | ||||
| 			if moreartists != []: | ||||
| 				limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>" | ||||
|  | ||||
| 	limitstring += " " + range_desc(**timekeys) | ||||
| 	limitstring += " " + timekeys["timerange"].desc(prefix=True) | ||||
|  | ||||
| 	delimitstring = delimit_desc(**delimitkeys) | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ def instructions(keys): | ||||
| 			if moreartists != []: | ||||
| 				limitstring += " <span class='extra'>including " + artistLinks(moreartists) + "</span>" | ||||
|  | ||||
| 	limitstring += " " + range_desc(**timekeys) | ||||
| 	limitstring += " " + timekeys["timerange"].desc(prefix=True) | ||||
|  | ||||
| 	html_filterselector = module_filterselection(keys) | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ def instructions(keys): | ||||
| 	else: | ||||
| 		imgurl = "" | ||||
|  | ||||
| 	limitstring += " " + range_desc(**timekeys) | ||||
| 	limitstring += " " + timekeys["timerange"].desc(prefix=True) | ||||
|  | ||||
| 	pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else [] | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ def instructions(keys): | ||||
| 	else: | ||||
| 		imgurl = "" | ||||
|  | ||||
| 	limitstring += " " + range_desc(**timekeys) | ||||
| 	limitstring += " " + timekeys["timerange"].desc(prefix=True) | ||||
|  | ||||
| 	pushresources = [{"file":imgurl,"type":"image"}] if imgurl.startswith("/") else [] | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Krateng
					Krateng