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:
parent
bed50452b9
commit
3cfa8428ff
35
database.py
35
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]
|
||||
|
||||
|
||||
|
64
htmlgenerators.py
Normal file
64
htmlgenerators.py
Normal 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
|
@ -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')
|
||||
|
28
utilities.py
28
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 "<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")
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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"]
|
||||
|
||||
|
@ -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>"
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user