diff --git a/database.py b/database.py index 868e56d..61f9362 100644 --- a/database.py +++ b/database.py @@ -525,8 +525,7 @@ def runserver(PORT): loadAPIkeys() - run(dbserver, host='0.0.0.0', port=PORT, server='waitress') - + run(dbserver, host='::', port=PORT, server='waitress') def build_db(): @@ -607,36 +606,32 @@ def sync(): def db_query(artists=None,title=None,track=None,since=None,to=None,associated=False): (since, to) = getTimestamps(since,to) - # 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 not, multiple artists are interpreted as requesting all scrobbles they were all involved in (but possibly other too) - # eg a track named "Awesome Song" by "TWICE", "AOA" and "f(x)" would count when we specifiy only the artists "AOA" and "f(x)", but not when we add the title (because then we'd be - # looking for that specific track with only those two artists - which could in fact exist) + # if not, duplicate artist arguments are ignored + # artists to numbers artists = set([(ARTISTS.index(a) if isinstance(a,str) else a) for a in artists]) - #for artist in artists: - # if isinstance(artist, str): - # artist = ARTISTS.index(artist) - #if isinstance(title, str): - # track = (frozenset(artists),title) - # track = TRACKS.index(track) - # if track is specified (only number works), we ignore title string + #check if track is requested via title if title!=None and track==None: track = TRACKS.index((frozenset(artists),title)) - - - if artists == []: artists = None + # if we're not looking for a track (either directly or per title artist arguments, which is converted to track above) + # we only need one artist + elif track==None and len(artists) != 0: + artist = artists.pop() + else: + artist = None + # right now we always request everything by name, maybe we don't actually need the request by number, but i'll leave it in for now if associated: - return [getScrobbleObject(s) for s in SCROBBLES if (s[0] == track or track==None) and (artists==None or artists.issubset(coa.getCreditedList(TRACKS[s[0]][0]))) and (since < s[1] < to)] + return [getScrobbleObject(s) for s in SCROBBLES if (s[0] == track or track==None) and (artist==None or artist in coa.getCreditedList(TRACKS[s[0]][0])) and (since < s[1] < to)] else: - return [getScrobbleObject(s) for s in SCROBBLES if (s[0] == track or track==None) and (artists==None or artists.issubset(TRACKS[s[0]][0])) and (since < s[1] < to)] + return [getScrobbleObject(s) for s in SCROBBLES if (s[0] == track or track==None) and (artist==None or artist in TRACKS[s[0]][0]) and (since < s[1] < to)] # pointless to check for artist when track is checked because every track has a fixed set of artists, but it's more elegant this way @@ -705,10 +700,10 @@ def db_search(query,type=None): def getTimestamps(f,t): #(f,t) = inp if isinstance(f, str) and f.lower() == "today": - tod = datetime.date.today() + tod = datetime.datetime.utcnow() f = [tod.year,tod.month,tod.day] if isinstance(t, str) and t.lower() == "today": - tod = datetime.date.today() + tod = datetime.datetime.utcnow() t = [tod.year,tod.month,tod.day] diff --git a/htmlgenerators.py b/htmlgenerators.py new file mode 100644 index 0000000..c8d819c --- /dev/null +++ b/htmlgenerators.py @@ -0,0 +1,64 @@ + + + +def artistLink(name): + import urllib + return "" + name + "" + +# necessary because urllib.parse.urlencode doesnt handle multidicts +def keysToUrl(*dicts): + import urllib + st = "" + keys = removeIdentical(*dicts) + for k in keys: + values = keys.getall(k) + st += "&".join([urllib.parse.urlencode({k:v}) for v in values]) + st += "&" + return st + +def removeIdentical(*dicts): + from bottle import FormsDict + + #combine multiple dicts + keys = FormsDict() + for d in dicts: + for k in d: + try: #multidicts + for v in d.getall(k): + keys.append(k,v) + except: #normaldicts + v = d.get(k) + keys.append(k,v) + + new = FormsDict() + for k in keys: + values = set(keys.getall(k)) + for v in values: + new.append(k,v) + + return new + +def getTimeDesc(timestamp): + import datetime + tim = datetime.datetime.utcfromtimestamp(timestamp) + return tim.strftime("%d. %b %Y %I:%M %p") + + +# limit a multidict to only the specified keys +# would be a simple constructor expression, but multidicts apparently don't let me do that +# hardcoding this to only allow multi values for a key in one case: artist when there is also a title specified +def pickKeys(d,*keys): + from bottle import FormsDict + if isinstance(d,dict) or not "title" in d: + return {k:d.get(k) for k in d if k in keys} + else: + # create a normal dictionary of lists + newd = {k:d.getall(k) for k in d if k in keys and k=="artist"} + newd2 = {k:[d.get(k)] for k in d if k in keys and k!="artist"} + # one by one add the list entries to the formsdict + finald = FormsDict() + for k in newd: + for v in newd.get(k): + finald.append(k,v) + + return finald diff --git a/server.py b/server.py index 0220ac4..0b4c862 100755 --- a/server.py +++ b/server.py @@ -2,7 +2,7 @@ from bottle import Bottle, route, get, post, error, run, template, static_file, request, response, FormsDict from importlib.machinery import SourceFileLoader -from utilities import removeIdentical +from htmlgenerators import removeIdentical import _thread import waitress import urllib.request @@ -120,4 +120,4 @@ except: ## start database server _thread.start_new_thread(SourceFileLoader("database","database.py").load_module().runserver,(DATABASE_PORT,)) -run(webserver, host='0.0.0.0', port=MAIN_PORT, server='waitress') +run(webserver, host='::', port=MAIN_PORT, server='waitress') diff --git a/utilities.py b/utilities.py index 853b056..cdb674a 100644 --- a/utilities.py +++ b/utilities.py @@ -228,32 +228,4 @@ def cacheImage(url,path,filename): target = path + "/" + filename + "." + response.info().get_content_subtype() urllib.request.urlretrieve(url,target) -def artistLink(name): - import urllib - return "" + name + "" -# necessary because urllib.parse.urlencode doesnt handle multidicts -def keysToUrl(keys): - import urllib - st = "" - for k in removeIdentical(keys): - values = keys.getall(k) - st += "&".join([urllib.parse.urlencode({k:v}) for v in values]) - st += "&" - return st - -def removeIdentical(keys): - from bottle import FormsDict - - new = FormsDict() - for k in keys: - values = set(keys.getall(k)) - for v in values: - new.append(k,v) - - return new - -def getTimeDesc(timestamp): - import datetime - tim = datetime.datetime.utcfromtimestamp(timestamp) - return tim.strftime("%d. %b %Y %I:%M %p") diff --git a/website/artist.html b/website/artist.html index da5de5f..3886c6b 100644 --- a/website/artist.html +++ b/website/artist.html @@ -18,7 +18,7 @@ KEY_ASSOCIATED
-KEY_DESCRIPTION
+KEY_DESCRIPTION
diff --git a/website/maloja.css b/website/maloja.css index ae374cb..aefad72 100644 --- a/website/maloja.css +++ b/website/maloja.css @@ -39,6 +39,15 @@ table.top_info td.text h1 { display:inline; padding-right:5px; } + +p.desc a { + padding-left:20px; + background-repeat:no-repeat; + background-size:contain; + background-position:left; + background-image:url("https://www.last.fm/static/images/lastfm_avatar_twitter.66cd2c48ce03.png"); +} + /* table.top_info td.text .stats { color:grey; diff --git a/website/scrobbles.py b/website/scrobbles.py index ac4ecd8..614dece 100644 --- a/website/scrobbles.py +++ b/website/scrobbles.py @@ -3,16 +3,15 @@ import json def replacedict(keys,dbport): - from utilities import getArtistInfo, getTimeDesc, artistLink, keysToUrl + from utilities import getArtistInfo + from htmlgenerators import getTimeDesc, artistLink, keysToUrl, pickKeys - - #hand down the since and from arguments - #extrakeys = urllib.parse.urlencode(keys,doseq=True) - extrakeys = keysToUrl(keys) + timekeys = pickKeys(keys,"since","to","in") + limitkeys = pickKeys(keys,"artist","title") limitstring = "" - response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/scrobbles?" + extrakeys) + response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/scrobbles?" + keysToUrl(limitkeys,timekeys)) db_data = json.loads(response.read()) scrobbles = db_data["list"] diff --git a/website/topartists.py b/website/topartists.py index 826876a..50289d1 100644 --- a/website/topartists.py +++ b/website/topartists.py @@ -3,12 +3,13 @@ import json def replacedict(keys,dbport): - from utilities import getArtistInfo, artistLink + from utilities import getArtistInfo + from htmlgenerators import artistLink, keysToUrl, pickKeys - #hand down the since and from arguments - extrakeys = urllib.parse.urlencode(keys,quote_via=urllib.parse.quote,safe="/") + timekeys = pickKeys(keys,"since","to","in") + limitkeys = pickKeys(keys) - response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/charts/artists?" + extrakeys) + response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/charts/artists?" + keysToUrl(timekeys,limitkeys)) db_data = json.loads(response.read()) charts = db_data["list"][:50] topartist = charts[0]["artist"] @@ -17,7 +18,7 @@ def replacedict(keys,dbport): imgurl = info.get("image") - response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/scrobbles?" + extrakeys) + response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/scrobbles?" + keysToUrl(timekeys,limitkeys)) db_data = json.loads(response.read()) scrobblelist = db_data["list"] scrobbles = len(scrobblelist) @@ -34,8 +35,8 @@ def replacedict(keys,dbport): html += artistLink(e["artist"]) if (e["counting"] != []): html += " incl. " + ", ".join([artistLink(a) for a in e["counting"]]) + "" - html += "