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

Modularizing HTML generation, Part I

This commit is contained in:
Krateng 2018-12-26 17:42:55 +01:00
parent bed50452b9
commit 3cfa8428ff
9 changed files with 112 additions and 77 deletions

View File

@ -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]

64
htmlgenerators.py Normal file
View File

@ -0,0 +1,64 @@
def artistLink(name):
import urllib
return "<a href='/artist?artist=" + urllib.parse.quote(name) + "'>" + name + "</a>"
# 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

View File

@ -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')

View File

@ -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 "<a href='/artist?artist=" + urllib.parse.quote(name) + "'>" + name + "</a>"
# 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")

View File

@ -18,7 +18,7 @@
<span>KEY_ASSOCIATED</span>
<p class="stats"><a href="/scrobbles?artist=KEY_ENC_ARTISTNAME">KEY_SCROBBLES Scrobbles</a></p>
<p>KEY_DESCRIPTION</p>
<p class="desc">KEY_DESCRIPTION</p>
</td>
</tr>
</table>

View File

@ -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;

View File

@ -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"]

View File

@ -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 += " <span class='extra'>incl. " + ", ".join([artistLink(a) for a in e["counting"]]) + "</span>"
html += "</td><td class='amount'><a href='/scrobbles?artist=" + urllib.parse.quote(e["artist"]) + "&associated&" + extrakeys + "'>" + str(e["scrobbles"]) + "</a></td>"
html += "<td class='bar'><a href='/scrobbles?artist=" + urllib.parse.quote(e["artist"]) + "&associated&" + extrakeys + "'><div style='width:" + str(e["scrobbles"]/maxbar * 100) + "%;'></div></a></td>"
html += "</td><td class='amount'><a href='/scrobbles?artist=" + urllib.parse.quote(e["artist"]) + "&associated&" + keysToUrl(timekeys) + "'>" + str(e["scrobbles"]) + "</a></td>"
html += "<td class='bar'><a href='/scrobbles?artist=" + urllib.parse.quote(e["artist"]) + "&associated&" + keysToUrl(timekeys) + "'><div style='width:" + str(e["scrobbles"]/maxbar * 100) + "%;'></div></a></td>"
html += "</tr>"
i += 1
html += "</table>"

View File

@ -3,18 +3,13 @@ import json
def replacedict(keys,dbport):
from utilities import getArtistInfo, artistLink, keysToUrl
from utilities import getArtistInfo
from htmlgenerators import artistLink, keysToUrl, pickKeys
# we don't use the associated key for top tracks so we don't wanna hand it down to functions we're calling
keys.pop("associated",None)
timekeys = pickKeys(keys,"since","to","in")
limitkeys = pickKeys(keys,"artist")
#hand down the since and from arguments
extrakeys = urllib.parse.urlencode(keys,quote_via=urllib.parse.quote,safe="/")
# I should probably add a separate variable for keys that are passed to db functions and keys that are inherited to links (usually only time)
#extrakeys = keysToUrl(keys)
# top tracks should always be of one artist
response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/charts/tracks?" + extrakeys)
response = urllib.request.urlopen("http://localhost:" + str(dbport) + "/charts/tracks?" + keysToUrl(timekeys,limitkeys))
db_data = json.loads(response.read())
charts = db_data["list"][:50]
limitstring = ""
@ -30,7 +25,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)
@ -45,8 +40,8 @@ def replacedict(keys,dbport):
html += "<td class='rank'>#" + str(i) + "</td><td class='artists'>"
html += ", ".join([artistLink(a) for a in e["track"]["artists"]])
html += "</td><td class='title'>" + e["track"]["title"]
html += "</td><td class='amount'><a href='/scrobbles?" + "&".join(["artist=" + urllib.parse.quote(a) for a in e["track"]["artists"]]) + "&title=" + urllib.parse.quote(e["track"]["title"]) + "&" + extrakeys + "'>" + str(e["scrobbles"]) + "</a></td>"
html += "<td class='bar'><a href='/scrobbles?" + "&".join(["artist=" + urllib.parse.quote(a) for a in e["track"]["artists"]]) + "&title=" + urllib.parse.quote(e["track"]["title"]) + "&" + extrakeys + "'><div style='width:" + str(e["scrobbles"]/maxbar * 100) + "%;'></div></a>"
html += "</td><td class='amount'><a href='/scrobbles?" + "&".join(["artist=" + urllib.parse.quote(a) for a in e["track"]["artists"]]) + "&title=" + urllib.parse.quote(e["track"]["title"]) + "&" + keysToUrl(timekeys) + "'>" + str(e["scrobbles"]) + "</a></td>"
html += "<td class='bar'><a href='/scrobbles?" + "&".join(["artist=" + urllib.parse.quote(a) for a in e["track"]["artists"]]) + "&title=" + urllib.parse.quote(e["track"]["title"]) + "&" + keysToUrl(timekeys) + "'><div style='width:" + str(e["scrobbles"]/maxbar * 100) + "%;'></div></a>"
html += "</td>"
html += "</tr>"
i += 1