mirror of
https://github.com/krateng/maloja.git
synced 2023-08-10 21:12:55 +03:00
Compare commits
6 Commits
b255d424ee
...
206ebd58ea
Author | SHA1 | Date | |
---|---|---|---|
|
206ebd58ea | ||
|
a642c274e3 | ||
|
8ba973ed91 | ||
|
ca726c774a | ||
|
33bbe61ece | ||
|
15f815ffe9 |
|
@ -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.3"
|
VERSION = "3.0.4"
|
||||||
HOMEPAGE = "https://github.com/krateng/maloja"
|
HOMEPAGE = "https://github.com/krateng/maloja"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,28 @@ api.__apipath__ = "mlj_1"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
errors = {
|
||||||
|
database.MissingScrobbleParameters: lambda e: (400,{
|
||||||
|
"status":"failure",
|
||||||
|
"error":{
|
||||||
|
'type':'missing_scrobble_data',
|
||||||
|
'value':e.params,
|
||||||
|
'desc':"A scrobble requires these parameters."
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Exception: lambda e: (500,{
|
||||||
|
"status":"failure",
|
||||||
|
"error":{
|
||||||
|
'type':'unknown_error',
|
||||||
|
'value':e.__repr__(),
|
||||||
|
'desc':"The server has encountered an exception."
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_common_args_to_docstring(filterkeys=False,limitkeys=False,delimitkeys=False,amountkeys=False):
|
def add_common_args_to_docstring(filterkeys=False,limitkeys=False,delimitkeys=False,amountkeys=False):
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
timeformats = "Possible formats include '2022', '2022/08', '2022/08/01', '2022/W42', 'today', 'thismonth', 'monday', 'august'"
|
timeformats = "Possible formats include '2022', '2022/08', '2022/08/01', '2022/W42', 'today', 'thismonth', 'monday', 'august'"
|
||||||
|
@ -84,24 +106,28 @@ def test_server(key=None):
|
||||||
response.set_header("Access-Control-Allow-Origin","*")
|
response.set_header("Access-Control-Allow-Origin","*")
|
||||||
if key is not None and not apikeystore.check_key(key):
|
if key is not None and not apikeystore.check_key(key):
|
||||||
response.status = 403
|
response.status = 403
|
||||||
return {"status":"error","error":"Wrong API key"}
|
return {
|
||||||
|
"status":"error",
|
||||||
|
"error":"Wrong API key"
|
||||||
|
}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
response.status = 200
|
response.status = 200
|
||||||
return {"status":"ok"}
|
return {
|
||||||
|
"status":"ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@api.get("serverinfo")
|
@api.get("serverinfo")
|
||||||
def server_info():
|
def server_info():
|
||||||
"""Returns basic information about the server.
|
"""Returns basic information about the server.
|
||||||
|
|
||||||
:return: name (String), version (Tuple), versionstring (String), db_status (String). Additional keys can be added at any point, but will not be removed within API version.
|
:return: name (String), version (Tuple), versionstring (String), db_status (Mapping). Additional keys can be added at any point, but will not be removed within API version.
|
||||||
:rtype: Dictionary
|
:rtype: Dictionary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
response.set_header("Access-Control-Allow-Origin","*")
|
response.set_header("Access-Control-Allow-Origin","*")
|
||||||
response.set_header("Content-Type","application/json")
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"name":malojaconfig["NAME"],
|
"name":malojaconfig["NAME"],
|
||||||
|
@ -131,7 +157,9 @@ def get_scrobbles_external(**keys):
|
||||||
result = result[offset:]
|
result = result[offset:]
|
||||||
if k_amount.get('perpage') is not math.inf: result = result[:k_amount.get('perpage')]
|
if k_amount.get('perpage') is not math.inf: result = result[:k_amount.get('perpage')]
|
||||||
|
|
||||||
return {"list":result}
|
return {
|
||||||
|
"list":result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@api.get("numscrobbles")
|
@api.get("numscrobbles")
|
||||||
|
@ -146,7 +174,10 @@ def get_scrobbles_num_external(**keys):
|
||||||
ckeys = {**k_filter, **k_time, **k_amount}
|
ckeys = {**k_filter, **k_time, **k_amount}
|
||||||
|
|
||||||
result = database.get_scrobbles_num(**ckeys)
|
result = database.get_scrobbles_num(**ckeys)
|
||||||
return {"amount":result}
|
|
||||||
|
return {
|
||||||
|
"amount":result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,7 +193,10 @@ def get_tracks_external(**keys):
|
||||||
ckeys = {**k_filter}
|
ckeys = {**k_filter}
|
||||||
|
|
||||||
result = database.get_tracks(**ckeys)
|
result = database.get_tracks(**ckeys)
|
||||||
return {"list":result}
|
|
||||||
|
return {
|
||||||
|
"list":result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,7 +208,10 @@ def get_artists_external():
|
||||||
:return: list (List)
|
:return: list (List)
|
||||||
:rtype: Dictionary"""
|
:rtype: Dictionary"""
|
||||||
result = database.get_artists()
|
result = database.get_artists()
|
||||||
return {"list":result}
|
|
||||||
|
return {
|
||||||
|
"list":result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,7 +228,10 @@ def get_charts_artists_external(**keys):
|
||||||
ckeys = {**k_time}
|
ckeys = {**k_time}
|
||||||
|
|
||||||
result = database.get_charts_artists(**ckeys)
|
result = database.get_charts_artists(**ckeys)
|
||||||
return {"list":result}
|
|
||||||
|
return {
|
||||||
|
"list":result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -206,7 +246,10 @@ def get_charts_tracks_external(**keys):
|
||||||
ckeys = {**k_filter, **k_time}
|
ckeys = {**k_filter, **k_time}
|
||||||
|
|
||||||
result = database.get_charts_tracks(**ckeys)
|
result = database.get_charts_tracks(**ckeys)
|
||||||
return {"list":result}
|
|
||||||
|
return {
|
||||||
|
"list":result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -222,7 +265,10 @@ def get_pulse_external(**keys):
|
||||||
ckeys = {**k_filter, **k_time, **k_internal, **k_amount}
|
ckeys = {**k_filter, **k_time, **k_internal, **k_amount}
|
||||||
|
|
||||||
results = database.get_pulse(**ckeys)
|
results = database.get_pulse(**ckeys)
|
||||||
return {"list":results}
|
|
||||||
|
return {
|
||||||
|
"list":results
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,7 +284,10 @@ def get_performance_external(**keys):
|
||||||
ckeys = {**k_filter, **k_time, **k_internal, **k_amount}
|
ckeys = {**k_filter, **k_time, **k_internal, **k_amount}
|
||||||
|
|
||||||
results = database.get_performance(**ckeys)
|
results = database.get_performance(**ckeys)
|
||||||
return {"list":results}
|
|
||||||
|
return {
|
||||||
|
"list":results
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -254,7 +303,10 @@ def get_top_artists_external(**keys):
|
||||||
ckeys = {**k_time, **k_internal}
|
ckeys = {**k_time, **k_internal}
|
||||||
|
|
||||||
results = database.get_top_artists(**ckeys)
|
results = database.get_top_artists(**ckeys)
|
||||||
return {"list":results}
|
|
||||||
|
return {
|
||||||
|
"list":results
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -272,7 +324,10 @@ def get_top_tracks_external(**keys):
|
||||||
# IMPLEMENT THIS FOR TOP TRACKS OF ARTIST AS WELL?
|
# IMPLEMENT THIS FOR TOP TRACKS OF ARTIST AS WELL?
|
||||||
|
|
||||||
results = database.get_top_tracks(**ckeys)
|
results = database.get_top_tracks(**ckeys)
|
||||||
return {"list":results}
|
|
||||||
|
return {
|
||||||
|
"list":results
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -325,7 +380,7 @@ def post_scrobble(
|
||||||
"""Submit a new scrobble.
|
"""Submit a new scrobble.
|
||||||
|
|
||||||
:param string artist: Artist. Can be submitted multiple times as query argument for multiple artists.
|
:param string artist: Artist. Can be submitted multiple times as query argument for multiple artists.
|
||||||
:param list artists: List of artists. Overwritten by artist parameter.
|
:param list artists: List of artists.
|
||||||
:param string title: Title of the track.
|
:param string title: Title of the track.
|
||||||
:param string album: Name of the album. Optional.
|
:param string album: Name of the album. Optional.
|
||||||
:param list albumartists: Album artists. Optional.
|
:param list albumartists: Album artists. Optional.
|
||||||
|
@ -339,7 +394,7 @@ def post_scrobble(
|
||||||
"""
|
"""
|
||||||
|
|
||||||
rawscrobble = {
|
rawscrobble = {
|
||||||
'track_artists':artist if artist is not None else artists,
|
'track_artists':(artist or []) + artists,
|
||||||
'track_title':title,
|
'track_title':title,
|
||||||
'album_name':album,
|
'album_name':album,
|
||||||
'album_artists':albumartists,
|
'album_artists':albumartists,
|
||||||
|
@ -351,6 +406,7 @@ def post_scrobble(
|
||||||
# for logging purposes, don't pass values that we didn't actually supply
|
# for logging purposes, don't pass values that we didn't actually supply
|
||||||
rawscrobble = {k:rawscrobble[k] for k in rawscrobble if rawscrobble[k]}
|
rawscrobble = {k:rawscrobble[k] for k in rawscrobble if rawscrobble[k]}
|
||||||
|
|
||||||
|
try:
|
||||||
result = database.incoming_scrobble(
|
result = database.incoming_scrobble(
|
||||||
rawscrobble,
|
rawscrobble,
|
||||||
client='browser' if auth_result.get('doreah_native_auth_check') else auth_result.get('client'),
|
client='browser' if auth_result.get('doreah_native_auth_check') else auth_result.get('client'),
|
||||||
|
@ -358,8 +414,7 @@ def post_scrobble(
|
||||||
fix=(nofix is None)
|
fix=(nofix is None)
|
||||||
)
|
)
|
||||||
|
|
||||||
if result:
|
responsedict = {
|
||||||
response = {
|
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'track': {
|
'track': {
|
||||||
'artists':result['track']['artists'],
|
'artists':result['track']['artists'],
|
||||||
|
@ -367,14 +422,24 @@ def post_scrobble(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if extra_kwargs:
|
if extra_kwargs:
|
||||||
response['warnings'] = [
|
responsedict['warnings'] = [
|
||||||
{'type':'invalid_keyword_ignored','value':k}
|
{'type':'invalid_keyword_ignored','value':k,
|
||||||
|
'desc':"This key was not recognized by the server and has been discarded."}
|
||||||
for k in extra_kwargs
|
for k in extra_kwargs
|
||||||
]
|
]
|
||||||
else:
|
if artist and artists:
|
||||||
response = {"status":"failure"}
|
responsedict['warnings'] = [
|
||||||
|
{'type':'mixed_schema','value':['artist','artists'],
|
||||||
|
'desc':"These two fields are meant as alternative methods to submit information. Use of both is discouraged, but works at the moment."}
|
||||||
|
]
|
||||||
|
return responsedict
|
||||||
|
except Exception as e:
|
||||||
|
for etype in errors:
|
||||||
|
if isinstance(e,etype):
|
||||||
|
errorhandling = errors[etype](e)
|
||||||
|
response.status = errorhandling[0]
|
||||||
|
return errorhandling[1]
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,4 @@ belongtogether Case & Point
|
||||||
belongtogether Selena Gomez & The Scene
|
belongtogether Selena Gomez & The Scene
|
||||||
belongtogether Gerry & The Pacemakers
|
belongtogether Gerry & The Pacemakers
|
||||||
belongtogether AC/DC
|
belongtogether AC/DC
|
||||||
|
belongtogether Au/Ra
|
||||||
|
|
Can't render this file because it has a wrong number of fields in line 4.
|
|
@ -51,6 +51,11 @@ class DatabaseNotBuilt(HTTPError):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MissingScrobbleParameters(Exception):
|
||||||
|
def __init__(self,params=[]):
|
||||||
|
self.params = params
|
||||||
|
|
||||||
|
|
||||||
def waitfordb(func):
|
def waitfordb(func):
|
||||||
def newfunc(*args,**kwargs):
|
def newfunc(*args,**kwargs):
|
||||||
if not dbstatus['healthy']: raise DatabaseNotBuilt()
|
if not dbstatus['healthy']: raise DatabaseNotBuilt()
|
||||||
|
@ -86,10 +91,14 @@ cla = CleanerAgent()
|
||||||
|
|
||||||
def incoming_scrobble(rawscrobble,fix=True,client=None,api=None,dbconn=None):
|
def incoming_scrobble(rawscrobble,fix=True,client=None,api=None,dbconn=None):
|
||||||
|
|
||||||
if (not "track_artists" in rawscrobble) or (len(rawscrobble['track_artists']) == 0) or (not "track_title" in rawscrobble):
|
missing = []
|
||||||
|
for necessary_arg in ["track_artists","track_title"]:
|
||||||
|
if not necessary_arg in rawscrobble or len(rawscrobble[necessary_arg]) == 0:
|
||||||
|
missing.append(necessary_arg)
|
||||||
|
if len(missing) > 0:
|
||||||
log(f"Invalid Scrobble [Client: {client} | API: {api}]: {rawscrobble} ",color='red')
|
log(f"Invalid Scrobble [Client: {client} | API: {api}]: {rawscrobble} ",color='red')
|
||||||
#return {"status":"failure"}
|
raise MissingScrobbleParameters(missing)
|
||||||
return False
|
|
||||||
|
|
||||||
log(f"Incoming scrobble [Client: {client} | API: {api}]: {rawscrobble}")
|
log(f"Incoming scrobble [Client: {client} | API: {api}]: {rawscrobble}")
|
||||||
|
|
||||||
|
|
|
@ -284,6 +284,7 @@ def delete_scrobble(scrobble_id,dbconn=None):
|
||||||
def get_track_id(trackdict,dbconn=None):
|
def get_track_id(trackdict,dbconn=None):
|
||||||
ntitle = normalize_name(trackdict['title'])
|
ntitle = normalize_name(trackdict['title'])
|
||||||
artist_ids = [get_artist_id(a) for a in trackdict['artists']]
|
artist_ids = [get_artist_id(a) for a in trackdict['artists']]
|
||||||
|
artist_ids = list(set(artist_ids))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[project]
|
[project]
|
||||||
name = "malojaserver"
|
name = "malojaserver"
|
||||||
version = "3.0.3"
|
version = "3.0.4"
|
||||||
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"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user