mirror of
https://github.com/krateng/maloja.git
synced 2025-04-13 15:37:13 +03:00
Merge branch 'newsettings'
This commit is contained in:
commit
e4b63bb570
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,10 +1,12 @@
|
||||
# generic temporary / dev files
|
||||
*.pyc
|
||||
*.sh
|
||||
!/install_*.sh
|
||||
*.note
|
||||
*.xcf
|
||||
nohup.out
|
||||
*-old
|
||||
|
||||
# local actions
|
||||
scripts/*
|
||||
|
||||
# currently not using
|
||||
/screenshot*.png
|
||||
|
@ -136,11 +136,11 @@ to run the server in the foreground.
|
||||
|
||||
### Customization
|
||||
|
||||
* Have a look at the [available settings](settings.md) and specifiy your choices in `/etc/maloja/settings/settings.ini`. You can also set each of these settings as an environment variable with the prefix `MALOJA_` (e.g. `MALOJA_SKIP_SETUP`).
|
||||
* Have a look at the [available settings](settings.md) and specifiy your choices in `/etc/maloja/settings.ini`. You can also set each of these settings as an environment variable with the prefix `MALOJA_` (e.g. `MALOJA_SKIP_SETUP`).
|
||||
|
||||
* If you have activated admin mode in your web interface, you can upload custom images for artists or tracks by simply dragging them onto the existing image on the artist or track page. You can also manage custom images directly in the file system - consult `images.info` in the `/var/lib/maloja/images` folder.
|
||||
|
||||
* To specify custom rules, consult the `rules.info` file in `/etc/maloja/rules`. You can also apply some predefined rules on the `/setup` page of your server.
|
||||
* To specify custom rules, consult the `rules.info` file in `/etc/maloja/rules`. You can also apply some predefined rules on the `/admin_setup` page of your server.
|
||||
|
||||
|
||||
## How to scrobble
|
||||
|
@ -15,7 +15,7 @@ python_version = ">=3.6"
|
||||
requires = [
|
||||
"bottle>=0.12.16",
|
||||
"waitress>=1.3",
|
||||
"doreah>=1.6.12",
|
||||
"doreah>=1.7.1",
|
||||
"nimrodel>=0.7.0",
|
||||
"setproctitle>=1.1.10",
|
||||
"wand>=0.5.4",
|
||||
|
@ -3,7 +3,7 @@ from ._exceptions import *
|
||||
from .. import database
|
||||
import datetime
|
||||
|
||||
from doreah.settings import get_settings
|
||||
from ..globalconf import malojaconfig
|
||||
|
||||
|
||||
class Listenbrainz(APIHandler):
|
||||
@ -72,7 +72,7 @@ class Listenbrainz(APIHandler):
|
||||
if token not in database.allAPIkeys():
|
||||
raise InvalidAuthException()
|
||||
else:
|
||||
return 200,{"code":200,"message":"Token valid.","valid":True,"user_name":get_settings("NAME") or 'Maloja User'}
|
||||
return 200,{"code":200,"message":"Token valid.","valid":True,"user_name":malojaconfig["NAME"]}
|
||||
|
||||
def get_token_from_request_keys(self,keys):
|
||||
if 'token' in keys:
|
||||
|
@ -1,5 +1,5 @@
|
||||
from ..database import *
|
||||
from doreah import settings
|
||||
from ..globalconf import malojaconfig
|
||||
from ..__pkginfo__ import version
|
||||
from ..malojauri import uri_to_internal
|
||||
from .. import utilities
|
||||
@ -41,7 +41,7 @@ def server_info():
|
||||
response.set_header("Content-Type","application/json")
|
||||
|
||||
return {
|
||||
"name":settings.get_settings("NAME"),
|
||||
"name":malojaconfig["NAME"],
|
||||
"version":version,
|
||||
"versionstring":".".join(str(n) for n in version),
|
||||
"db_status":dbstatus
|
||||
@ -61,7 +61,7 @@ def get_scrobbles_external(**keys):
|
||||
offset = (k_amount.get('page') * k_amount.get('perpage')) if k_amount.get('perpage') is not math.inf else 0
|
||||
result = result[offset:]
|
||||
if k_amount.get('perpage') is not math.inf: result = result[:k_amount.get('perpage')]
|
||||
|
||||
|
||||
return {"list":result}
|
||||
|
||||
|
||||
@ -326,3 +326,10 @@ def add_picture(b64,artist:Multi=[],title=None):
|
||||
def newrule(**keys):
|
||||
tsv.add_entry(data_dir['rules']("webmade.tsv"),[k for k in keys])
|
||||
#addEntry("rules/webmade.tsv",[k for k in keys])
|
||||
|
||||
|
||||
@api.post("settings")
|
||||
@authenticated_api
|
||||
def set_settings(**keys):
|
||||
from .. import globalconf
|
||||
globalconf.malojaconfig.update(keys)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import re
|
||||
#from . import utilities
|
||||
from doreah import tsv, settings
|
||||
from .globalconf import data_dir
|
||||
from doreah import tsv
|
||||
from .globalconf import data_dir, malojaconfig
|
||||
import pkg_resources
|
||||
|
||||
# need to do this as a class so it can retain loaded settings from file
|
||||
@ -62,13 +62,13 @@ class CleanerAgent:
|
||||
|
||||
#Delimiters used for extra artists, even when in the title field
|
||||
#delimiters_feat = ["ft.","ft","feat.","feat","featuring","Ft.","Ft","Feat.","Feat","Featuring"]
|
||||
delimiters_feat = settings.get_settings("DELIMITERS_FEAT")
|
||||
delimiters_feat = malojaconfig["DELIMITERS_FEAT"]
|
||||
#Delimiters in informal artist strings, spaces expected around them
|
||||
#delimiters = ["vs.","vs","&"]
|
||||
delimiters = settings.get_settings("DELIMITERS_INFORMAL")
|
||||
delimiters = malojaconfig["DELIMITERS_FEAT"]
|
||||
#Delimiters used specifically to tag multiple artists when only one tag field is available, no spaces used
|
||||
#delimiters_formal = ["; ",";","/"]
|
||||
delimiters_formal = settings.get_settings("DELIMITERS_FORMAL")
|
||||
delimiters_formal = malojaconfig["DELIMITERS_FEAT"]
|
||||
|
||||
def parseArtists(self,a):
|
||||
|
||||
@ -76,7 +76,7 @@ class CleanerAgent:
|
||||
res = [self.parseArtists(art) for art in a]
|
||||
return [a for group in res for a in group]
|
||||
|
||||
if a.strip() in settings.get_settings("INVALID_ARTISTS"):
|
||||
if a.strip() in malojaconfig["DELIMITERS_FEAT"]:
|
||||
return []
|
||||
|
||||
if a.strip().lower() in self.rules_ignoreartist:
|
||||
@ -135,7 +135,7 @@ class CleanerAgent:
|
||||
t = re.sub(r" \(originally by .*?\)","",t)
|
||||
t = re.sub(r" \(.*?Remaster.*?\)","",t)
|
||||
|
||||
for s in settings.get_settings("REMOVE_FROM_TITLE"):
|
||||
for s in malojaconfig["DELIMITERS_FEAT"]:
|
||||
if s in t:
|
||||
t = t.replace(s,"")
|
||||
|
||||
|
0
maloja/data_files/config/.maloja_config_sentinel
Normal file
0
maloja/data_files/config/.maloja_config_sentinel
Normal file
@ -1,100 +0,0 @@
|
||||
# Do not change settings in this file
|
||||
# Instead, simply write an entry with the same name in your own settings.ini file
|
||||
# Category headers in [brackets] are only for organization and not necessary
|
||||
|
||||
[Directories]
|
||||
# DATA_DIRECTORY determines the base directory. It should be specified as environment
|
||||
# variable because this file itself is loaded from it.
|
||||
# Configuration is always in this base directory. Other data defaults to be here
|
||||
# too, but can be customized with the options below.
|
||||
DIRECTORY_STATE = None # This is /var/lib/maloja per XDG
|
||||
DIRECTORY_LOGS = None # this is /var/log/maloja per XDG
|
||||
DIRECTORY_CACHE = None # this is /var/cache/maloja per XDG
|
||||
|
||||
[HTTP]
|
||||
|
||||
WEB_PORT = 42010
|
||||
HOST = "::" # You most likely want either :: for IPv6 or 0.0.0.0 for IPv4 here
|
||||
|
||||
[Login]
|
||||
|
||||
DEFAULT_PASSWORD = none
|
||||
FORCE_PASSWORD = none
|
||||
# these are only meant for Docker containers
|
||||
# on first start, set the environment variable MALOJA_DEFAULT_PASSWORD
|
||||
# if you forgot and already generated a random password, you can overwrite it with MALOJA_FORCE_PASSWORD
|
||||
|
||||
[Third Party Services]
|
||||
|
||||
# order in which to use the metadata providers
|
||||
# keep in mind that musicbrainz is rate-limited and should probably not be used first
|
||||
METADATA_PROVIDERS = [lastfm,spotify,deezer,musicbrainz]
|
||||
# whether to proxy scrobble to other services
|
||||
SCROBBLE_LASTFM = false
|
||||
|
||||
CACHE_EXPIRE_NEGATIVE = 30 # after how many days negative results should be tried again
|
||||
CACHE_EXPIRE_POSITIVE = 300 # after how many days positive results should be refreshed
|
||||
THUMBOR_SERVER = None
|
||||
THUMBOR_SECRET = ""
|
||||
|
||||
# Can be 'YouTube', 'YouTube Music', 'Spotify', 'Tidal', 'SoundCloud', 'Deezer', 'Amazon Music', 'Apple', 'Beatport', 'Bandcamp', 'Qobuz'
|
||||
# Set to None to disable
|
||||
TRACK_SEARCH_PROVIDER = None
|
||||
|
||||
[Database]
|
||||
|
||||
USE_DB_CACHE = yes
|
||||
CACHE_DATABASE_SHORT = true
|
||||
CACHE_DATABASE_PERM = true #more permanent cache for old timeranges
|
||||
DB_CACHE_ENTRIES = 10000 #experiment with this depending on your RAM
|
||||
DB_MAX_MEMORY = 75 # percentage of RAM utilization (whole container, not just maloja) that should trigger a flush
|
||||
INVALID_ARTISTS = ["[Unknown Artist]","Unknown Artist","Spotify"]
|
||||
REMOVE_FROM_TITLE = ["(Original Mix)","(Radio Edit)","(Album Version)","(Explicit Version)","(Bonus Track)"]
|
||||
DELIMITERS_FEAT = ["ft.","ft","feat.","feat","featuring","Ft.","Ft","Feat.","Feat","Featuring"]
|
||||
DELIMITERS_INFORMAL = ["vs.","vs","&"]
|
||||
DELIMITERS_FORMAL = [";","/"]
|
||||
USE_PARSE_PLUGINS = no
|
||||
|
||||
[Local Images]
|
||||
|
||||
USE_LOCAL_IMAGES = true
|
||||
LOCAL_IMAGE_ROTATE = 3600 # when multiple images are present locally, how many seconds we wait between rotation
|
||||
|
||||
[Web Interface]
|
||||
|
||||
# what range is shown per default for the tile view on the start page
|
||||
# can be week, month, year, alltime
|
||||
DEFAULT_RANGE_CHARTS_ARTISTS = year
|
||||
DEFAULT_RANGE_CHARTS_TRACKS = year
|
||||
# same for pulse view
|
||||
# can be day, week, month, year
|
||||
DEFAULT_STEP_PULSE = month
|
||||
|
||||
# display top tiles on artist and track chart pages
|
||||
CHARTS_DISPLAY_TILES = false
|
||||
|
||||
# this does not actually block any requests, it's just an interface feature t
|
||||
# prevent visitors from mindlessly clicking on those options and hogging your cpu
|
||||
DISCOURAGE_CPU_HEAVY_STATS = false
|
||||
|
||||
# Offset in hours to UTC
|
||||
TIMEZONE = 0
|
||||
TIME_FORMAT = "%d. %b %Y %I:%M %p" # use '%H:%M' instead of '%I:%M %p' for 24 hour clock
|
||||
|
||||
[Fluff]
|
||||
|
||||
# how many scrobbles a track needs to aquire this status
|
||||
SCROBBLES_GOLD = 250
|
||||
SCROBBLES_PLATINUM = 500
|
||||
SCROBBLES_DIAMOND = 1000
|
||||
# name for comparisons
|
||||
NAME = None
|
||||
|
||||
[Misc]
|
||||
|
||||
SKIP_SETUP = no
|
||||
LOGGING = true
|
||||
DEV_MODE = false
|
||||
|
||||
# set this to true if your console output will be processed and should never change existing lines
|
||||
CLEAN_OUTPUT = false
|
0
maloja/data_files/logs/.maloja_logs_sentinel
Normal file
0
maloja/data_files/logs/.maloja_logs_sentinel
Normal file
0
maloja/data_files/state/.maloja_state_sentinel
Normal file
0
maloja/data_files/state/.maloja_state_sentinel
Normal file
@ -10,12 +10,11 @@ from .malojauri import uri_to_internal, internal_to_uri, compose_querystring
|
||||
from .thirdparty import proxy_scrobble_all
|
||||
|
||||
from .__pkginfo__ import version
|
||||
from .globalconf import data_dir
|
||||
from .globalconf import data_dir, malojaconfig
|
||||
|
||||
# doreah toolkit
|
||||
from doreah.logging import log
|
||||
from doreah import tsv
|
||||
from doreah import settings
|
||||
from doreah.caching import Cache, DeepCache
|
||||
from doreah.auth import authenticated_api, authenticated_api_with_alternate
|
||||
from doreah.io import ProgressBar
|
||||
@ -283,7 +282,7 @@ def info():
|
||||
artists = {}
|
||||
|
||||
return {
|
||||
"name":settings.get_settings("NAME"),
|
||||
"name":malojaconfig["NAME"],
|
||||
"artists":{
|
||||
chartentry["artist"]:round(chartentry["scrobbles"] * 100 / totalscrobbles,3)
|
||||
for chartentry in get_charts_artists() if chartentry["scrobbles"]/totalscrobbles >= 0
|
||||
@ -476,7 +475,7 @@ def trackInfo(track):
|
||||
scrobbles = c["scrobbles"]
|
||||
position = c["rank"]
|
||||
cert = None
|
||||
threshold_gold, threshold_platinum, threshold_diamond = settings.get_settings("SCROBBLES_GOLD","SCROBBLES_PLATINUM","SCROBBLES_DIAMOND")
|
||||
threshold_gold, threshold_platinum, threshold_diamond = malojaconfig["SCROBBLES_GOLD","SCROBBLES_PLATINUM","SCROBBLES_DIAMOND"]
|
||||
if scrobbles >= threshold_diamond: cert = "diamond"
|
||||
elif scrobbles >= threshold_platinum: cert = "platinum"
|
||||
elif scrobbles >= threshold_gold: cert = "gold"
|
||||
@ -742,7 +741,7 @@ def build_db():
|
||||
scrobblenum = len(db)
|
||||
log(f"Found {scrobblenum} scrobbles...")
|
||||
|
||||
usebar = not settings.get_settings("CLEAN_OUTPUT")
|
||||
usebar = not malojaconfig["CLEAN_OUTPUT"]
|
||||
if usebar: pbar = ProgressBar(max=scrobblenum,prefix="Loading scrobbles")
|
||||
else:
|
||||
n = 0
|
||||
@ -860,7 +859,7 @@ def sync():
|
||||
|
||||
import copy
|
||||
|
||||
if settings.get_settings("USE_DB_CACHE"):
|
||||
if malojaconfig["USE_DB_CACHE"]:
|
||||
def db_query(**kwargs):
|
||||
return db_query_cached(**kwargs)
|
||||
def db_aggregate(**kwargs):
|
||||
@ -872,8 +871,8 @@ else:
|
||||
return db_aggregate_full(**kwargs)
|
||||
|
||||
|
||||
csz = settings.get_settings("DB_CACHE_ENTRIES")
|
||||
cmp = settings.get_settings("DB_MAX_MEMORY")
|
||||
csz = malojaconfig["DB_CACHE_ENTRIES"]
|
||||
cmp = malojaconfig["DB_MAX_MEMORY"]
|
||||
try:
|
||||
import psutil
|
||||
use_psutil = True
|
||||
@ -885,8 +884,8 @@ cache_query_perm = lru.LRU(csz)
|
||||
cache_aggregate = lru.LRU(csz)
|
||||
cache_aggregate_perm = lru.LRU(csz)
|
||||
|
||||
perm_caching = settings.get_settings("CACHE_DATABASE_PERM")
|
||||
temp_caching = settings.get_settings("CACHE_DATABASE_SHORT")
|
||||
perm_caching = malojaconfig["CACHE_DATABASE_PERM"]
|
||||
temp_caching = malojaconfig["CACHE_DATABASE_SHORT"]
|
||||
|
||||
cachestats = {
|
||||
"cache_query":{
|
||||
|
@ -1,8 +1,8 @@
|
||||
import os
|
||||
from doreah.settings import get_settings
|
||||
from doreah.settings import config as settingsconfig
|
||||
from doreah.configuration import Configuration
|
||||
from doreah.configuration import types as tp
|
||||
|
||||
pthj = os.path.join
|
||||
|
||||
|
||||
# if DATA_DIRECTORY is specified, this is the directory to use for EVERYTHING, no matter what
|
||||
@ -17,102 +17,233 @@ pthj = os.path.join
|
||||
# if not, use the first we have permissions for
|
||||
# after we decide which to use, fix it in settings to avoid future heuristics
|
||||
|
||||
try:
|
||||
HOME_DIR = os.environ["XDG_DATA_HOME"].split(":")[0]
|
||||
assert os.path.exists(HOME_DIR)
|
||||
except:
|
||||
HOME_DIR = os.path.join(os.environ["HOME"],".local/share/")
|
||||
usrfol = pthj(HOME_DIR,"maloja")
|
||||
etccfg = '/etc/maloja'
|
||||
varlib = '/var/lib/maloja'
|
||||
varcac = '/var/cache/maloja'
|
||||
varlog = '/var/log/maloja'
|
||||
# USEFUL FUNCS
|
||||
pthj = os.path.join
|
||||
|
||||
dir_settings = {
|
||||
"config":None,
|
||||
"state":None,
|
||||
"logs":None,
|
||||
"cache":None,
|
||||
# "clients":None,
|
||||
# "rules":None,
|
||||
# "settings":None,
|
||||
# "auth":None,
|
||||
# "backups":None,
|
||||
# "images":None,
|
||||
# "scrobbles":None,
|
||||
# "logs":None,
|
||||
# "cache":None
|
||||
def is_dir_usable(pth):
|
||||
try:
|
||||
os.makedirs(pth,exist_ok=True)
|
||||
os.mknod(pthj(pth,".test"))
|
||||
os.remove(pthj(pth,".test"))
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_env_vars(key,pathsuffix=[]):
|
||||
return [pthj(pth,*pathsuffix) for pth in os.environ.get(key,'').split(':') if pth != '']
|
||||
|
||||
|
||||
|
||||
directory_info = {
|
||||
"config":{
|
||||
"sentinel":"rules",
|
||||
"possible_folders":[
|
||||
"/etc/maloja",
|
||||
os.path.expanduser("~/.local/share/maloja")
|
||||
],
|
||||
"setting":"directory_config"
|
||||
},
|
||||
"cache":{
|
||||
"sentinel":"dummy",
|
||||
"possible_folders":[
|
||||
"/var/cache/maloja",
|
||||
os.path.expanduser("~/.local/share/maloja/cache")
|
||||
],
|
||||
"setting":"directory_cache"
|
||||
},
|
||||
"state":{
|
||||
"sentinel":"scrobbles",
|
||||
"possible_folders":[
|
||||
"/var/lib/maloja",
|
||||
os.path.expanduser("~/.local/share/maloja")
|
||||
],
|
||||
"setting":"directory_state"
|
||||
},
|
||||
"logs":{
|
||||
"sentinel":"dbfix",
|
||||
"possible_folders":[
|
||||
"/var/log/maloja",
|
||||
os.path.expanduser("~/.local/share/maloja/logs")
|
||||
],
|
||||
"setting":"directory_logs"
|
||||
}
|
||||
}
|
||||
|
||||
dir_options = {
|
||||
"config":[
|
||||
"/etc/maloja",
|
||||
usrfol
|
||||
],
|
||||
"state":[
|
||||
"/var/lib/maloja",
|
||||
"/etc/maloja",
|
||||
usrfol
|
||||
],
|
||||
"logs":[
|
||||
"/var/log/maloja",
|
||||
"/etc/maloja/logs",
|
||||
pthj(usrfol,"logs")
|
||||
],
|
||||
"cache":[
|
||||
"/var/cache/maloja",
|
||||
"/etc/maloja/cache",
|
||||
pthj(usrfol,"cache")
|
||||
]
|
||||
}
|
||||
# function that
|
||||
# 1) checks if folder has been specified by user
|
||||
# 2) if not, checks if one has been in use before and writes it to dict/config
|
||||
# 3) if not, determines which to use and writes it to dict/config
|
||||
# returns determined folder
|
||||
def find_good_folder(datatype,configobject):
|
||||
info = directory_info[datatype]
|
||||
|
||||
sentinels = {
|
||||
"config":"settings",
|
||||
"state":"scrobbles",
|
||||
"logs":None,
|
||||
"cache":None,
|
||||
}
|
||||
# check each possible folder if its used
|
||||
for p in info['possible_folders']:
|
||||
if os.path.exists(pthj(p,info['sentinel'])):
|
||||
#print(p,"has been determined as maloja's folder for",datatype)
|
||||
configobject[info['setting']] = p
|
||||
return p
|
||||
|
||||
# check environ variables
|
||||
stng_data = get_settings("DATA_DIRECTORY",files=[],environ_prefix="MALOJA_")
|
||||
if stng_data is not None:
|
||||
dir_settings['config'] = stng_data
|
||||
dir_settings['state'] = stng_data
|
||||
dir_settings['cache'] = pthj(stng_data,'cache')
|
||||
dir_settings['logs'] = pthj(stng_data,'logs')
|
||||
#print("Could not find previous",datatype,"folder")
|
||||
# check which one we can use
|
||||
for p in info['possible_folders']:
|
||||
if is_dir_usable(p):
|
||||
#print(p,"has been selected as maloja's folder for",datatype)
|
||||
configobject[info['setting']] = p
|
||||
return p
|
||||
#print("No folder can be used for",datatype)
|
||||
#print("This should not happen!")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### STEP 1 - find out where the settings file is
|
||||
# environment variables
|
||||
maloja_dir_config = os.environ.get("MALOJA_DATA_DIRECTORY") or os.environ.get("MALOJA_DIRECTORY_CONFIG")
|
||||
|
||||
|
||||
if maloja_dir_config is None:
|
||||
maloja_dir_config = find_good_folder('config',{})
|
||||
found_new_config_dir = True
|
||||
else:
|
||||
dir_settings['config'], dir_settings['state'], dir_settings['cache'], dir_settings['logs'] = get_settings("DIRECTORY_CONFIG","DIRECTORY_STATE","DIRECTORY_LOGS","DIRECTORY_CACHE",files=[],environ_prefix="MALOJA_")
|
||||
# as soon as we know the config directory, we can load from settings file
|
||||
if dir_settings['config'] is not None:
|
||||
settingsfiles = [pthj(dir_settings['config'],'settings','default.ini'),pthj(dir_settings['config'],'settings','settings.ini')]
|
||||
dir_settings['config'], dir_settings['state'], dir_settings['cache'], dir_settings['logs'] = get_settings("DIRECTORY_CONFIG","DIRECTORY_STATE","DIRECTORY_LOGS","DIRECTORY_CACHE",files=settingsfiles,environ_prefix="MALOJA_")
|
||||
found_new_config_dir = False
|
||||
# remember whether we had to find our config dir or it was user-specified
|
||||
|
||||
oldsettingsfile = pthj(maloja_dir_config,"settings","settings.ini")
|
||||
newsettingsfile = pthj(maloja_dir_config,"settings.ini")
|
||||
|
||||
if os.path.exists(oldsettingsfile):
|
||||
os.rename(oldsettingsfile,newsettingsfile)
|
||||
|
||||
|
||||
# now to the stuff no setting has explicitly defined
|
||||
for dirtype in dir_settings:
|
||||
if dir_settings[dirtype] is None:
|
||||
for option in dir_options[dirtype]:
|
||||
if os.path.exists(option):
|
||||
# check if this is really the directory used for this category (/etc/maloja could be used for state or just config)
|
||||
if sentinels[dirtype] is None or os.path.exists(pthj(option,sentinels[dirtype])):
|
||||
dir_settings[dirtype] = option
|
||||
break
|
||||
|
||||
# if no directory seems to exist, use the first writable one
|
||||
for dirtype in dir_settings:
|
||||
if dir_settings[dirtype] is None:
|
||||
for option in dir_options[dirtype]:
|
||||
try:
|
||||
os.makedirs(option,exist_ok=True)
|
||||
os.mknod(pthj(option,".test"))
|
||||
os.remove(pthj(option,".test"))
|
||||
dir_settings[dirtype] = option
|
||||
break
|
||||
except:
|
||||
pass
|
||||
### STEP 2 - create settings object
|
||||
|
||||
|
||||
assert all((dir_settings[s] is not None) for s in dir_settings)
|
||||
malojaconfig = Configuration(
|
||||
settings={
|
||||
"Setup":{
|
||||
"data_directory":(tp.String(), "Data Directory", None, "Folder for all user data. Overwrites all choices for specific directories."),
|
||||
"directory_config":(tp.String(), "Config Directory", "/etc/maloja", "Folder for config data. Only applied when global data directory is not set."),
|
||||
"directory_state":(tp.String(), "State Directory", "/var/lib/maloja", "Folder for state data. Only applied when global data directory is not set."),
|
||||
"directory_logs":(tp.String(), "Log Directory", "/var/log/maloja", "Folder for log data. Only applied when global data directory is not set."),
|
||||
"directory_cache":(tp.String(), "Cache Directory", "/var/cache/maloja", "Folder for cache data. Only applied when global data directory is not set."),
|
||||
"skip_setup":(tp.Boolean(), "Skip Setup", False, "Make server setup process non-interactive. Vital for Docker."),
|
||||
"force_password":(tp.String(), "Force Password", None, "On startup, overwrite admin password with this one. This should usually only be done via environment variable in Docker."),
|
||||
"clean_output":(tp.Boolean(), "Avoid Mutable Console Output", False, "Use if console output will be redirected e.g. to a web interface.")
|
||||
},
|
||||
"Debug":{
|
||||
"logging":(tp.Boolean(), "Enable Logging", True),
|
||||
"dev_mode":(tp.Boolean(), "Enable developer mode", False),
|
||||
},
|
||||
"Network":{
|
||||
"host":(tp.String(), "Host", "::", "Host for your server - most likely :: for IPv6 or 0.0.0.0 for IPv4"),
|
||||
"port":(tp.Integer(), "Port", 42010),
|
||||
},
|
||||
"Technical":{
|
||||
"cache_expire_positive":(tp.Integer(), "Image Cache Expiration", 300, "Days until images are refetched"),
|
||||
"cache_expire_negative":(tp.Integer(), "Image Cache Negative Expiration", 30, "Days until failed image fetches are reattempted"),
|
||||
"use_db_cache":(tp.Boolean(), "Use DB Cache", True),
|
||||
"cache_database_short":(tp.Boolean(), "Use volatile Database Cache", True),
|
||||
"cache_database_perm":(tp.Boolean(), "Use permanent Database Cache", True),
|
||||
"db_cache_entries":(tp.Integer(), "Maximal Cache entries", 10000),
|
||||
"db_max_memory":(tp.Integer(max=100,min=20), "RAM Percentage Theshold", 75, "Maximal percentage of RAM that should be used by whole system before Maloja discards cache entries. Use a higher number if your Maloja runs on a dedicated instance (e.g. a container)")
|
||||
},
|
||||
"Fluff":{
|
||||
"scrobbles_gold":(tp.Integer(), "Scrobbles for Gold", 250, "How many scrobbles a track needs to be considered 'Gold' status"),
|
||||
"scrobbles_platinum":(tp.Integer(), "Scrobbles for Platinum", 500, "How many scrobbles a track needs to be considered 'Platinum' status"),
|
||||
"scrobbles_diamond":(tp.Integer(), "Scrobbles for Diamond", 1000, "How many scrobbles a track needs to be considered 'Diamond' status"),
|
||||
"name":(tp.String(), "Name", "Generic Maloja User")
|
||||
},
|
||||
"Third Party Services":{
|
||||
"metadata_providers":(tp.List(tp.String()), "Metadata Providers", ['lastfm','spotify','deezer','musicbrainz'], "Which metadata providers should be used in what order. Musicbrainz is rate-limited and should not be used first."),
|
||||
"scrobble_lastfm":(tp.Boolean(), "Proxy-Scrobble to Last.fm", False),
|
||||
"lastfm_api_key":(tp.String(), "Last.fm API Key", None),
|
||||
"lastfm_api_secret":(tp.String(), "Last.fm API Secret", None),
|
||||
"spotify_api_id":(tp.String(), "Spotify API ID", None),
|
||||
"spotify_api_secret":(tp.String(), "Spotify API Secret", None),
|
||||
"lastfm_api_key":(tp.String(), "Last.fm API Key", None),
|
||||
"audiodb_api_key":(tp.String(), "TheAudioDB API Key", None),
|
||||
"track_search_provider":(tp.String(), "Track Search Provider", None),
|
||||
"send_stats":(tp.Boolean(), "Send Statistics", None),
|
||||
|
||||
},
|
||||
"Database":{
|
||||
"invalid_artists":(tp.Set(tp.String()), "Invalid Artists", ["[Unknown Artist]","Unknown Artist","Spotify"], "Artists that should be discarded immediately"),
|
||||
"remove_from_title":(tp.Set(tp.String()), "Remove from Title", ["(Original Mix)","(Radio Edit)","(Album Version)","(Explicit Version)","(Bonus Track)"], "Phrases that should be removed from song titles"),
|
||||
"delimiters_feat":(tp.Set(tp.String()), "Featuring Delimiters", ["ft.","ft","feat.","feat","featuring","Ft.","Ft","Feat.","Feat","Featuring"], "Delimiters used for extra artists, even when in the title field"),
|
||||
"delimiters_informal":(tp.Set(tp.String()), "Informal Delimiters", ["vs.","vs","&"], "Delimiters in informal artist strings with spaces expected around them"),
|
||||
"delimiters_formal":(tp.Set(tp.String()), "Formal Delimiters", [";","/"], "Delimiters used to tag multiple artists when only one tag field is available")
|
||||
},
|
||||
"Web Interface":{
|
||||
"default_range_charts_artists":(tp.Choice({'alltime':'All Time','year':'Year','month':"Month",'week':'Week'}), "Default Range Artist Charts", "year"),
|
||||
"default_range_charts_tracks":(tp.Choice({'alltime':'All Time','year':'Year','month':"Month",'week':'Week'}), "Default Range Track Charts", "year"),
|
||||
"default_step_pulse":(tp.Choice({'year':'Year','month':"Month",'week':'Week','day':'Day'}), "Default Pulse Step", "month"),
|
||||
"charts_display_tiles":(tp.Boolean(), "Display Chart Tiles", False),
|
||||
"discourage_cpu_heavy_stats":(tp.Boolean(), "Discourage CPU-heavy stats", False, "Prevent visitors from mindlessly clicking on CPU-heavy options. Does not actually disable them for malicious actors!"),
|
||||
"use_local_images":(tp.Boolean(), "Use Local Images", True),
|
||||
"local_image_rotate":(tp.Integer(), "Local Image Rotate", 3600),
|
||||
"timezone":(tp.Integer(), "UTC Offset", 0),
|
||||
"time_format":(tp.String(), "Time Format", "%d. %b %Y %I:%M %p")
|
||||
}
|
||||
},
|
||||
configfile=newsettingsfile,
|
||||
save_endpoint="/apis/mlj_1/settings",
|
||||
env_prefix="MALOJA_"
|
||||
|
||||
)
|
||||
|
||||
if found_new_config_dir:
|
||||
malojaconfig["DIRECTORY_CONFIG"] = maloja_dir_config
|
||||
# this really doesn't matter because when are we gonna load info about where
|
||||
# the settings file is stored from the settings file
|
||||
# but oh well
|
||||
|
||||
malojaconfig.render_help(pthj(maloja_dir_config,"settings.md"),
|
||||
top_text='''If you wish to adjust settings in the settings.ini file, do so while the server
|
||||
is not running in order to avoid data being overwritten.
|
||||
|
||||
Technically, each setting can be set via environment variable or the settings
|
||||
file - simply add the prefix `MALOJA_` for environment variables. It is recommended
|
||||
to use the settings file where possible and not configure each aspect of your
|
||||
server via environment variables!''')
|
||||
|
||||
|
||||
### STEP 3 - check all possible folders for files (old installation)
|
||||
|
||||
|
||||
|
||||
|
||||
for datatype in ("state","cache","logs"):
|
||||
# obviously default values shouldn't trigger this
|
||||
# if user has nothing specified, we need to use this
|
||||
if malojaconfig.get_specified(directory_info[datatype]['setting']) is None and malojaconfig.get_specified('DATA_DIRECTORY') is None:
|
||||
find_good_folder(datatype,malojaconfig)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### STEP 4 - this is where all the guessing about previous installation ends
|
||||
### we have our definite settings and are now just generating the real
|
||||
### folder names for everything
|
||||
|
||||
|
||||
if malojaconfig['DATA_DIRECTORY'] is None:
|
||||
dir_settings = {
|
||||
"config":malojaconfig['DIRECTORY_CONFIG'],
|
||||
"state":malojaconfig['DIRECTORY_STATE'],
|
||||
"cache":malojaconfig['DIRECTORY_CACHE'],
|
||||
"logs":malojaconfig['DIRECTORY_LOGS'],
|
||||
}
|
||||
else:
|
||||
dir_settings = {
|
||||
"config":malojaconfig['DATA_DIRECTORY'],
|
||||
"state":malojaconfig['DATA_DIRECTORY'],
|
||||
"cache":pthj(malojaconfig['DATA_DIRECTORY'],"cache"),
|
||||
"logs":pthj(malojaconfig['DATA_DIRECTORY'],"logs"),
|
||||
}
|
||||
|
||||
|
||||
data_directories = {
|
||||
@ -122,7 +253,7 @@ data_directories = {
|
||||
"scrobbles":pthj(dir_settings['state'],"scrobbles"),
|
||||
"rules":pthj(dir_settings['config'],"rules"),
|
||||
"clients":pthj(dir_settings['config'],"clients"),
|
||||
"settings":pthj(dir_settings['config'],"settings"),
|
||||
"settings":pthj(dir_settings['config']),
|
||||
"css":pthj(dir_settings['config'],"custom_css"),
|
||||
"logs":pthj(dir_settings['logs']),
|
||||
"cache":pthj(dir_settings['cache']),
|
||||
@ -142,13 +273,6 @@ data_dir = {
|
||||
from doreah import config
|
||||
|
||||
config(
|
||||
settings={
|
||||
"files":[
|
||||
data_dir['settings']("default.ini"),
|
||||
data_dir['settings']("settings.ini")
|
||||
],
|
||||
"environ_prefix":"MALOJA_"
|
||||
},
|
||||
caching={
|
||||
"folder": data_dir['cache']()
|
||||
},
|
||||
@ -157,36 +281,19 @@ config(
|
||||
"cookieprefix":"maloja",
|
||||
"stylesheets":["/style.css"],
|
||||
"dbfile":data_dir['auth']("auth.ddb")
|
||||
}
|
||||
)
|
||||
|
||||
# because we loaded a doreah module already before setting the config, we need to to that manually
|
||||
settingsconfig._readpreconfig()
|
||||
|
||||
config(
|
||||
},
|
||||
logging={
|
||||
"logfolder": data_dir['logs']() if get_settings("LOGGING") else None
|
||||
"logfolder": data_dir['logs']() if malojaconfig["LOGGING"] else None
|
||||
},
|
||||
regular={
|
||||
"autostart": False,
|
||||
"offset": get_settings("TIMEZONE") or 0
|
||||
"offset": malojaconfig["TIMEZONE"]
|
||||
}
|
||||
)
|
||||
|
||||
settingsconfig._readpreconfig()
|
||||
|
||||
|
||||
|
||||
# thumbor
|
||||
|
||||
THUMBOR_SERVER, THUMBOR_SECRET = get_settings("THUMBOR_SERVER","THUMBOR_SECRET")
|
||||
try:
|
||||
USE_THUMBOR = THUMBOR_SERVER is not None and THUMBOR_SECRET is not None
|
||||
if USE_THUMBOR:
|
||||
from libthumbor import CryptoURL
|
||||
THUMBOR_GENERATOR = CryptoURL(key=THUMBOR_SECRET)
|
||||
OWNURL = get_settings("PUBLIC_URL")
|
||||
assert OWNURL is not None
|
||||
except:
|
||||
USE_THUMBOR = False
|
||||
log("Thumbor could not be initialized. Is libthumbor installed?")
|
||||
# what the fuck did i just write
|
||||
# this spaghetti file is proudly sponsored by the rice crackers i'm eating at the
|
||||
# moment as well as some cute chinese girl whose asmr i'm listening to in the
|
||||
# background. and now to bed!
|
||||
|
@ -1,8 +1,8 @@
|
||||
from .. import database_packed
|
||||
from . import filters
|
||||
from ..globalconf import malojaconfig
|
||||
|
||||
from .. import database, database_packed, malojatime, utilities, malojauri
|
||||
from doreah import settings
|
||||
from doreah.regular import repeatdaily
|
||||
|
||||
import urllib
|
||||
@ -30,7 +30,7 @@ def update_jinja_environment():
|
||||
"malojatime": malojatime,
|
||||
"utilities": utilities,
|
||||
"mlj_uri": malojauri,
|
||||
"settings": settings.get_settings,
|
||||
"settings": malojaconfig,
|
||||
# external
|
||||
"urllib": urllib,
|
||||
"math":math,
|
||||
|
@ -2,10 +2,11 @@ from datetime import timezone, timedelta, date, time, datetime
|
||||
from calendar import monthrange
|
||||
from os.path import commonprefix
|
||||
import math
|
||||
from doreah.settings import get_settings
|
||||
|
||||
from .globalconf import malojaconfig
|
||||
|
||||
|
||||
OFFSET = get_settings("TIMEZONE")
|
||||
OFFSET = malojaconfig["TIMEZONE"]
|
||||
TIMEZONE = timezone(timedelta(hours=OFFSET))
|
||||
UTC = timezone.utc
|
||||
|
||||
@ -486,7 +487,7 @@ def timestamp_desc(t,short=False):
|
||||
|
||||
timeobj = datetime.fromtimestamp(t,tz=TIMEZONE)
|
||||
|
||||
if not short: return timeobj.strftime(get_settings("TIME_FORMAT"))
|
||||
if not short: return timeobj.strftime(malojaconfig["TIME_FORMAT"])
|
||||
|
||||
difference = int(datetime.now().timestamp() - t)
|
||||
|
||||
|
@ -47,7 +47,7 @@ def start():
|
||||
sp = subprocess.Popen(["python3","-m","maloja.proccontrol.supervisor"],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
|
||||
print(col["green"]("Maloja started!"))
|
||||
|
||||
port = settings.get_settings("WEB_PORT")
|
||||
port = malojaconfig["WEB_PORT"]
|
||||
|
||||
print("Visit your server address (Port " + str(port) + ") to see your web interface. Visit /admin_setup to get started.")
|
||||
print("If you're installing this on your local machine, these links should get you there:")
|
||||
|
@ -1,11 +1,10 @@
|
||||
import pkg_resources
|
||||
from distutils import dir_util
|
||||
from doreah import settings
|
||||
from doreah.io import col, ask, prompt
|
||||
from doreah import auth
|
||||
import os
|
||||
|
||||
from ..globalconf import data_dir, dir_settings
|
||||
from ..globalconf import data_dir, dir_settings, malojaconfig
|
||||
|
||||
|
||||
# EXTERNAL API KEYS
|
||||
@ -32,19 +31,19 @@ def randomstring(length=32):
|
||||
def setup():
|
||||
|
||||
copy_initial_local_files()
|
||||
SKIP = settings.get_settings("SKIP_SETUP")
|
||||
SKIP = malojaconfig["SKIP_SETUP"]
|
||||
|
||||
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)
|
||||
key = malojaconfig[k]
|
||||
if key is False:
|
||||
print("\t" + "Currently not using a " + apikeys[k] + " for image display.")
|
||||
print("\t" + "Currently not using a " + col['red'](apikeys[k]) + " for image display.")
|
||||
elif key is None or key == "ASK":
|
||||
print("\t" + "Please enter your " + col['gold'](apikeys[k]) + ". If you do not want to use one at this moment, simply leave this empty and press Enter.")
|
||||
key = prompt("",types=(str,),default=False,skip=SKIP)
|
||||
settings.update_settings(data_dir['settings']("settings.ini"),{k:key},create_new=True)
|
||||
malojaconfig[k] = key
|
||||
else:
|
||||
print("\t" + apikeys[k] + " found.")
|
||||
print("\t" + col['lawngreen'](apikeys[k]) + " found.")
|
||||
|
||||
|
||||
# OWN API KEY
|
||||
@ -57,8 +56,7 @@ def setup():
|
||||
keyfile.write(key + "\t" + "Default Generated Key")
|
||||
|
||||
# PASSWORD
|
||||
defaultpassword = settings.get_settings("DEFAULT_PASSWORD")
|
||||
forcepassword = settings.get_settings("FORCE_PASSWORD")
|
||||
forcepassword = malojaconfig["FORCE_PASSWORD"]
|
||||
# this is mainly meant for docker, supply password via environment variable
|
||||
|
||||
if forcepassword is not None:
|
||||
@ -67,25 +65,17 @@ def setup():
|
||||
print("Password has been set.")
|
||||
elif auth.defaultuser.checkpw("admin"):
|
||||
# if the actual pw is admin, it means we've never set this up properly (eg first start after update)
|
||||
if defaultpassword is None:
|
||||
# non-docker installation or user didn't set environment variable
|
||||
defaultpassword = randomstring(32)
|
||||
newpw = prompt("Please set a password for web backend access. Leave this empty to generate a random password.",skip=SKIP,secret=True)
|
||||
if newpw is None:
|
||||
newpw = defaultpassword
|
||||
print("Generated password:",newpw)
|
||||
else:
|
||||
# docker installation (or settings file, but don't do that)
|
||||
# we still 'ask' the user to set one, but for docker this will be skipped
|
||||
newpw = prompt("Please set a password for web backend access. Leave this empty to use the default password.",skip=SKIP,default=defaultpassword,secret=True)
|
||||
auth.defaultuser.setpw(newpw)
|
||||
if settings.get_settings("NAME") is None:
|
||||
name = prompt("Please enter your name. This will be displayed e.g. when comparing your charts to another user. Leave this empty if you would not like to specify a name right now.",default="Generic Maloja User",skip=SKIP)
|
||||
settings.update_settings(data_dir['settings']("settings.ini"),{"NAME":name},create_new=True)
|
||||
newpw = prompt("Please set a password for web backend access. Leave this empty to generate a random password.",skip=SKIP,secret=True)
|
||||
if newpw is None:
|
||||
newpw = randomstring(32)
|
||||
print("Generated password:",newpw)
|
||||
|
||||
if settings.get_settings("SEND_STATS") is None:
|
||||
auth.defaultuser.setpw(newpw)
|
||||
|
||||
if malojaconfig["SEND_STATS"] is None:
|
||||
answer = ask("I would like to know how many people use Maloja. Would it be okay to send a daily ping to my server (this contains no data that isn't accessible via your web interface already)?",default=True,skip=SKIP)
|
||||
if answer:
|
||||
settings.update_settings(data_dir['settings']("settings.ini"),{"SEND_STATS":True,"PUBLIC_URL":None},create_new=True)
|
||||
malojaconfig["SEND_STATS"] = True
|
||||
malojaconfig["PUBLIC_URL"] = None
|
||||
else:
|
||||
settings.update_settings(data_dir['settings']("settings.ini"),{"SEND_STATS":False},create_new=True)
|
||||
malojaconfig["SEND_STATS"] = False
|
||||
|
@ -5,8 +5,8 @@ import subprocess
|
||||
import setproctitle
|
||||
import signal
|
||||
from doreah.logging import log
|
||||
from doreah.settings import get_settings
|
||||
|
||||
from .globalconf import malojaconfig
|
||||
from .control import getInstance
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ def start():
|
||||
|
||||
while True:
|
||||
log("Maloja is not running, starting...",module="supervisor")
|
||||
if get_settings("UPDATE_AFTER_CRASH"):
|
||||
if malojaconfig["UPDATE_AFTER_CRASH"]:
|
||||
update()
|
||||
process = start()
|
||||
|
||||
|
@ -17,10 +17,10 @@ from . import malojauri
|
||||
from .utilities import resolveImage
|
||||
from .malojauri import uri_to_internal, remove_identical, compose_querystring
|
||||
from . import globalconf
|
||||
from .globalconf import malojaconfig
|
||||
from .jinjaenv.context import jinja_environment
|
||||
from jinja2.exceptions import TemplateNotFound
|
||||
# doreah toolkit
|
||||
from doreah import settings
|
||||
from doreah.logging import log
|
||||
from doreah.timing import Clock
|
||||
from doreah import auth
|
||||
@ -43,11 +43,8 @@ import urllib
|
||||
### TECHNICAL SETTINGS
|
||||
#####
|
||||
|
||||
|
||||
#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")
|
||||
PORT = malojaconfig["PORT"]
|
||||
HOST = malojaconfig["HOST"]
|
||||
THREADS = 24
|
||||
BaseRequest.MEMFILE_MAX = 15 * 1024 * 1024
|
||||
|
||||
@ -87,8 +84,10 @@ css = generate_css()
|
||||
#####
|
||||
|
||||
def clean_html(inp):
|
||||
if settings.get_settings("DEV_MODE"): return inp
|
||||
else: return html_minify(inp)
|
||||
return inp
|
||||
|
||||
#if malojaconfig["DEV_MODE"]: return inp
|
||||
#else: return html_minify(inp)
|
||||
|
||||
|
||||
|
||||
@ -215,7 +214,7 @@ def static_image(pth):
|
||||
def get_css():
|
||||
response.content_type = 'text/css'
|
||||
global css
|
||||
if settings.get_settings("DEV_MODE"): css = generate_css()
|
||||
if malojaconfig["DEV_MODE"]: css = generate_css()
|
||||
return css
|
||||
|
||||
|
||||
@ -247,6 +246,7 @@ def static_html(name):
|
||||
|
||||
LOCAL_CONTEXT = {
|
||||
"adminmode":adminmode,
|
||||
"config":malojaconfig,
|
||||
"apikey":request.cookies.get("apikey") if adminmode else None,
|
||||
"_urikeys":keys, #temporary!
|
||||
}
|
||||
@ -259,7 +259,7 @@ def static_html(name):
|
||||
except (ValueError, IndexError) as e:
|
||||
abort(404,"This Artist or Track does not exist")
|
||||
|
||||
if settings.get_settings("DEV_MODE"): jinja_environment.cache.clear()
|
||||
if malojaconfig["DEV_MODE"]: jinja_environment.cache.clear()
|
||||
|
||||
log("Generated page {name} in {time:.5f}s".format(name=name,time=clock.stop()),module="debug_performance")
|
||||
return clean_html(res)
|
||||
@ -326,7 +326,7 @@ def run_server():
|
||||
|
||||
try:
|
||||
#run(webserver, host=HOST, port=MAIN_PORT, server='waitress')
|
||||
waitress.serve(webserver, host=HOST, port=MAIN_PORT, threads=THREADS)
|
||||
waitress.serve(webserver, host=HOST, port=PORT, threads=THREADS)
|
||||
except OSError:
|
||||
log("Error. Is another Maloja process already running?")
|
||||
raise
|
||||
|
12
maloja/thirdparty/__init__.py
vendored
12
maloja/thirdparty/__init__.py
vendored
@ -10,9 +10,9 @@ import xml.etree.ElementTree as ElementTree
|
||||
import json
|
||||
import urllib.parse, urllib.request
|
||||
import base64
|
||||
from doreah.settings import get_settings
|
||||
from doreah.logging import log
|
||||
|
||||
from ..globalconf import malojaconfig
|
||||
|
||||
|
||||
services = {
|
||||
@ -69,7 +69,7 @@ class GenericInterface:
|
||||
# populate from settings file once on creation
|
||||
# avoid constant disk access, restart on adding services is acceptable
|
||||
for key in self.settings:
|
||||
self.settings[key] = get_settings(self.settings[key])
|
||||
self.settings[key] = malojaconfig[self.settings[key]]
|
||||
self.authorize()
|
||||
|
||||
# this makes sure that of every class we define, we immediately create an
|
||||
@ -105,7 +105,7 @@ class ProxyScrobbleInterface(GenericInterface,abstract=True):
|
||||
def active_proxyscrobble(self):
|
||||
return (
|
||||
all(self.settings[key] not in [None,"ASK",False] for key in self.proxyscrobble["required_settings"]) and
|
||||
get_settings(self.proxyscrobble["activated_setting"])
|
||||
malojaconfig[self.proxyscrobble["activated_setting"]]
|
||||
)
|
||||
|
||||
def scrobble(self,artists,title,timestamp):
|
||||
@ -130,7 +130,7 @@ class ImportInterface(GenericInterface,abstract=True):
|
||||
def active_import(self):
|
||||
return (
|
||||
all(self.settings[key] not in [None,"ASK",False] for key in self.scrobbleimport["required_settings"]) and
|
||||
get_settings(self.scrobbleimport["activated_setting"])
|
||||
malojaconfig[self.scrobbleimport["activated_setting"]]
|
||||
)
|
||||
|
||||
|
||||
@ -147,7 +147,7 @@ class MetadataInterface(GenericInterface,abstract=True):
|
||||
def active_metadata(self):
|
||||
return (
|
||||
all(self.settings[key] not in [None,"ASK",False] for key in self.metadata["required_settings"]) and
|
||||
self.identifier in get_settings("METADATA_PROVIDERS")
|
||||
self.identifier in malojaconfig["METADATA_PROVIDERS"]
|
||||
)
|
||||
|
||||
def get_image_track(self,track):
|
||||
@ -228,5 +228,5 @@ from . import *
|
||||
|
||||
|
||||
services["metadata"].sort(
|
||||
key=lambda provider : get_settings("METADATA_PROVIDERS").index(provider.identifier)
|
||||
key=lambda provider : malojaconfig["METADATA_PROVIDERS"].index(provider.identifier)
|
||||
)
|
||||
|
@ -1,8 +1,7 @@
|
||||
from .. import globalconf
|
||||
from ..globalconf import data_dir
|
||||
from ..globalconf import data_dir, malojaconfig
|
||||
from .. import thirdparty
|
||||
|
||||
from doreah import settings, caching
|
||||
from doreah import caching
|
||||
from doreah.logging import log
|
||||
|
||||
import itertools
|
||||
@ -15,27 +14,13 @@ import re
|
||||
import datetime
|
||||
|
||||
|
||||
if globalconf.USE_THUMBOR:
|
||||
def thumborize(url):
|
||||
if url.startswith("/"): url = globalconf.OWNURL + url
|
||||
encrypted_url = globalconf.THUMBOR_GENERATOR.generate(
|
||||
width=300,
|
||||
height=300,
|
||||
smart=True,
|
||||
image_url=url
|
||||
)
|
||||
return globalconf.THUMBOR_SERVER + encrypted_url
|
||||
|
||||
else:
|
||||
def thumborize(url):
|
||||
return url
|
||||
|
||||
|
||||
|
||||
### Caches
|
||||
|
||||
cacheage = settings.get_settings("CACHE_EXPIRE_POSITIVE") * 24 * 3600
|
||||
cacheage_neg = settings.get_settings("CACHE_EXPIRE_NEGATIVE") * 24 * 3600
|
||||
cacheage = malojaconfig["CACHE_EXPIRE_POSITIVE"] * 24 * 3600
|
||||
cacheage_neg = malojaconfig["CACHE_EXPIRE_NEGATIVE"] * 24 * 3600
|
||||
|
||||
artist_cache = caching.Cache(name="imgcache_artists",maxage=cacheage,maxage_negative=cacheage_neg,persistent=True)
|
||||
track_cache = caching.Cache(name="imgcache_tracks",maxage=cacheage,maxage_negative=cacheage_neg,persistent=True)
|
||||
@ -133,7 +118,7 @@ def local_files(artist=None,artists=None,title=None):
|
||||
|
||||
|
||||
# these caches are there so we don't check all files every time, but return the same one
|
||||
local_cache_age = settings.get_settings("LOCAL_IMAGE_ROTATE")
|
||||
local_cache_age = malojaconfig["LOCAL_IMAGE_ROTATE"]
|
||||
local_artist_cache = caching.Cache(maxage=local_cache_age)
|
||||
local_track_cache = caching.Cache(maxage=local_cache_age)
|
||||
|
||||
@ -142,9 +127,9 @@ def getTrackImage(artists,title,fast=False):
|
||||
hashable_track = (frozenset(artists),title)
|
||||
|
||||
# Prio 1: Local image
|
||||
if settings.get_settings("USE_LOCAL_IMAGES"):
|
||||
if malojaconfig["USE_LOCAL_IMAGES"]:
|
||||
try:
|
||||
return thumborize(local_track_cache.get(hashable_track))
|
||||
return local_track_cache.get(hashable_track)
|
||||
except:
|
||||
images = local_files(artists=artists,title=title)
|
||||
if len(images) != 0:
|
||||
@ -156,7 +141,7 @@ def getTrackImage(artists,title,fast=False):
|
||||
# Prio 2: Cached remote link
|
||||
try:
|
||||
result = track_cache.get(hashable_track)
|
||||
if result is not None: return thumborize(result)
|
||||
if result is not None: return result
|
||||
# if we have cached the nonexistence of that image, we immediately return
|
||||
# the redirect to the artist and let the resolver handle it
|
||||
# (even if we're not in a fast lookup right now)
|
||||
@ -179,7 +164,7 @@ def getTrackImage(artists,title,fast=False):
|
||||
# cache results (even negative ones)
|
||||
track_cache.add(hashable_track,result)
|
||||
# return either result or redirect to artist
|
||||
if result is not None: return thumborize(result)
|
||||
if result is not None: return result
|
||||
for a in artists:
|
||||
res = getArtistImage(artist=a,fast=False)
|
||||
if res != "": return res
|
||||
@ -189,21 +174,21 @@ def getTrackImage(artists,title,fast=False):
|
||||
def getArtistImage(artist,fast=False):
|
||||
|
||||
# Prio 1: Local image
|
||||
if settings.get_settings("USE_LOCAL_IMAGES"):
|
||||
if malojaconfig["USE_LOCAL_IMAGES"]:
|
||||
try:
|
||||
return thumborize(local_artist_cache.get(artist))
|
||||
return local_artist_cache.get(artist)
|
||||
except:
|
||||
images = local_files(artist=artist)
|
||||
if len(images) != 0:
|
||||
res = random.choice(images)
|
||||
local_artist_cache.add(artist,res)
|
||||
return thumborize(urllib.parse.quote(res))
|
||||
return urllib.parse.quote(res)
|
||||
|
||||
|
||||
# Prio 2: Cached remote link
|
||||
try:
|
||||
result = artist_cache.get(artist)
|
||||
if result is not None: return thumborize(result)
|
||||
if result is not None: return result
|
||||
else: return ""
|
||||
# none means non-existence is cached, return empty
|
||||
except:
|
||||
@ -219,7 +204,7 @@ def getArtistImage(artist,fast=False):
|
||||
result = thirdparty.get_image_artist_all(artist)
|
||||
# cache results (even negative ones)
|
||||
artist_cache.add(artist,result) #cache_artist(artist,result)
|
||||
if result is not None: return thumborize(result)
|
||||
if result is not None: return result
|
||||
else: return ""
|
||||
|
||||
def getTrackImages(trackobjectlist,fast=False):
|
||||
|
@ -1,8 +1,8 @@
|
||||
from ..__pkginfo__ import version
|
||||
from ..malojatime import ranges, thisweek, thisyear
|
||||
from ..globalconf import malojaconfig
|
||||
|
||||
from doreah.regular import yearly, daily
|
||||
from doreah import settings
|
||||
from doreah.logging import log
|
||||
|
||||
import datetime
|
||||
@ -87,7 +87,7 @@ def update_weekly():
|
||||
|
||||
@daily
|
||||
def send_stats():
|
||||
if settings.get_settings("SEND_STATS"):
|
||||
if malojaconfig["SEND_STATS"]:
|
||||
|
||||
log("Sending daily stats report...")
|
||||
|
||||
@ -98,8 +98,8 @@ def send_stats():
|
||||
"method":"POST",
|
||||
"headers":{"Content-Type": "application/json"},
|
||||
"data":json.dumps({
|
||||
"name":settings.get_settings("NAME"),
|
||||
"url":settings.get_settings("PUBLIC_URL"),
|
||||
"name":malojaconfig["NAME"],
|
||||
"url":malojaconfig["PUBLIC_URL"],
|
||||
"version":".".join(str(d) for d in version),
|
||||
"artists":len(ARTISTS),
|
||||
"tracks":len(TRACKS),
|
||||
|
@ -35,6 +35,11 @@
|
||||
<span style="opacity:0.5;">Database Maintenance</span>
|
||||
{% else %}
|
||||
<a href="/admin_issues">Database Maintenance</a>
|
||||
{% endif %} |
|
||||
{% if page=='admin_settings' %}
|
||||
<span style="opacity:0.5;">Settings</span>
|
||||
{% else %}
|
||||
<a href="/admin_settings">Settings</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
<br/><br/>
|
||||
|
@ -48,13 +48,13 @@
|
||||
<span>Get your own Maloja scrobble server on <a target="_blank" rel="noopener noreferrer" href="https://pypi.org/project/malojaserver/">PyPI</a></span>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/"><span style="font-weight:bold;">Maloja {% if settings("DEV_MODE") %}[Developer Mode]{% endif %}</span></a>
|
||||
<a href="/"><span style="font-weight:bold;">Maloja {% if settings["DEV_MODE"] %}[Developer Mode]{% endif %}</span></a>
|
||||
</div>
|
||||
<div>
|
||||
<span><input id="searchinput" placeholder="Search for an artist or track..." oninput="search(this)" onblur="clearresults()" /></span>
|
||||
</div>
|
||||
|
||||
<span id="resultwrap" class="hide">
|
||||
<div id="resultwrap" class="hide">
|
||||
<div class="searchresults">
|
||||
<span>Artists</span>
|
||||
<table class="searchresults_artists" id="searchresults_artists">
|
||||
@ -64,7 +64,7 @@
|
||||
<table class="searchresults_tracks" id="searchresults_tracks">
|
||||
</table>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="/admin_overview"><div title="Server Administration" id="settingsicon">
|
||||
|
8
maloja/web/jinja/admin_settings.jinja
Normal file
8
maloja/web/jinja/admin_settings.jinja
Normal file
@ -0,0 +1,8 @@
|
||||
{% set page ='admin_settings' %}
|
||||
{% extends "abstracts/admin.jinja" %}
|
||||
{% block title %}Maloja - Settings{% endblock %}
|
||||
|
||||
|
||||
{% block maincontent %}
|
||||
{{ config.html() }}
|
||||
{% endblock %}
|
@ -35,7 +35,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{% if settings('CHARTS_DISPLAY_TILES') %}
|
||||
{% if settings['CHARTS_DISPLAY_TILES'] %}
|
||||
{% include 'partials/charts_artists_tiles.jinja' %}
|
||||
<br/><br/>
|
||||
{% endif %}
|
||||
|
@ -37,7 +37,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{% if settings('CHARTS_DISPLAY_TILES') %}
|
||||
{% if settings['CHARTS_DISPLAY_TILES'] %}
|
||||
{% include 'partials/charts_tracks_tiles.jinja' %}
|
||||
<br/><br/>
|
||||
{% endif %}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<td class='icon'><div style="background-image:url('{{ img }}')"></div></td>
|
||||
{% if "artists" in entity %}
|
||||
{% if settings('TRACK_SEARCH_PROVIDER') is not none %}
|
||||
{% if settings['TRACK_SEARCH_PROVIDER'] %}
|
||||
<td class='searchProvider'>{{ links.link_search(entity) }}</td>
|
||||
{% endif %}
|
||||
<td class='track'>
|
||||
|
@ -62,7 +62,7 @@
|
||||
{% macro link_search(entity) -%}
|
||||
{% set searchstr = (entity.artists + [entity.title]) | join(" ") | urlencode %}
|
||||
|
||||
{% set searchprovider = settings('TRACK_SEARCH_PROVIDER') | lower | replace(' ','') %}
|
||||
{% set searchprovider = settings['TRACK_SEARCH_PROVIDER'] | lower | replace(' ','') %}
|
||||
{% set searchproviders =
|
||||
{
|
||||
"youtube":'https://www.youtube.com/results?search_query=',
|
||||
|
@ -31,7 +31,7 @@
|
||||
{% for r in xcurrent %}
|
||||
{% if r.range == limitkeys.timerange %}
|
||||
<span class='stat_selector' style='opacity:0.5;'>{{ r.localisation }}</span>
|
||||
{% elif r.heavy and settings('DISCOURAGE_CPU_HEAVY_STATS') %}
|
||||
{% elif r.heavy and settings['DISCOURAGE_CPU_HEAVY_STATS'] %}
|
||||
<span class='stat_selector blocked' title="CPU heavy statistics are discouraged at the moment.">{{ r.localisation }}</span>
|
||||
{% else %}
|
||||
<a href='{{ mlj_uri.create_uri("",allkeys,{"timerange":r.range}) }}'><span class='stat_selector'>{{ r.localisation }}</span></a>
|
||||
@ -49,7 +49,7 @@
|
||||
{# {% if all(r.keys[k] == allkeys[k] for k in r.keys) %} #}
|
||||
{% if r.replacekeys | map('compare_key_in_dicts',r.replacekeys,allkeys) | alltrue %}
|
||||
<span class='stat_selector' style='opacity:0.5;'>{{ r.localisation }}</span>
|
||||
{% elif r.heavy and settings('DISCOURAGE_CPU_HEAVY_STATS') %}
|
||||
{% elif r.heavy and settings['DISCOURAGE_CPU_HEAVY_STATS'] %}
|
||||
<span class='stat_selector blocked' title="CPU heavy statistics are discouraged at the moment.">{{ r.localisation }}</span>
|
||||
{% else %}
|
||||
<a href='{{ mlj_uri.create_uri("",allkeys,r.replacekeys) }}'><span class='stat_selector'>{{ r.localisation }}</span></a>
|
||||
|
@ -4,9 +4,9 @@
|
||||
{% block scripts %}
|
||||
|
||||
<script>document.addEventListener('DOMContentLoaded',function() {
|
||||
showRange('topartists','{{ settings("DEFAULT_RANGE_CHARTS_ARTISTS") }}');
|
||||
showRange('toptracks','{{ settings("DEFAULT_RANGE_CHARTS_TRACKS") }}');
|
||||
showRange('pulse','{{ settings("DEFAULT_STEP_PULSE") }}');
|
||||
showRange('topartists','{{ settings["DEFAULT_RANGE_CHARTS_ARTISTS"] }}');
|
||||
showRange('toptracks','{{ settings["DEFAULT_RANGE_CHARTS_TRACKS"] }}');
|
||||
showRange('pulse','{{ settings["DEFAULT_STEP_PULSE"] }}');
|
||||
})</script>
|
||||
<script src="/rangeselect.js"></script>
|
||||
<script src="/cookies.js"></script>
|
||||
|
@ -138,6 +138,20 @@ a.hidelink:hover {
|
||||
|
||||
|
||||
|
||||
/** INPUTS **/
|
||||
|
||||
input[type="text"], input[type="number"] {
|
||||
background-color: transparent;
|
||||
border: 0px;
|
||||
border-bottom: 1px solid var(--text-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: 0;
|
||||
background-color: var(--base-color-accent-light);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
bottle>=0.12.16
|
||||
waitress>=1.3
|
||||
doreah>=1.6.12
|
||||
doreah>=1.7.1
|
||||
nimrodel>=0.7.0
|
||||
setproctitle>=1.1.10
|
||||
wand>=0.5.4
|
||||
jinja2>2.11
|
||||
jinja2>=2.11
|
||||
lru-dict>=1.1.6
|
||||
css_html_js_minify>=2.5.5
|
||||
|
91
settings.md
91
settings.md
@ -3,53 +3,56 @@ Technically, each setting can be set via environment variable or the settings fi
|
||||
Settings File | Environment Variable | Type | Description
|
||||
------ | --------- | --------- | ---------
|
||||
**Setup**
|
||||
| `MALOJA_DATA_DIRECTORY` | String | Use this directory to store all application files. Useful for docker. Overwrites all individually specified directories below.
|
||||
| `MALOJA_DIRECTORY_CONFIG` | String | Use this directory to store configuration files.
|
||||
`DIRECTORY_STATE` | `MALOJA_DIRECTORY_STATE` | String | Use this directory to store state files.
|
||||
`DIRECTORY_LOGS` | `MALOJA_DIRECTORY_LOGS` | String | Use this directory to store log files.
|
||||
`DIRECTORY_CACHE` | `MALOJA_DIRECTORY_CACHE` | String | Use this directory to store cache files.
|
||||
`SKIP_SETUP` | `MALOJA_SKIP_SETUP` | Boolean | Whether to make server startup non-interactive. Vital for docker.
|
||||
| `MALOJA_FORCE_PASSWORD` | String | Sets password for admin login in web interface. This should normally be done via the interactive prompt.
|
||||
`CLEAN_OUTPUT` | `MALOJA_CLEAN_OUTPUT` | Boolean | Avoid mutable console output. Use if console output will be redirected e.g. to a web interface.
|
||||
`data_directory` | `MALOJA_DATA_DIRECTORY` | String | Folder for all user data. Overwrites all choices for specific directories.
|
||||
`directory_config` | `MALOJA_DIRECTORY_CONFIG` | String | Folder for config data. Only applied when global data directory is not set.
|
||||
`directory_state` | `MALOJA_DIRECTORY_STATE` | String | Folder for state data. Only applied when global data directory is not set.
|
||||
`directory_logs` | `MALOJA_DIRECTORY_LOGS` | String | Folder for log data. Only applied when global data directory is not set.
|
||||
`directory_cache` | `MALOJA_DIRECTORY_CACHE` | String | Folder for cache data. Only applied when global data directory is not set.
|
||||
`skip_setup` | `MALOJA_SKIP_SETUP` | Boolean | Make server setup process non-interactive. Vital for Docker.
|
||||
`force_password` | `MALOJA_FORCE_PASSWORD` | String | On startup, overwrite admin password with this one. This should usually only be done via environment variable in Docker.
|
||||
`clean_output` | `MALOJA_CLEAN_OUTPUT` | Boolean | Use if console output will be redirected e.g. to a web interface.
|
||||
**Debug**
|
||||
`LOGGING` | `MALOJA_LOGGING` | Boolean | Enable logging
|
||||
`DEV_MODE` | `MALOJA_DEV_MODE` | Boolean | Enable developer mode
|
||||
`logging` | `MALOJA_LOGGING` | Boolean | Enable Logging
|
||||
`dev_mode` | `MALOJA_DEV_MODE` | Boolean | Enable developer mode
|
||||
**Network**
|
||||
`host` | `MALOJA_HOST` | String | Host for your server - most likely :: for IPv6 or 0.0.0.0 for IPv4
|
||||
`port` | `MALOJA_PORT` | Integer | Port
|
||||
**Technical**
|
||||
`WEB_PORT` | | Integer | HTTP port to use for your web interface and API
|
||||
`HOST` | | String | Host for your server - most likely `::` for IPv6 or `0.0.0.0` for IPv4
|
||||
`CACHE_EXPIRE_POSITIVE` | | Integer | Days until images are refetched
|
||||
`CACHE_EXPIRE_NEGATIVE` | | Integer | Days until failed image fetches are reattempted
|
||||
`USE_DB_CACHE` | | Boolean | Whether to use the Database Cache.
|
||||
`CACHE_DATABASE_SHORT` | | Boolean | Whether to use the Volatile DB Cache.
|
||||
`CACHE_DATABASE_PERM` | | Boolean | Whether to use the Permanent DB Cache.
|
||||
`DB_CACHE_ENTRIES` | | Integer | Maximal entries of cache.
|
||||
`DB_MAX_MEMORY` | | Integer | Maximal percentage of total RAM that should be used (by whole system) before Maloja discards cache entries. Use a higher number if your Maloja runs on a dedicated instance (e.g. a container)
|
||||
`cache_expire_positive` | `MALOJA_CACHE_EXPIRE_POSITIVE` | Integer | Days until images are refetched
|
||||
`cache_expire_negative` | `MALOJA_CACHE_EXPIRE_NEGATIVE` | Integer | Days until failed image fetches are reattempted
|
||||
`use_db_cache` | `MALOJA_USE_DB_CACHE` | Boolean | Use DB Cache
|
||||
`cache_database_short` | `MALOJA_CACHE_DATABASE_SHORT` | Boolean | Use volatile Database Cache
|
||||
`cache_database_perm` | `MALOJA_CACHE_DATABASE_PERM` | Boolean | Use permanent Database Cache
|
||||
`db_cache_entries` | `MALOJA_DB_CACHE_ENTRIES` | Integer | Maximal Cache entries
|
||||
`db_max_memory` | `MALOJA_DB_MAX_MEMORY` | Integer | Maximal percentage of RAM that should be used by whole system before Maloja discards cache entries. Use a higher number if your Maloja runs on a dedicated instance (e.g. a container)
|
||||
**Fluff**
|
||||
`SCROBBLES_GOLD` | | Integer | How many scrobbles should be considered 'Gold' status for a track
|
||||
`SCROBBLES_PLATINUM` | | Integer | How many scrobbles should be considered 'Platinum' status for a track
|
||||
`SCROBBLES_DIAMOND` | | Integer | How many scrobbles should be considered 'Diamond' status for a track
|
||||
`NAME` | | String | Your Name for display
|
||||
`scrobbles_gold` | `MALOJA_SCROBBLES_GOLD` | Integer | How many scrobbles a track needs to be considered 'Gold' status
|
||||
`scrobbles_platinum` | `MALOJA_SCROBBLES_PLATINUM` | Integer | How many scrobbles a track needs to be considered 'Platinum' status
|
||||
`scrobbles_diamond` | `MALOJA_SCROBBLES_DIAMOND` | Integer | How many scrobbles a track needs to be considered 'Diamond' status
|
||||
`name` | `MALOJA_NAME` | String | Name
|
||||
**Third Party Services**
|
||||
`METADATA_PROVIDERS` | | List (String) | Which metadata providers should be used in what order. Musicbrainz is rate-limited and should not be used first.
|
||||
`SCROBBLE_LASTFM` | | Boolean | Proxy-scrobble to Last.fm
|
||||
`LASTFM_API_KEY` | | String | API key for Last.fm. Necessary if proxy-scrobbling to Last.fm or using it as a metadata provider
|
||||
`LASTFM_API_SECRET` | | String | API secret for Last.fm. Necessary if proxy-scrobbling to Last.fm or using it as a metadata provider
|
||||
`SPOTIFY_API_ID` | | String | API ID for Spotify. Necessary if using it as a metadata provider.
|
||||
`SPOTIFY_API_SECRET` | | String | API Secret for Spotify. Necessary if using it as a metadata provider.
|
||||
`TRACK_SEARCH_PROVIDER` | | String | Provider for track search next to scrobbles. None to disable.
|
||||
`THUMBOR_SERVER` | | String | URL of Thumbor server to serve custom artwork.
|
||||
`THUMBOR_SECRET` | | String | Secret of Thumbor server
|
||||
`metadata_providers` | `MALOJA_METADATA_PROVIDERS` | List | Which metadata providers should be used in what order. Musicbrainz is rate-limited and should not be used first.
|
||||
`scrobble_lastfm` | `MALOJA_SCROBBLE_LASTFM` | Boolean | Proxy-Scrobble to Last.fm
|
||||
`lastfm_api_key` | `MALOJA_LASTFM_API_KEY` | String | Last.fm API Key
|
||||
`lastfm_api_secret` | `MALOJA_LASTFM_API_SECRET` | String | Last.fm API Secret
|
||||
`spotify_api_id` | `MALOJA_SPOTIFY_API_ID` | String | Spotify API ID
|
||||
`spotify_api_secret` | `MALOJA_SPOTIFY_API_SECRET` | String | Spotify API Secret
|
||||
`audiodb_api_key` | `MALOJA_AUDIODB_API_KEY` | String | TheAudioDB API Key
|
||||
`track_search_provider` | `MALOJA_TRACK_SEARCH_PROVIDER` | String | Track Search Provider
|
||||
`send_stats` | `MALOJA_SEND_STATS` | Boolean | Send Statistics
|
||||
**Database**
|
||||
`INVALID_ARTISTS` | | List (String) | Artists that should be discarded immediately
|
||||
`REMOVE_FROM_TITLE` | | List (String) | Phrases that should be removed from song titles
|
||||
`DELIMITERS_FEAT` | | List (String) | Delimiters used for extra artists, even when in the title field
|
||||
`DELIMITERS_INFORMAL` | | List (String) | Delimiters in informal artist strings with spaces expected around them
|
||||
`DELIMITERS_FORMAL` | | List (String) | Delimiters used to tag multiple artists when only one tag field is available
|
||||
`invalid_artists` | `MALOJA_INVALID_ARTISTS` | Set | Artists that should be discarded immediately
|
||||
`remove_from_title` | `MALOJA_REMOVE_FROM_TITLE` | Set | Phrases that should be removed from song titles
|
||||
`delimiters_feat` | `MALOJA_DELIMITERS_FEAT` | Set | Delimiters used for extra artists, even when in the title field
|
||||
`delimiters_informal` | `MALOJA_DELIMITERS_INFORMAL` | Set | Delimiters in informal artist strings with spaces expected around them
|
||||
`delimiters_formal` | `MALOJA_DELIMITERS_FORMAL` | Set | Delimiters used to tag multiple artists when only one tag field is available
|
||||
**Web Interface**
|
||||
`DEFAULT_RANGE_CHARTS_ARTISTS` | | String | What range is shown per default for the tile view on the start page
|
||||
`DEFAULT_RANGE_CHARTS_TRACKS` | | String | What range is shown per default for the tile view on the start page
|
||||
`DEFAULT_STEP_PULSE` | | String | What steps are shown per default for the pulse view on the start page
|
||||
`CHARTS_DISPLAY_TILES` | | Boolean | Whether to show tiles on chart pages
|
||||
`DISCOURAGE_CPU_HEAVY_STATS` | | Boolean | Prevent visitors from mindlessly clicking on CPU-heavy options. Does not actually disable them for malicious actors!
|
||||
`USE_LOCAL_IMAGES` | | Boolean | Use local images if present
|
||||
`LOCAL_IMAGE_ROTATE` | | Integer | How many seconds to wait between rotating local images
|
||||
`default_range_charts_artists` | `MALOJA_DEFAULT_RANGE_CHARTS_ARTISTS` | Choice | Default Range Artist Charts
|
||||
`default_range_charts_tracks` | `MALOJA_DEFAULT_RANGE_CHARTS_TRACKS` | Choice | Default Range Track Charts
|
||||
`default_step_pulse` | `MALOJA_DEFAULT_STEP_PULSE` | Choice | Default Pulse Step
|
||||
`charts_display_tiles` | `MALOJA_CHARTS_DISPLAY_TILES` | Boolean | Display Chart Tiles
|
||||
`discourage_cpu_heavy_stats` | `MALOJA_DISCOURAGE_CPU_HEAVY_STATS` | Boolean | Prevent visitors from mindlessly clicking on CPU-heavy options. Does not actually disable them for malicious actors!
|
||||
`use_local_images` | `MALOJA_USE_LOCAL_IMAGES` | Boolean | Use Local Images
|
||||
`local_image_rotate` | `MALOJA_LOCAL_IMAGE_ROTATE` | Integer | Local Image Rotate
|
||||
`timezone` | `MALOJA_TIMEZONE` | Integer | UTC Offset
|
||||
`time_format` | `MALOJA_TIME_FORMAT` | String | Time Format
|
||||
|
Loading…
x
Reference in New Issue
Block a user