Refactored into Python Package

This commit is contained in:
Krateng 2019-11-24 21:47:03 +01:00
parent 3c12462d36
commit 55621ef4ef
102 changed files with 1043 additions and 483 deletions

View File

4
.gitignore vendored
View File

@ -1,17 +1,15 @@
# generic temporary / dev files
*.pyc
*.sh
!/update_requirements.sh
*.note
*.xcf
nohup.out
/.dev
/maloja.egg-info
# user files
*.tsv
*.rulestate
*.log
*.css
# currently not using
/screenshot*.png

10
info.py
View File

@ -1,10 +0,0 @@
import os
author = {
"name":"Johannes Krattenmacher",
"email":"maloja@krateng.dev",
"github": "krateng"
}
version = 1,5,15
versionstr = ".".join(str(n) for n in version)
dev = os.path.exists("./.dev")

350
maloja
View File

@ -1,350 +0,0 @@
#!/usr/bin/env python3
import subprocess
import sys
import signal
import os
import stat
import pathlib
neededmodules = [
"bottle",
"waitress",
"setproctitle",
"doreah",
"nimrodel"
]
recommendedmodules = [
"wand"
]
SOURCE_URL = "https://github.com/krateng/maloja/archive/master.zip"
def blue(txt): return "\033[94m" + txt + "\033[0m"
def green(txt): return "\033[92m" + txt + "\033[0m"
def yellow(txt): return "\033[93m" + txt + "\033[0m"
## GOTODIR goes to directory that seems to have a maloja install
## SETUP assumes correct directory. sets settings and key
## INSTALL ignores local files, just installs prerequisites
## START INSTALL - GOTODIR - SETUP - starts process
## RESTART STOP - START
## STOP Stops process
## UPDATE GOTODIR - updates from repo
## LOADLASTFM GOTODIR - imports csv data
## INSTALLHERE makes this directory valid - UPDATE - INSTALL - SETUP
def gotodir():
if os.path.exists("./server.py"):
return True
elif os.path.exists("/opt/maloja/server.py"):
os.chdir("/opt/maloja/")
return True
print("Maloja installation could not be found.")
return False
def setup():
from doreah import settings
# EXTERNAL API KEYS
apikeys = {
"LASTFM_API_KEY":"Last.fm API Key",
"FANARTTV_API_KEY":"Fanart.tv API Key",
"SPOTIFY_API_ID":"Spotify Client ID",
"SPOTIFY_API_SECRET":"Spotify Client Secret"
}
print("Various external services can be used to display images. If not enough of them are set up, only local images will be used.")
for k in apikeys:
key = settings.get_settings(k)
if key is None:
print("\t" + "Currently not using a " + apikeys[k] + " for image display.")
elif key == "ASK":
print("\t" + "Please enter your " + apikeys[k] + ". If you do not want to use one at this moment, simply leave this empty and press Enter.")
key = input()
if key == "": key = None
settings.update_settings("settings/settings.ini",{k:key},create_new=True)
else:
print("\t" + apikeys[k] + " found.")
# OWN API KEY
if os.path.exists("./clients/authenticated_machines.tsv"):
pass
else:
print("Do you want to set up a key to enable scrobbling? Your scrobble extension needs that key so that only you can scrobble tracks to your database. [Y/n]")
answer = input()
if answer.lower() in ["y","yes","yea","1","positive","true",""]:
import random
key = ""
for i in range(64):
key += str(random.choice(list(range(10)) + list("abcdefghijklmnopqrstuvwxyz") + list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")))
print("Your API Key: " + yellow(key))
with open("./clients/authenticated_machines.tsv","w") as keyfile:
keyfile.write(key + "\t" + "Default Generated Key")
elif answer.lower() in ["n","no","nay","0","negative","false"]:
pass
def install():
toinstall = []
toinstallr = []
for m in neededmodules:
try:
exec("import " + m) #I'm sorry
except:
toinstall.append(m)
for m in recommendedmodules:
try:
exec("import " + m)
except:
toinstallr.append(m)
if toinstall != []:
print("The following python modules need to be installed:")
for m in toinstall:
print("\t" + yellow(m))
if toinstallr != []:
print("The following python modules are highly recommended, some features will not work without them:")
for m in toinstallr:
print("\t" + yellow(m))
if toinstall != [] or toinstallr != []:
if os.geteuid() != 0:
print("You can install them with",yellow("pip install -r requirements.txt"),"or Maloja can try to install them automatically. For this, you need to run this script as a root user.")
return False
else:
print("You can install them with",yellow("pip install -r requirements.txt"),"or Maloja can try to install them automatically, This might or might not work / bloat your system / cause a nuclear war.")
fail = False
if toinstall != []:
print("Attempt to install required modules? [Y/n]")
answer = input()
if answer.lower() in ["y","yes","yea","1","positive","true",""]:
for m in toinstall:
try:
print("Installing " + m + " with pip...")
from pip._internal import main as pipmain
#os.system("pip3 install " + m)
pipmain(["install",m])
print("Success!")
except:
print("Failure!")
fail = True
elif answer.lower() in ["n","no","nay","0","negative","false"]:
return False #if you dont want to auto install required, you probably dont want to install recommended
else:
print("What?")
return False
if toinstallr != []:
print("Attempt to install recommended modules? [Y/n]")
answer = input()
if answer.lower() in ["y","yes","yea","1","positive","true",""]:
for m in toinstallr:
try:
print("Installing " + m + " with pip...")
from pip._internal import main as pipmain
#os.system("pip3 install " + m)
pipmain(["install",m])
print("Success!")
except:
print("Failure!")
fail = True
elif answer.lower() in ["n","no","nay","0","negative","false"]:
return False
else:
print("What?")
return False
if fail: return False
print("All modules successfully installed!")
print("Run the script again (without root) to start Maloja.")
return False
else:
print("All necessary modules seem to be installed.")
return True
def getInstance():
try:
output = subprocess.check_output(["pidof","Maloja"])
pid = int(output)
return pid
except:
return None
def getInstanceSupervisor():
try:
output = subprocess.check_output(["pidof","maloja_supervisor"])
pid = int(output)
return pid
except:
return None
def start():
if install():
if gotodir():
setup()
p = subprocess.Popen(["python3","server.py"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
p = subprocess.Popen(["python3","supervisor.py"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
print(green("Maloja started!") + " PID: " + str(p.pid))
from doreah import settings
port = settings.get_settings("WEB_PORT")
print("Visit your server address (Port " + str(port) + ") to see your web interface. Visit /setup to get started.")
print("If you're installing this on your local machine, these links should get you there:")
print("\t" + blue("http://localhost:" + str(port)))
print("\t" + blue("http://localhost:" + str(port) + "/setup"))
return True
#else:
# os.chdir("/opt/maloja/")
# p = subprocess.Popen(["python3","server.py"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
# print("Maloja started! PID: " + str(p.pid))
# return True
print("Error while starting Maloja.")
return False
def restart():
#pid = getInstance()
#if pid == None:
# print("Server is not running.")
#else:
# stop()
#start()
wasrunning = stop()
start()
return wasrunning
def stop():
pid_sv = getInstanceSupervisor()
if pid_sv is not None:
os.kill(pid_sv,signal.SIGTERM)
pid = getInstance()
if pid is None:
print("Server is not running")
return False
else:
os.kill(pid,signal.SIGTERM)
print("Maloja stopped! PID: " + str(pid))
return True
def update():
import urllib.request
import shutil
#import tempfile
import zipfile
import distutils.dir_util
if not gotodir(): return False
if os.path.exists("./.dev"):
print("Better not overwrite the development server!")
return
print("Updating Maloja...")
#with urllib.request.urlopen(SOURCE_URL) as response:
# with tempfile.NamedTemporaryFile(delete=True) as tmpfile:
# shutil.copyfileobj(response,tmpfile)
#
# with zipfile.ZipFile(tmpfile.name,"r") as z:
#
# for f in z.namelist():
# #print("extracting " + f)
# z.extract(f)
os.system("wget " + SOURCE_URL)
with zipfile.ZipFile("./master.zip","r") as z:
# if we ever have a separate directory for the code
# (the calling update script is not the same version as the current
# remote repository, so we better add this check just in case)
if "source/" in z.namelist():
for f in z.namelist():
if f.startswith("source/"):
z.extract(f)
for dir,_,files in os.walk("source"):
for f in files:
origfile = os.path.join(dir,f)
newfile = ps.path.join(dir[7:],f)
os.renames(origfile,newfile) #also prunes empty directory
else:
for f in z.namelist():
z.extract(f)
os.remove("./master.zip")
distutils.dir_util.copy_tree("./maloja-master/","./",verbose=2)
shutil.rmtree("./maloja-master")
print("Done!")
os.chmod("./maloja",os.stat("./maloja").st_mode | stat.S_IXUSR)
os.chmod("./update_requirements.sh",os.stat("./update_requirements.sh").st_mode | stat.S_IXUSR)
try:
returnval = os.system("./update_requirements.sh")
assert returnval == 0
except:
print("Make sure to update required modules! (" + yellow("./update_requirements.sh") + ")")
if stop(): start() #stop returns whether it was running before, in which case we restart it
def loadlastfm():
try:
filename = sys.argv[2]
filename = os.path.abspath(filename)
except:
print("Please specify a file!")
return
if gotodir():
if os.path.exists("./scrobbles/lastfmimport.tsv"):
print("Already imported Last.FM data. Overwrite? [y/N]")
if input().lower() in ["y","yes","yea","1","positive","true"]:
pass
else:
return
print("Please wait...")
os.system("python3 ./lastfmconverter.py " + filename + " ./scrobbles/lastfmimport.tsv")
print("Successfully imported your Last.FM scrobbles!")
def installhere():
if len(os.listdir()) > 1:
print("You should install Maloja in an empty directory.")
return False
else:
open("server.py","w").close()
# if it's cheese, but it works, it ain't cheese
update()
install()
setup()
print("Maloja installed! Start with " + yellow("./maloja start"))
if __name__ == "__main__":
if sys.argv[1] == "start": restart()
elif sys.argv[1] == "restart": restart()
elif sys.argv[1] == "stop": stop()
elif sys.argv[1] == "update": update()
elif sys.argv[1] == "import": loadlastfm()
elif sys.argv[1] == "install": installhere()
else: print("Valid commands: start restart stop update import install")

19
maloja/__init__.py Normal file
View File

@ -0,0 +1,19 @@
name = "maloja"
from .info import author,version,versionstr
requires = [
"bottle>=0.12.16",
"waitress>=1.3",
"doreah>=1.2.7",
"nimrodel>=0.4.9",
"setproctitle>=1.1.10",
"wand>=0.5.4",
"lesscpy>=0.13"
]
resources = [
"website/*/*",
"website/*",
"data_files/*/*",
"data_files/.doreah"
]

View File

@ -1,5 +1,5 @@
import re
import utilities
from . import utilities
from doreah import tsv, settings
# need to do this as a class so it can retain loaded settings from file

View File

@ -1,11 +1,11 @@
from doreah.logging import log
import hashlib
import random
import database
from . import database
import datetime
import itertools
import sys
from cleanup import CleanerAgent
from .cleanup import CleanerAgent
from bottle import response
## GNU-FM-compliant scrobbling
@ -68,7 +68,7 @@ def handle(path,keys):
def scrobbletrack(artiststr,titlestr,timestamp):
try:
log("Incoming scrobble (compliant API): ARTISTS: " + artiststr + ", TRACK: " + titlestr,module="debug")
log("Incoming scrobble (compliant API): ARTISTS: " + artiststr + ", TRACK: " + titlestr,module="debug")
(artists,title) = cla.fullclean(artiststr,titlestr)
database.createScrobble(artists,title,timestamp)
database.sync()

165
maloja/controller.py Executable file
View File

@ -0,0 +1,165 @@
#!/usr/bin/env python3
import subprocess
import sys
import signal
import os
import shutil
from distutils import dir_util
import stat
import pathlib
import pkg_resources
from .info import DATA_DIR
def blue(txt): return "\033[94m" + txt + "\033[0m"
def green(txt): return "\033[92m" + txt + "\033[0m"
def yellow(txt): return "\033[93m" + txt + "\033[0m"
os.chdir(DATA_DIR)
def copy_initial_local_files():
folder = pkg_resources.resource_filename(__name__,"data_files")
#shutil.copy(folder,DATA_DIR)
dir_util.copy_tree(folder,DATA_DIR)
def setup():
copy_initial_local_files()
from doreah import settings
# EXTERNAL API KEYS
apikeys = {
"LASTFM_API_KEY":"Last.fm API Key",
"FANARTTV_API_KEY":"Fanart.tv API Key",
"SPOTIFY_API_ID":"Spotify Client ID",
"SPOTIFY_API_SECRET":"Spotify Client Secret"
}
print("Various external services can be used to display images. If not enough of them are set up, only local images will be used.")
for k in apikeys:
key = settings.get_settings(k)
if key is None:
print("\t" + "Currently not using a " + apikeys[k] + " for image display.")
elif key == "ASK":
print("\t" + "Please enter your " + apikeys[k] + ". If you do not want to use one at this moment, simply leave this empty and press Enter.")
key = input()
if key == "": key = None
settings.update_settings("settings/settings.ini",{k:key},create_new=True)
else:
print("\t" + apikeys[k] + " found.")
# OWN API KEY
if os.path.exists("./clients/authenticated_machines.tsv"):
pass
else:
print("Do you want to set up a key to enable scrobbling? Your scrobble extension needs that key so that only you can scrobble tracks to your database. [Y/n]")
answer = input()
if answer.lower() in ["y","yes","yea","1","positive","true",""]:
import random
key = ""
for i in range(64):
key += str(random.choice(list(range(10)) + list("abcdefghijklmnopqrstuvwxyz") + list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")))
print("Your API Key: " + yellow(key))
with open("./clients/authenticated_machines.tsv","w") as keyfile:
keyfile.write(key + "\t" + "Default Generated Key")
elif answer.lower() in ["n","no","nay","0","negative","false"]:
pass
def getInstance():
try:
output = subprocess.check_output(["pidof","Maloja"])
pid = int(output)
return pid
except:
return None
def getInstanceSupervisor():
try:
output = subprocess.check_output(["pidof","maloja_supervisor"])
pid = int(output)
return pid
except:
return None
def start():
setup()
try:
p = subprocess.Popen(["python3","-m","maloja.server"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,cwd=DATA_DIR)
sp = subprocess.Popen(["python3","-m","maloja.supervisor"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,cwd=DATA_DIR)
print(green("Maloja started!") + " PID: " + str(p.pid))
from doreah import settings
port = settings.get_settings("WEB_PORT")
print("Visit your server address (Port " + str(port) + ") to see your web interface. Visit /setup to get started.")
print("If you're installing this on your local machine, these links should get you there:")
print("\t" + blue("http://localhost:" + str(port)))
print("\t" + blue("http://localhost:" + str(port) + "/setup"))
return True
except:
print("Error while starting Maloja.")
return False
def restart():
wasrunning = stop()
start()
return wasrunning
def stop():
pid_sv = getInstanceSupervisor()
if pid_sv is not None:
os.kill(pid_sv,signal.SIGTERM)
pid = getInstance()
if pid is None:
print("Server is not running")
return False
else:
os.kill(pid,signal.SIGTERM)
print("Maloja stopped! PID: " + str(pid))
return True
def loadlastfm():
try:
filename = sys.argv[2]
filename = os.path.abspath(filename)
except:
print("Please specify a file!")
return
if os.path.exists("./scrobbles/lastfmimport.tsv"):
print("Already imported Last.FM data. Overwrite? [y/N]")
if input().lower() in ["y","yes","yea","1","positive","true"]:
pass
else:
return
print("Please wait...")
os.system("python3 ./lastfmconverter.py " + filename + " ./scrobbles/lastfmimport.tsv")
print("Successfully imported your Last.FM scrobbles!")
def main():
if sys.argv[1] == "start": restart()
elif sys.argv[1] == "restart": restart()
elif sys.argv[1] == "stop": stop()
#elif sys.argv[1] == "update": update()
elif sys.argv[1] == "import": loadlastfm()
#elif sys.argv[1] == "install": installhere()
else: print("Valid commands: start restart stop import")
if __name__ == "__main__":
main()

View File

Can't render this file because it has a wrong number of fields in line 4.

View File

Can't render this file because it has a wrong number of fields in line 5.

View File

Can't render this file because it has a wrong number of fields in line 5.

View File

Can't render this file because it has a wrong number of fields in line 5.

View File

Can't render this file because it has a wrong number of fields in line 5.

View File

Can't render this file because it has a wrong number of fields in line 4.

View File

Can't render this file because it has a wrong number of fields in line 4.

View File

View File

@ -1,12 +1,13 @@
# server
from bottle import request, response, FormsDict
# rest of the project
from cleanup import CleanerAgent, CollectorAgent
import utilities
from malojatime import register_scrobbletime, time_stamps, ranges
from urihandler import uri_to_internal, internal_to_uri, compose_querystring
import compliant_api
from external import proxy_scrobble
from .cleanup import CleanerAgent, CollectorAgent
from . import utilities
from .malojatime import register_scrobbletime, time_stamps, ranges
from .urihandler import uri_to_internal, internal_to_uri, compose_querystring
from . import compliant_api
from .external import proxy_scrobble
from . import info
# doreah toolkit
from doreah.logging import log
from doreah import tsv
@ -232,7 +233,7 @@ def test_server(key=None):
@dbserver.get("serverinfo")
def server_info():
import info
response.set_header("Access-Control-Allow-Origin","*")
response.set_header("Content-Type","application/json")

1
maloja/doreah Symbolic link
View File

@ -0,0 +1 @@
../../tools/doreah/doreah

View File

@ -1,6 +1,6 @@
import os
import re
from cleanup import CleanerAgent
from .cleanup import CleanerAgent
from doreah.logging import log
import difflib

View File

@ -1,7 +1,7 @@
import urllib
from bottle import FormsDict
import datetime
from urihandler import compose_querystring
from .urihandler import compose_querystring
import urllib.parse
from doreah.settings import get_settings

View File

@ -1,8 +1,8 @@
from htmlgenerators import *
import database
from utilities import getArtistImage, getTrackImage
from malojatime import *
from urihandler import compose_querystring, internal_to_uri, uri_to_internal
from .htmlgenerators import *
from . import database
from .utilities import getArtistImage, getTrackImage
from .malojatime import *
from .urihandler import compose_querystring, internal_to_uri, uri_to_internal
import urllib
import datetime
import math

19
maloja/info.py Normal file
View File

@ -0,0 +1,19 @@
import os
author = {
"name":"Johannes Krattenmacher",
"email":"maloja@krateng.dev",
"github": "krateng"
}
version = 2,0,0
versionstr = ".".join(str(n) for n in version)
try:
DATA_DIR = os.environ["XDG_DATA_HOME"].split(":")[0]
assert os.path.exists(DATA_DIR)
except:
DATA_DIR = os.path.join(os.environ["HOME"],".local/share/")
DATA_DIR = os.path.join(DATA_DIR,"maloja")
os.makedirs(DATA_DIR,exist_ok=True)

View File

@ -1,6 +1,6 @@
import sys, os, datetime, re, cleanup
from cleanup import *
from utilities import *
from .cleanup import *
from .utilities import *
log = open(sys.argv[1])

View File

@ -1,55 +1,66 @@
#!/usr/bin/env python
import os
from .info import DATA_DIR
os.chdir(DATA_DIR)
# server stuff
from bottle import Bottle, route, get, post, error, run, template, static_file, request, response, FormsDict, redirect, template, HTTPResponse, BaseRequest
import waitress
# monkey patching
import monkey
from . import monkey
# rest of the project
import database
import htmlmodules
import htmlgenerators
import malojatime
import utilities
from utilities import resolveImage
from urihandler import uri_to_internal, remove_identical
import urihandler
import info
from . import database
from . import htmlmodules
from . import htmlgenerators
from . import malojatime
from . import utilities
from .utilities import resolveImage
from .urihandler import uri_to_internal, remove_identical
from . import urihandler
from . import info
# doreah toolkit
from doreah import settings
from doreah.logging import log
from doreah.timing import Clock
# technical
from importlib.machinery import SourceFileLoader
#from importlib.machinery import SourceFileLoader
import importlib
import _thread
import sys
import signal
import os
import setproctitle
import pkg_resources
# url handling
import urllib
#settings.config(files=["settings/default.ini","settings/settings.ini"])
#settings.update("settings/default.ini","settings/settings.ini")
MAIN_PORT = settings.get_settings("WEB_PORT")
HOST = settings.get_settings("HOST")
THREADS = 12
BaseRequest.MEMFILE_MAX = 15 * 1024 * 1024
WEBFOLDER = pkg_resources.resource_filename(__name__,"website")
webserver = Bottle()
pthjoin = os.path.join
import lesscpy
css = ""
for f in os.listdir("website/less"):
css += lesscpy.compile("website/less/" + f)
#import lesscpy
#css = ""
#for f in os.listdir(pthjoin(WEBFOLDER,"less")):
# css += lesscpy.compile(pthjoin(WEBFOLDER,"less",f))
os.makedirs("website/css",exist_ok=True)
with open("website/css/style.css","w") as f:
f.write(css)
#os.makedirs("website/css",exist_ok=True)
#with open("website/css/style.css","w") as f:
# f.write(css)
@webserver.route("")
@ -69,16 +80,16 @@ def customerror(error):
code = int(str(error).split(",")[0][1:])
log("HTTP Error: " + str(code),module="error")
if os.path.exists("website/errors/" + str(code) + ".html"):
return static_file("website/errors/" + str(code) + ".html",root="")
if os.path.exists(pthjoin(WEBFOLDER,"errors",str(code) + ".html")):
return static_file(pthjoin(WEBFOLDER,"errors",str(code) + ".html"),root="")
else:
with open("website/errors/generic.html") as htmlfile:
with open(pthjoin(WEBFOLDER,"errors/generic.html")) as htmlfile:
html = htmlfile.read()
# apply global substitutions
with open("website/common/footer.html") as footerfile:
with open(pthjoin(WEBFOLDER,"common/footer.html")) as footerfile:
footerhtml = footerfile.read()
with open("website/common/header.html") as headerfile:
with open(pthjoin(WEBFOLDER,"common/header.html")) as headerfile:
headerhtml = headerfile.read()
html = html.replace("</body>",footerhtml + "</body>").replace("</head>",headerhtml + "</head>")
@ -143,17 +154,18 @@ def static_image(pth):
@webserver.route("/<name:re:.*\\.ico>")
@webserver.route("/<name:re:.*\\.txt>")
def static(name):
response = static_file("website/" + name,root="")
response = static_file(name,root=WEBFOLDER)
response.set_header("Cache-Control", "public, max-age=3600")
return response
@webserver.route("/<name>")
def static_html(name):
linkheaders = ["</css/style.css>; rel=preload; as=style"]
keys = remove_identical(FormsDict.decode(request.query))
pyhp_file = os.path.exists("website/" + name + ".pyhp")
html_file = os.path.exists("website/" + name + ".html")
pyhp_file = os.path.exists(pthjoin(WEBFOLDER,name + ".pyhp"))
html_file = os.path.exists(pthjoin(WEBFOLDER,name + ".html"))
pyhp_pref = settings.get_settings("USE_PYHP")
adminmode = request.cookies.get("adminmode") == "true" and database.checkAPIkey(request.cookies.get("apikey")) is not False
@ -183,29 +195,30 @@ def static_html(name):
environ["filterkeys"], environ["limitkeys"], environ["delimitkeys"], environ["amountkeys"] = uri_to_internal(keys)
#response.set_header("Content-Type","application/xhtml+xml")
res = file("website/" + name + ".pyhp",environ)
res = file(pthjoin(WEBFOLDER,name + ".pyhp"),environ)
log("Generated page " + name + " in " + str(clock.stop()) + "s (PYHP)",module="debug")
return res
# if not, use the old way
else:
with open("website/" + name + ".html") as htmlfile:
with open(pthjoin(WEBFOLDER,name + ".html")) as htmlfile:
html = htmlfile.read()
# apply global substitutions
with open("website/common/footer.html") as footerfile:
with open(pthjoin(WEBFOLDER,"common/footer.html")) as footerfile:
footerhtml = footerfile.read()
with open("website/common/header.html") as headerfile:
with open(pthjoin(WEBFOLDER,"common/header.html")) as headerfile:
headerhtml = headerfile.read()
html = html.replace("</body>",footerhtml + "</body>").replace("</head>",headerhtml + "</head>")
# If a python file exists, it provides the replacement dict for the html file
if os.path.exists("website/" + name + ".py"):
if os.path.exists(pthjoin(WEBFOLDER,name + ".py")):
#txt_keys = SourceFileLoader(name,"website/" + name + ".py").load_module().replacedict(keys,DATABASE_PORT)
try:
txt_keys,resources = SourceFileLoader(name,"website/" + name + ".py").load_module().instructions(keys)
module = importlib.import_module(".website." + name,package="maloja")
txt_keys,resources = module.instructions(keys)
except Exception as e:
log("Error in website generation: " + str(sys.exc_info()),module="error")
raise

View File

@ -20,6 +20,6 @@ while True:
except:
log("Maloja is not running, restarting...",module="supervisor")
try:
p = subprocess.Popen(["python3","server.py"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
p = subprocess.Popen(["python3","-m","maloja.server"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
except e:
log("Error starting Maloja: " + str(e),module="supervisor")

View File

@ -1,6 +1,6 @@
import urllib
from bottle import FormsDict
from malojatime import time_fix, time_str, get_range_object
from .malojatime import time_fix, time_str, get_range_object
import math
# necessary because urllib.parse.urlencode doesnt handle multidicts

View File

@ -14,7 +14,7 @@ from doreah import caching
from doreah.logging import log
from doreah.regular import yearly, daily
from external import api_request_track, api_request_artist
from .external import api_request_track, api_request_artist
@ -469,7 +469,7 @@ def set_image(b64,**keys):
def update_medals():
from database import MEDALS, MEDALS_TRACKS, STAMPS, get_charts_artists, get_charts_tracks
from .database import MEDALS, MEDALS_TRACKS, STAMPS, get_charts_artists, get_charts_tracks
currentyear = datetime.datetime.utcnow().year
try:
@ -505,8 +505,8 @@ def update_medals():
@daily
def update_weekly():
from database import WEEKLY_TOPTRACKS, WEEKLY_TOPARTISTS, get_charts_artists, get_charts_tracks
from malojatime import ranges, thisweek
from .database import WEEKLY_TOPTRACKS, WEEKLY_TOPARTISTS, get_charts_artists, get_charts_tracks
from .malojatime import ranges, thisweek
WEEKLY_TOPARTISTS.clear()

View File

@ -1,13 +1,13 @@
import urllib
import database
from malojatime import today,thisweek,thismonth,thisyear
from .. import database
from ..malojatime import today,thisweek,thismonth,thisyear
def instructions(keys):
from utilities import getArtistImage
from htmlgenerators import artistLink, artistLinks, link_address
from urihandler import compose_querystring, uri_to_internal
from htmlmodules import module_pulse, module_performance, module_trackcharts, module_scrobblelist
from ..utilities import getArtistImage
from ..htmlgenerators import artistLink, artistLinks, link_address
from ..urihandler import compose_querystring, uri_to_internal
from ..htmlmodules import module_pulse, module_performance, module_trackcharts, module_scrobblelist
filterkeys, _, _, _ = uri_to_internal(keys,forceArtist=True)
artist = filterkeys.get("artist")

View File

@ -2,10 +2,10 @@ import urllib
def instructions(keys):
from utilities import getArtistImage
from urihandler import compose_querystring, uri_to_internal
from htmlmodules import module_artistcharts, module_filterselection, module_artistcharts_tiles
from malojatime import range_desc
from ..utilities import getArtistImage
from ..urihandler import compose_querystring, uri_to_internal
from ..htmlmodules import module_artistcharts, module_filterselection, module_artistcharts_tiles
from ..malojatime import range_desc
from doreah.settings import get_settings

View File

@ -2,11 +2,11 @@ import urllib
def instructions(keys):
from utilities import getArtistImage, getTrackImage
from htmlgenerators import artistLink
from urihandler import compose_querystring, uri_to_internal
from htmlmodules import module_trackcharts, module_filterselection, module_trackcharts_tiles
from malojatime import range_desc
from ..utilities import getArtistImage, getTrackImage
from ..htmlgenerators import artistLink
from ..urihandler import compose_querystring, uri_to_internal
from ..htmlmodules import module_trackcharts, module_filterselection, module_trackcharts_tiles
from ..malojatime import range_desc
from doreah.settings import get_settings
filterkeys, timekeys, _, amountkeys = uri_to_internal(keys)

View File

@ -1,8 +1,8 @@
import urllib
import database
from .. import database
import json
from htmlgenerators import artistLink
from utilities import getArtistImage
from ..htmlgenerators import artistLink
from ..utilities import getArtistImage
def instructions(keys):

View File

@ -0,0 +1,671 @@
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Regular'), local('Ubuntu-Regular'), url(https://fonts.gstatic.com/s/ubuntu/v14/4iCs6KVjbNBYlgoKcg72j00.woff2) format('woff2');
}
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Regular'), local('Ubuntu-Regular'), url(https://fonts.gstatic.com/s/ubuntu/v14/4iCs6KVjbNBYlgoKew72j00.woff2) format('woff2');
unicode-range: U + 0400 -045F, U + 0490 -0491, U + 04 B0-04B1, U + 2116;
}
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Regular'), local('Ubuntu-Regular'), url(https://fonts.gstatic.com/s/ubuntu/v14/4iCs6KVjbNBYlgoKcw72j00.woff2) format('woff2');
unicode-range: U + 1 F00-1FFF;
}
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Regular'), local('Ubuntu-Regular'), url(https://fonts.gstatic.com/s/ubuntu/v14/4iCs6KVjbNBYlgoKfA72j00.woff2) format('woff2');
unicode-range: U + 0370 -03FF;
}
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Regular'), local('Ubuntu-Regular'), url(https://fonts.gstatic.com/s/ubuntu/v14/4iCs6KVjbNBYlgoKcQ72j00.woff2) format('woff2');
}
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Regular'), local('Ubuntu-Regular'), url(https://fonts.gstatic.com/s/ubuntu/v14/4iCs6KVjbNBYlgoKfw72.woff2) format('woff2');
}body {
background-color: #333337;
color: beige;
font-family: "Ubuntu";
}
table.top_info td.image div {
margin-right: 20px;
margin-bottom: 20px;
background-size: cover;
background-position: center;
height: 174px;
width: 174px;
}
table.top_info td.text {
vertical-align: top;
}
table.top_info td.text h1 {
display: inline;
padding-right: 5px;
}
table.top_info td.text table.image_row td {
height: 50px;
width: 50px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
opacity: 0.5;
filter: grayscale(80%);
}
table.top_info td.text table.image_row td:hover {
opacity: 1;
filter: grayscale(0%);
}
::-webkit-scrollbar {
width: 8px;
cursor: pointer;
}
::-webkit-scrollbar-track {
background: grey;
background-color: rgba(0,255,255,0.1);
}
::-webkit-scrollbar-thumb {
background-color: rgba(103,85,0,0.7);
}
::-webkit-scrollbar-thumb:hover {
background: gold;
}
[onclick]:hover,
a:hover {
cursor: pointer;
}
div.grisons_bar {
background-color: rgba(0,255,255,0.1);
}
div.grisons_bar > div {
height: 100%;
background-color: rgba(103,85,0,0.7);
}
div.grisons_bar:hover > div {
background-color: gold;
}
a {
color: inherit;
text-decoration: none;
}
a.textlink {
color: yellow;
}
a.hidelink:hover {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
body {
padding: 15px;
padding-bottom: 35px;
}
input[type="date"] {
background-color: inherit;
color: inherit;
outline: none;
border: 0px;
font-family: inherit;
font-size: inherit;
}
div#settingsicon {
position: fixed;
right: 30px;
top: 30px;
fill: beige;
}
div#settingsicon:hover {
fill: yellow;
}
div.footer {
position: fixed;
height: 20px;
background-color: #0a0a0a;
bottom: 0px;
left: 0px;
right: 0px;
padding: 10px;
opacity: 1;
}
div.footer div:nth-child(1) {
display: inline-block;
width: 40%;
text-align: left;
}
div.footer div:nth-child(2) {
display: inline-block;
width: 19%;
text-align: center;
color: gold;
font-size: 110%;
}
div.footer div:nth-child(3) {
display: inline-block;
width: 40%;
text-align: right;
}
div.footer span a {
padding-left: 20px;
background-repeat: no-repeat;
background-size: contain;
background-position: left;
background-image: url("https://github.com/favicon.ico");
}
div.footer input {
background-color: inherit;
border: 0px;
border-bottom: 1px solid beige;
color: beige;
font-size: 90%;
width: 70%;
padding-left: 5px;
padding-right: 5px;
padding-top: 2px;
padding-bottom: 2px;
font-family: "Ubuntu";
}
div.footer input:focus {
outline: none;
}
div.searchresults {
position: fixed;
bottom: 50px;
right: 20px;
width: 500px;
background-color: rgba(10,10,10,0.99);
padding: 15px;
}
div.searchresults > span {
font-size: 20px;
font-weight: bold;
}
div.searchresults table {
width: 100%;
border-spacing: 0px 4px;
}
div.searchresults tr {
background-color: #05050501;
margin-top: 5px;
margin-bottom: 5px;
height: 50px;
cursor: pointer;
}
div.searchresults tr:hover {
background-color: #23232301;
}
div.searchresults tr td.image {
height: 50px;
width: 50px;
background-size: cover;
background-position: center;
}
div.searchresults tr td:nth-child(2) {
padding-left: 10px;
}
div.searchresults table.searchresults_tracks td span:nth-child(1) {
font-size: 12px;
color: grey;
}
@media (max-width:1000px) {
div.footer {
position: fixed;
background-color: #0a0a0a;
bottom: 0px;
left: 0px;
right: 0px;
padding: 3px;
opacity: 1;
}
div.footer div:nth-child(1) {
display: none;
}
div.footer div:nth-child(2) {
display: inline-block;
width: 20%;
text-align: center;
color: gold;
}
div.footer div:nth-child(3) {
display: inline-block;
width: 70%;
text-align: right;
}
div.footer input {
width: 90%;
}
}
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 + .stat_module_topartists table,
table.top_info + .stat_module_toptracks table {
margin: 15px 0;
}
.paginate {
text-align: center;
padding: 30px;
}
.stats {
color: grey;
}
.rank {
text-align: right;
color: grey;
}
.extra {
color: grey;
font-size: 80%;
}
input#apikey {
font-family: 'Ubuntu';
outline: none;
border: 0px solid;
padding: 2px;
}
input.simpleinput {
font-family: 'Ubuntu';
color: beige;
outline: none;
border-top: 0px solid;
border-left: 0px solid;
border-right: 0px solid;
padding: 2px;
background-color: inherit;
border-bottom: 1px solid beige;
}
a {
cursor: pointer;
}
span.stat_selector_pulse,
span.stat_selector_topartists,
span.stat_selector_toptracks {
cursor: pointer;
}
.medal {
top: 5px;
font-size: 80%;
padding: 3px;
margin: 2px;
border-radius: 2px;
}
.shiny {
overflow: hidden;
position: relative;
display: inline-block;
}
.shiny:after {
content: "";
position: absolute;
top: -110%;
left: -210%;
width: 200%;
height: 200%;
opacity: 0;
transform: rotate(30deg);
background: rgba(255,255,255,0.13);
background: linear-gradient(to right,rgba(255,255,255,0.13)0%,rgba(255,255,255,0.13)77%,rgba(255,255,255,0.5)92%,rgba(255,255,255,0.0)100% );
}
.shiny:hover:after {
opacity: 1;
top: -30%;
left: -30%;
transition-property: left, top, opacity;
transition-duration: 0.7s, 0.7s, 0.15s;
transition-timing-function: ease;
}
.shiny:active:after {
opacity: 0;
}
a.gold {
background-color: gold;
color: black;
}
a.silver {
background-color: silver;
color: black;
}
a.bronze {
background-color: #cd7f32;
color: black;
}
img.certrecord {
height: 30px;
vertical-align: text-bottom;
}
img.certrecord_small {
height: 20px;
vertical-align: text-bottom;
}
img.star {
height: 20px;
vertical-align: text-bottom;
}
.button {
padding: 3px;
padding-right: 6px;
padding-left: 6px;
background-color: beige;
color: #333337;
cursor: pointer;
}
.button:hover {
background-color: yellow;
color: #333337;
}
.button.locked {
background-color: grey;
color: black;
cursor: not-allowed;
}
table.twopart {
width: 100%;
}
table.twopart > tbody > tr > td {
width: 50%;
}
table.list {
border-collapse: collapse;
}
table.list tr td {
border-bottom: 2px solid;
border-color: rgba(0,0,0,0);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 15px;
}
table.list tr:nth-child(even) {
background-color: #37373b;
}
table.list tr:nth-child(5n) td {
border-color: rgba(120,120,120,0.2);
}
table.list tr:hover {
background-color: #404044;
}
table.list td.time {
width: 11%;
color: grey;
}
table.list tr td.rank {
padding-right: 4px;
}
table.list tr td.rankup {
color: green;
padding-right: 8px;
font-size: 80%;
}
table.list tr td.rankdown {
color: red;
padding-right: 8px;
font-size: 80%;
}
table.list tr td.ranksame {
color: grey;
padding-right: 8px;
font-size: 80%;
}
table.list tr td.icon {
padding: 0px;
padding-right: 5px;
width: 20px;
}
table.list td.icon div {
width: 20px;
height: 20px;
background-size: cover;
background-position: center;
}
table.list td.artists,
td.artist,
td.title,
td.track {
min-width: 100px;
}
table.list td.track span.artist_in_trackcolumn {
color: #bbbbbb;
}
table.list td.track a.trackProviderSearch {
margin-right: 5px;
padding: 0 10px;
}
table.list td.amount {
width: 50px;
text-align: right;
}
table.list td.bar {
width: 500px;
background-color: #333337;
}
table.list td.bar div {
background-color: beige;
height: 20px;
position: relative;
}
table.list tr:hover td.bar div {
background-color: yellow;
cursor: pointer;
}
table.list td.chart {
width: 500px;
background-color: #333337;
}
table.list td.chart div {
height: 20px;
background-color: rgba(0,0,0,0.1);
border-radius: 0px 30px 30px 0px;
background-image: url("/media/chartpos_normal.png");
background-position: right;
background-repeat: no-repeat;
background-size: auto 100%;
position: relative;
}
table.list tr:hover td.chart div {
cursor: pointer;
}
table.list tr td.chart div.gold {
background-image: url("/media/chartpos_gold.png");
}
table.list tr td.chart div.silver {
background-image: url("/media/chartpos_silver.png");
}
table.list tr td.chart div.bronze {
background-image: url("/media/chartpos_bronze.png");
}
table.list tr td.button {
width: 200px;
cursor: pointer;
border-color: rgba(0,0,0,0) !important;
}
table.list td.button div {
background-color: beige;
color: #333337;
padding: 3px;
border-radius: 4px;
}
table.list td.button div:hover {
background-color: yellow;
color: #333337;
padding: 3px;
border-radius: 4px;
}
td.button.important div {
background-color: red;
color: white;
}
table.misc {
margin-left: 20px;
}
table.misc td {
padding-right: 20px;
color: #bbbbaa;
}
table.misc th {
text-align: left;
}
table.misc td.interaction {
width: 65px;
}
table.tiles_top td {
padding: 0px;
border: 0px;
}
table.tiles_top:hover td td {
opacity: 0.5;
filter: grayscale(80%);
}
table.tiles_top:hover td td:hover {
opacity: 1;
filter: grayscale(0%);
}
table.tiles_top,
table.tiles_sub {
border-collapse: collapse;
}
table.tiles_top > tbody > tr > td {
height: 300px;
width: 300px;
}
table.tiles_sub {
height: 100%;
width: 100%;
}
table.tiles_top td {
background-size: cover;
background-position: center;
vertical-align: bottom;
}
table.tiles_top td span {
background-color: rgba(0,0,0,0.7);
}
table.tiles_1x1 td {
height: 100%;
width: 100%;
font-size: 100%;
}
table.tiles_2x2 td {
height: 50%;
width: 50%;
font-size: 90%;
}
table.tiles_3x3 td {
height: 33.333%;
width: 33.333%;
font-size: 70%;
}
span.stat_module_pulse,
span.stat_module_topartists,
span.stat_module_toptracks {
display: inline-block;
vertical-align: top;
}
@media (min-width:1600px) {
div.sidelist {
position: absolute;
right: 0px;
top: 0px;
width: 40%;
height: 100%;
background-color: #444447;
padding-left: 30px;
padding-right: 30px;
}
}
div.sidelist table {
width: 100%;
table-layout: fixed;
}
div.sidelist table.list td.time {
width: 17%;
}body {
background-color: #333337;
color: beige;
font-family: "Ubuntu";
}
table.top_info td.image div {
margin-right: 20px;
margin-bottom: 20px;
background-size: cover;
background-position: center;
height: 174px;
width: 174px;
}
table.top_info td.text {
vertical-align: top;
}
table.top_info td.text h1 {
display: inline;
padding-right: 5px;
}
table.top_info td.text table.image_row td {
height: 50px;
width: 50px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
opacity: 0.5;
filter: grayscale(80%);
}
table.top_info td.text table.image_row td:hover {
opacity: 1;
filter: grayscale(0%);
}
::-webkit-scrollbar {
width: 8px;
cursor: pointer;
}
::-webkit-scrollbar-track {
background: grey;
background-color: rgba(0,255,255,0.1);
}
::-webkit-scrollbar-thumb {
background-color: rgba(103,85,0,0.7);
}
::-webkit-scrollbar-thumb:hover {
background: gold;
}
[onclick]:hover,
a:hover {
cursor: pointer;
}
div.grisons_bar {
background-color: rgba(0,255,255,0.1);
}
div.grisons_bar > div {
height: 100%;
background-color: rgba(103,85,0,0.7);
}
div.grisons_bar:hover > div {
background-color: gold;
}
a {
color: inherit;
text-decoration: none;
}
a.textlink {
color: yellow;
}
a.hidelink:hover {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}

View File

Before

Width:  |  Height:  |  Size: 866 B

After

Width:  |  Height:  |  Size: 866 B

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,6 +1,6 @@
import urllib
import database
from htmlgenerators import artistLink
from .. import database
from ..htmlgenerators import artistLink
def instructions(keys):

View File

@ -15,7 +15,8 @@ else{for(var key in data){body+=encodeURIComponent(key)+"="+encodeURIComponent(d
xhttp.send(body);console.log("Sent XHTTP request to",url)}
function xhttprequest(url,data={},method="GET",json=true){var p=new Promise(resolve=>xhttpreq(url,data,method,resolve,json));return p;}
function now(){return Math.floor(Date.now()/1000);}
return{getCookie:getCookie,setCookie:setCookie,getCookies:getCookies,saveCookies:saveCookies,xhttpreq:xhttpreq,xhttprequest:xhttprequest,now:now}}();document.addEventListener('DOMContentLoaded',function(){var elements=document.getElementsByClassName("seekable");for(var i=0;i<elements.length;i++){callback=elements[i].getAttribute("data-seekcallback");elements[i].addEventListener("click",function(evt){elmnt=evt.currentTarget;var percentage=evt.offsetX/elmnt.offsetWidth;elmnt.firstElementChild.style.width=(percentage*100)+"%";window[callback](percentage);})}
return{getCookie:getCookie,setCookie:setCookie,getCookies:getCookies,saveCookies:saveCookies,xhttpreq:xhttpreq,xhttprequest:xhttprequest,now:now}}();document.addEventListener('DOMContentLoaded',function(){var elements=document.getElementsByClassName("seekable");for(var i=0;i<elements.length;i++){elements[i].addEventListener("click",function(evt){var elmnt=evt.currentTarget;var percentage=evt.offsetX/elmnt.offsetWidth;percentage=Math.max(0,Math.min(100,percentage));elmnt.firstElementChild.style.width=(percentage*100)+"%";var callback=elmnt.getAttribute("data-seekcallback");window[callback](percentage);})}
var elements=document.getElementsByClassName("scrollseekable");for(var i=0;i<elements.length;i++){elements[i].addEventListener("wheel",function(evt){var elmnt=evt.currentTarget;var currentPercentage=elmnt.firstElementChild.offsetWidth/elmnt.offsetWidth;var sensitivity=elmnt.getAttribute("data-scrollsensitivity")||1;var percentage=currentPercentage-evt.deltaY*sensitivity/1000;percentage=Math.max(0,Math.min(1,percentage));elmnt.firstElementChild.style.width=(percentage*100)+"%";var callback=elmnt.getAttribute("data-seekcallback");window[callback](percentage);})}
var elements2=document.getElementsByClassName("update");var functions=[]
for(var i=0;i<elements2.length;i++){updatefunc=elements2[i].getAttribute("data-updatefrom");functions.push([elements2[i],updatefunc])}
const SMOOTH_UPDATE=true;const update_delay=SMOOTH_UPDATE?40:500;function supervisor(){for(let entry of functions){var[element,func]=entry

View File

Before

Width:  |  Height:  |  Size: 244 B

After

Width:  |  Height:  |  Size: 244 B

View File

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 239 B

View File

Before

Width:  |  Height:  |  Size: 245 B

After

Width:  |  Height:  |  Size: 245 B

View File

Before

Width:  |  Height:  |  Size: 240 B

After

Width:  |  Height:  |  Size: 240 B

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -1,13 +1,13 @@
import urllib
import database
from .. import database
def instructions(keys):
from utilities import getArtistImage, getTrackImage
from htmlgenerators import artistLink, artistLinks, trackLink, scrobblesLink
from urihandler import compose_querystring, uri_to_internal, internal_to_uri
from htmlmodules import module_performance, module_filterselection
from malojatime import range_desc, delimit_desc
from ..utilities import getArtistImage, getTrackImage
from ..htmlgenerators import artistLink, artistLinks, trackLink, scrobblesLink
from ..urihandler import compose_querystring, uri_to_internal, internal_to_uri
from ..htmlmodules import module_performance, module_filterselection
from ..malojatime import range_desc, delimit_desc
filterkeys, timekeys, delimitkeys, paginatekeys = uri_to_internal(keys)

View File

@ -3,8 +3,8 @@ import urllib.request
import hashlib
import xml.etree.ElementTree as ET
from bottle import redirect, request
from database import checkAPIkey
from external import lfmbuild
from ..database import checkAPIkey
from ..external import lfmbuild
def instructions(keys):
authenticated = False

View File

@ -1,13 +1,13 @@
import urllib
import database
from .. import database
def instructions(keys):
from utilities import getArtistImage, getTrackImage
from htmlgenerators import artistLink, artistLinks, trackLink, scrobblesLink
from urihandler import compose_querystring, uri_to_internal, internal_to_uri
from htmlmodules import module_pulse, module_filterselection
from malojatime import range_desc, delimit_desc
from ..utilities import getArtistImage, getTrackImage
from ..htmlgenerators import artistLink, artistLinks, trackLink, scrobblesLink
from ..urihandler import compose_querystring, uri_to_internal, internal_to_uri
from ..htmlmodules import module_pulse, module_filterselection
from ..malojatime import range_desc, delimit_desc
filterkeys, timekeys, delimitkeys, paginatekeys = uri_to_internal(keys)

View File

@ -1,13 +1,13 @@
import urllib
import database
from .. import database
def instructions(keys):
from utilities import getArtistImage, getTrackImage
from htmlgenerators import artistLink, artistLinks, trackLink
from urihandler import compose_querystring, uri_to_internal
from htmlmodules import module_scrobblelist, module_filterselection
from malojatime import range_desc
from ..utilities import getArtistImage, getTrackImage
from ..htmlgenerators import artistLink, artistLinks, trackLink
from ..urihandler import compose_querystring, uri_to_internal
from ..htmlmodules import module_scrobblelist, module_filterselection
from ..malojatime import range_desc
filterkeys, timekeys, _, amountkeys = uri_to_internal(keys)

View File

@ -1,10 +1,10 @@
import urllib
from datetime import datetime, timedelta
import database
from .. import database
from doreah.timing import clock, clockp
from doreah.settings import get_settings
from htmlmodules import module_scrobblelist, module_pulse, module_artistcharts_tiles, module_trackcharts_tiles
from ..htmlmodules import module_scrobblelist, module_pulse, module_artistcharts_tiles, module_trackcharts_tiles
def instructions(keys):
@ -17,7 +17,7 @@ def instructions(keys):
#clock()
from malojatime import today,thisweek,thismonth,thisyear
from ..malojatime import today,thisweek,thismonth,thisyear
# artists

View File

@ -2,11 +2,11 @@ import urllib
def instructions(keys):
from utilities import getArtistImage, getTrackImage
from htmlgenerators import artistLink
from urihandler import compose_querystring, uri_to_internal
from htmlmodules import module_topartists, module_filterselection
from malojatime import range_desc
from ..utilities import getArtistImage, getTrackImage
from ..htmlgenerators import artistLink
from ..urihandler import compose_querystring, uri_to_internal
from ..htmlmodules import module_topartists, module_filterselection
from ..malojatime import range_desc
_, timekeys, delimitkeys, _ = uri_to_internal(keys)

View File

@ -2,11 +2,11 @@ import urllib
def instructions(keys):
from utilities import getArtistImage, getTrackImage
from htmlgenerators import artistLink
from urihandler import compose_querystring, uri_to_internal
from htmlmodules import module_toptracks, module_filterselection
from malojatime import range_desc
from ..utilities import getArtistImage, getTrackImage
from ..htmlgenerators import artistLink
from ..urihandler import compose_querystring, uri_to_internal
from ..htmlmodules import module_toptracks, module_filterselection
from ..malojatime import range_desc
filterkeys, timekeys, delimitkeys, _ = uri_to_internal(keys)

View File

@ -1,13 +1,13 @@
import urllib
import database
from malojatime import today,thisweek,thismonth,thisyear
from .. import database
from ..malojatime import today,thisweek,thismonth,thisyear
def instructions(keys):
from utilities import getArtistImage, getTrackImage
from htmlgenerators import artistLinks
from urihandler import compose_querystring, uri_to_internal
from htmlmodules import module_scrobblelist, module_pulse, module_performance
from ..utilities import getArtistImage, getTrackImage
from ..htmlgenerators import artistLinks
from ..urihandler import compose_querystring, uri_to_internal
from ..htmlmodules import module_scrobblelist, module_pulse, module_performance
filterkeys, _, _, _ = uri_to_internal(keys,forceTrack=True)

Some files were not shown because too many files have changed in this diff Show More