mirror of
https://github.com/krateng/maloja.git
synced 2025-04-18 17:47:37 +03:00
Merge branch 'master' into feature-restructure
This commit is contained in:
commit
4cffc9971d
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1 +1 @@
|
|||||||
custom: ["https://flattr.com/@Krateng", "https://paypal.me/krateng", "bitcoin:1krat8JMniJBTiHftMfR1LtF3Y1w5DAxx"]
|
custom: ["https://flattr.com/@Krateng", "https://paypal.me/krateng"]
|
||||||
|
@ -151,14 +151,13 @@ def main(*args,**kwargs):
|
|||||||
|
|
||||||
if "version" in kwargs:
|
if "version" in kwargs:
|
||||||
print(info.VERSION)
|
print(info.VERSION)
|
||||||
|
return True
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
action, *args = args
|
action, *args = args
|
||||||
action = actions[action]
|
action = actions[action]
|
||||||
except (ValueError, KeyError):
|
except (ValueError, KeyError):
|
||||||
print("Valid commands: " + " ".join(a for a in actions))
|
print("Valid commands: " + " ".join(a for a in actions))
|
||||||
return
|
return False
|
||||||
|
|
||||||
return action(*args,**kwargs)
|
return action(*args,**kwargs)
|
||||||
|
|
||||||
return True
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# you know what f*ck it
|
# you know what f*ck it
|
||||||
# this is hardcoded for now because of that damn project / package name discrepancy
|
# this is hardcoded for now because of that damn project / package name discrepancy
|
||||||
# i'll fix it one day
|
# i'll fix it one day
|
||||||
VERSION = "3.0.0"
|
VERSION = "3.0.2"
|
||||||
HOMEPAGE = "https://github.com/krateng/maloja"
|
HOMEPAGE = "https://github.com/krateng/maloja"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import math
|
||||||
|
|
||||||
from bottle import response, static_file, request, FormsDict
|
from bottle import response, static_file, request, FormsDict
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class DatabaseNotBuilt(HTTPError):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
status=503,
|
status=503,
|
||||||
body="The Maloja Database is being upgraded to Version 3. This could take several minutes.",
|
body="The Maloja Database is being upgraded to Version 3. This could take quite a long time! (~ 2-5 minutes per 10 000 scrobbles)",
|
||||||
headers={"Retry-After":120}
|
headers={"Retry-After":120}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,24 +10,30 @@ from ..pkg_global.conf import data_dir
|
|||||||
|
|
||||||
profiler = cProfile.Profile()
|
profiler = cProfile.Profile()
|
||||||
|
|
||||||
|
FULL_PROFILE = False
|
||||||
|
|
||||||
def profile(func):
|
def profile(func):
|
||||||
def newfunc(*args,**kwargs):
|
def newfunc(*args,**kwargs):
|
||||||
|
|
||||||
benchmarkfolder = data_dir['logs']("benchmarks")
|
if FULL_PROFILE:
|
||||||
os.makedirs(benchmarkfolder,exist_ok=True)
|
benchmarkfolder = data_dir['logs']("benchmarks")
|
||||||
|
os.makedirs(benchmarkfolder,exist_ok=True)
|
||||||
|
|
||||||
clock = Clock()
|
clock = Clock()
|
||||||
clock.start()
|
clock.start()
|
||||||
|
|
||||||
profiler.enable()
|
if FULL_PROFILE:
|
||||||
|
profiler.enable()
|
||||||
result = func(*args,**kwargs)
|
result = func(*args,**kwargs)
|
||||||
profiler.disable()
|
if FULL_PROFILE:
|
||||||
|
profiler.disable()
|
||||||
|
|
||||||
log(f"Executed {func.__name__} ({args}, {kwargs}) in {clock.stop():.2f}s",module="debug_performance")
|
log(f"Executed {func.__name__} ({args}, {kwargs}) in {clock.stop():.2f}s",module="debug_performance")
|
||||||
try:
|
if FULL_PROFILE:
|
||||||
pstats.Stats(profiler).dump_stats(os.path.join(benchmarkfolder,f"{func.__name__}.stats"))
|
try:
|
||||||
except:
|
pstats.Stats(profiler).dump_stats(os.path.join(benchmarkfolder,f"{func.__name__}.stats"))
|
||||||
pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from threading import Thread
|
|||||||
from importlib import resources
|
from importlib import resources
|
||||||
from css_html_js_minify import html_minify, css_minify
|
from css_html_js_minify import html_minify, css_minify
|
||||||
import datauri
|
import datauri
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
# server stuff
|
# server stuff
|
||||||
@ -34,7 +35,7 @@ from .dev.profiler import profile
|
|||||||
|
|
||||||
PORT = malojaconfig["PORT"]
|
PORT = malojaconfig["PORT"]
|
||||||
HOST = malojaconfig["HOST"]
|
HOST = malojaconfig["HOST"]
|
||||||
THREADS = 12
|
THREADS = 16
|
||||||
BaseRequest.MEMFILE_MAX = 15 * 1024 * 1024
|
BaseRequest.MEMFILE_MAX = 15 * 1024 * 1024
|
||||||
|
|
||||||
#STATICFOLDER = importlib.resources.path(__name__,"web/static")
|
#STATICFOLDER = importlib.resources.path(__name__,"web/static")
|
||||||
@ -233,6 +234,7 @@ def static(path):
|
|||||||
|
|
||||||
### DYNAMIC
|
### DYNAMIC
|
||||||
|
|
||||||
|
@profile
|
||||||
def jinja_page(name):
|
def jinja_page(name):
|
||||||
if name in aliases: redirect(aliases[name])
|
if name in aliases: redirect(aliases[name])
|
||||||
keys = remove_identical(FormsDict.decode(request.query))
|
keys = remove_identical(FormsDict.decode(request.query))
|
||||||
@ -292,6 +294,31 @@ def redirect_track(artists,title):
|
|||||||
#####
|
#####
|
||||||
|
|
||||||
|
|
||||||
|
# warning interception
|
||||||
|
import logging
|
||||||
|
|
||||||
|
class WaitressLogHandler():
|
||||||
|
def __init__(self):
|
||||||
|
self.lastwarned = 0
|
||||||
|
self.barrier = 5
|
||||||
|
self.level = 20
|
||||||
|
self.filters = []
|
||||||
|
def handle(self,record):
|
||||||
|
if record.name == 'waitress.queue':
|
||||||
|
now = time.time()
|
||||||
|
depth = record.args[0]
|
||||||
|
|
||||||
|
if depth > self.barrier:
|
||||||
|
log(f"Waitress Task Queue Depth at {depth}")
|
||||||
|
self.lastwarned = now
|
||||||
|
self.barrier = max(depth,self.barrier+5)
|
||||||
|
elif now - self.lastwarned > 5:
|
||||||
|
self.barrier = max(5,self.barrier-5)
|
||||||
|
else:
|
||||||
|
log(f"Waitress: {record.msg % record.args}")
|
||||||
|
logging.getLogger().addHandler(WaitressLogHandler())
|
||||||
|
|
||||||
|
|
||||||
def run_server():
|
def run_server():
|
||||||
log("Starting up Maloja server...")
|
log("Starting up Maloja server...")
|
||||||
|
|
||||||
@ -299,6 +326,7 @@ def run_server():
|
|||||||
Thread(target=database.start_db).start()
|
Thread(target=database.start_db).start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
#run(webserver, host=HOST, port=MAIN_PORT, server='waitress')
|
#run(webserver, host=HOST, port=MAIN_PORT, server='waitress')
|
||||||
log(f"Listening on {HOST}:{PORT}")
|
log(f"Listening on {HOST}:{PORT}")
|
||||||
|
@ -44,7 +44,7 @@ def upgrade_apikeys():
|
|||||||
def upgrade_db(callback_add_scrobbles):
|
def upgrade_db(callback_add_scrobbles):
|
||||||
|
|
||||||
oldfolder = os.path.join(dir_settings['state'],"scrobbles")
|
oldfolder = os.path.join(dir_settings['state'],"scrobbles")
|
||||||
newfolder = os.path.join(dir_settings['state'],".oldscrobbles")
|
newfolder = os.path.join(dir_settings['state'],".v2scrobbles")
|
||||||
os.makedirs(newfolder,exist_ok=True)
|
os.makedirs(newfolder,exist_ok=True)
|
||||||
if os.path.exists(oldfolder):
|
if os.path.exists(oldfolder):
|
||||||
scrobblefiles = [f for f in os.listdir(oldfolder) if f.endswith(".tsv")]
|
scrobblefiles = [f for f in os.listdir(oldfolder) if f.endswith(".tsv")]
|
||||||
@ -67,7 +67,7 @@ def upgrade_db(callback_add_scrobbles):
|
|||||||
scrobblelist = []
|
scrobblelist = []
|
||||||
log(f"\tImporting from {sf} ({idx}/{len(scrobblefiles)}) - {len(scrobbles)} Scrobbles")
|
log(f"\tImporting from {sf} ({idx}/{len(scrobblefiles)}) - {len(scrobbles)} Scrobbles")
|
||||||
for scrobble in scrobbles:
|
for scrobble in scrobbles:
|
||||||
timestamp, artists, title, album, duration = scrobble
|
timestamp, artists, title, album, duration, *_ = scrobble + [None,None]
|
||||||
if album in ('-',''): album = None
|
if album in ('-',''): album = None
|
||||||
if duration in ('-',''): duration = None
|
if duration in ('-',''): duration = None
|
||||||
scrobblelist.append({
|
scrobblelist.append({
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>{% block title %}{% endblock %}</title>
|
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="referrer" content="same-origin" />
|
||||||
|
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
<meta name="description" content='Maloja is a self-hosted music scrobble server.' />
|
<meta name="description" content='Maloja is a self-hosted music scrobble server.' />
|
||||||
|
|
||||||
<meta name="color-scheme" content="dark" />
|
<meta name="color-scheme" content="dark" />
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
With Admin Mode activated, you can:
|
With Admin Mode activated, you can:
|
||||||
<ul>
|
<ul>
|
||||||
<li>manually scrobble from track pages</li>
|
<li>manually scrobble from track pages</li>
|
||||||
|
<li>delete scrobbles</li>
|
||||||
<li>upload artist and track art by dropping a file on the existing image on an artist or track page</li>
|
<li>upload artist and track art by dropping a file on the existing image on an artist or track page</li>
|
||||||
<li>see more detailed error pages</li>
|
<li>see more detailed error pages</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
{% import 'snippets/links.jinja' as links %}
|
{% import 'snippets/links.jinja' as links %}
|
||||||
|
|
||||||
{% if 'artists' in entity %}
|
{% if entity is mapping and 'artists' in entity %}
|
||||||
{% set img = images.get_track_image(entity) %}
|
{% set img = images.get_track_image(entity) %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% set img = images.get_artist_image(entity) %}
|
{% set img = images.get_artist_image(entity) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<td class='icon'><div style="background-image:url('{{ img }}')"></div></td>
|
<td class='icon'><div style="background-image:url('{{ img }}')"></div></td>
|
||||||
{% if "artists" in entity %}
|
{% if entity is mapping and 'artists' in entity %}
|
||||||
{% if settings['TRACK_SEARCH_PROVIDER'] %}
|
{% if settings['TRACK_SEARCH_PROVIDER'] %}
|
||||||
<td class='searchProvider'>{{ links.link_search(entity) }}</td>
|
<td class='searchProvider'>{{ links.link_search(entity) }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{% macro link(entity) -%}
|
{% macro link(entity) -%}
|
||||||
{% if 'artists' in entity %}
|
{% if entity is mapping and 'artists' in entity %}
|
||||||
{% set name = entity.title %}
|
{% set name = entity.title %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% set name = entity %}
|
{% set name = entity %}
|
||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
|
|
||||||
{% macro url(entity) %}
|
{% macro url(entity) %}
|
||||||
{% if 'artists' in entity -%}
|
{% if entity is mapping and 'artists' in entity -%}
|
||||||
{{ mlj_uri.create_uri("/track",{'track':entity}) }}
|
{{ mlj_uri.create_uri("/track",{'track':entity}) }}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{{ mlj_uri.create_uri("/artist",{'artist':entity}) }}
|
{{ mlj_uri.create_uri("/artist",{'artist':entity}) }}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "malojaserver"
|
name = "malojaserver"
|
||||||
version = "3.0.0"
|
version = "3.0.2"
|
||||||
description = "Self-hosted music scrobble database"
|
description = "Self-hosted music scrobble database"
|
||||||
readme = "./README.md"
|
readme = "./README.md"
|
||||||
requires-python = ">=3.6"
|
requires-python = ">=3.6"
|
||||||
@ -21,7 +21,7 @@ classifiers = [
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bottle>=0.12.16",
|
"bottle>=0.12.16",
|
||||||
"waitress>=1.3",
|
"waitress>=1.3",
|
||||||
"doreah>=1.9.0, <2",
|
"doreah>=1.9.1, <2",
|
||||||
"nimrodel>=0.8.0",
|
"nimrodel>=0.8.0",
|
||||||
"setproctitle>=1.1.10",
|
"setproctitle>=1.1.10",
|
||||||
#"pyvips>=2.1.16",
|
#"pyvips>=2.1.16",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user