mirror of
https://github.com/krateng/maloja.git
synced 2023-08-10 21:12:55 +03:00
Experimental support for Listenbrainz scrobblers
This commit is contained in:
parent
042f4f12fb
commit
5aa92a1ab8
24
README.md
24
README.md
@ -61,12 +61,24 @@ If you didn't install Maloja from the package (and therefore don't have it in `/
|
|||||||
|
|
||||||
## How to scrobble
|
## How to scrobble
|
||||||
|
|
||||||
|
### Native API
|
||||||
|
|
||||||
If you use Plex Web or Youtube Music on Chromium, you can use the included extension. Make sure to enter the random key Maloja generates on first startup in the extension settings.
|
If you use Plex Web or Youtube Music on Chromium, you can use the included extension. Make sure to enter the random key Maloja generates on first startup in the extension settings.
|
||||||
|
|
||||||
You can use any third-party scrobbler that supports the audioscrobbler protocol (GNUFM). This is still very experimental, but give it a try with these settings:
|
|
||||||
|
|
||||||
Gnukebox URL: Your Maloja URL followed by `/api/s/audioscrobbler`
|
|
||||||
Username: Any name, doesn't matter
|
|
||||||
Password: Any of your API keys (you can define new ones in `clients/authenticated_machines` in your Maloja folder)
|
|
||||||
|
|
||||||
If you want to implement your own method of scrobbling, it's very simple: You only need one POST request with the keys `artist`, `title` and `key`.
|
If you want to implement your own method of scrobbling, it's very simple: You only need one POST request with the keys `artist`, `title` and `key`.
|
||||||
|
|
||||||
|
### Standard-compliant API
|
||||||
|
|
||||||
|
You can use any third-party scrobbler that supports the audioscrobbler (GNUFM) or the ListenBrainz protocol. This is still very experimental, but give it a try with these settings:
|
||||||
|
|
||||||
|
GNU FM |
|
||||||
|
------ | ---------
|
||||||
|
Gnukebox URL | Your Maloja URL followed by `/api/s/audioscrobbler`
|
||||||
|
Username | Any name, doesn't matter
|
||||||
|
Password | Any of your API keys (you can define new ones in `clients/authenticated_machines` in your Maloja folder)
|
||||||
|
|
||||||
|
ListenBrainz |
|
||||||
|
------ | ---------
|
||||||
|
API URL | Your Maloja URL followed by `api/s/listenbrainz`
|
||||||
|
Username | Any name, doesn't matter
|
||||||
|
Auth Token | Any of your API keys (you can define new ones in `clients/authenticated_machines` in your Maloja folder)
|
||||||
|
@ -2,7 +2,9 @@ from doreah.logging import log
|
|||||||
import hashlib
|
import hashlib
|
||||||
import random
|
import random
|
||||||
import database
|
import database
|
||||||
|
import datetime
|
||||||
from cleanup import CleanerAgent
|
from cleanup import CleanerAgent
|
||||||
|
from bottle import response
|
||||||
|
|
||||||
## GNU-FM-compliant scrobbling
|
## GNU-FM-compliant scrobbling
|
||||||
|
|
||||||
@ -51,6 +53,7 @@ def handle(path,keys,headers,auth):
|
|||||||
response = {"error_message":"Invalid scrobble protocol"}
|
response = {"error_message":"Invalid scrobble protocol"}
|
||||||
except:
|
except:
|
||||||
response = {"error_message":"Unknown API error"}
|
response = {"error_message":"Unknown API error"}
|
||||||
|
raise
|
||||||
|
|
||||||
print("Response: " + str(response))
|
print("Response: " + str(response))
|
||||||
return response
|
return response
|
||||||
@ -113,8 +116,32 @@ def handle_listenbrainz(path,keys,headers):
|
|||||||
if path[1] == "submit-listens":
|
if path[1] == "submit-listens":
|
||||||
|
|
||||||
if headers.get("Authorization") is not None:
|
if headers.get("Authorization") is not None:
|
||||||
print(headers.get("Authorization"))
|
token = headers.get("Authorization").replace("token ","").strip()
|
||||||
return {"wat":"wut"}
|
if token in database.allAPIkeys():
|
||||||
|
if "payload" in keys:
|
||||||
|
if keys["listen_type"] in ["single","import"]:
|
||||||
|
for listen in keys["payload"]:
|
||||||
|
metadata = listen["track_metadata"]
|
||||||
|
artiststr, titlestr = metadata["artist_name"], metadata["track_name"]
|
||||||
|
(artists,title) = cla.fullclean(artiststr,titlestr)
|
||||||
|
try:
|
||||||
|
timestamp = int(listen["listened_at"])
|
||||||
|
except:
|
||||||
|
timestamp = int(datetime.datetime.now(tz=datetime.timezone.utc).timestamp())
|
||||||
|
database.createScrobble(artists,title,timestamp)
|
||||||
|
return {"code":200,"status":"ok"}
|
||||||
|
else:
|
||||||
|
response.status = 400
|
||||||
|
return {"code":400,"error":"Invalid JSON document submitted."}
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
return {"error":"Bad Auth"}
|
||||||
|
|
||||||
|
else:
|
||||||
|
return {"code":401,"error":"You need to provide an Authorization header."}
|
||||||
|
|
||||||
|
else:
|
||||||
|
return {"error_message":"Invalid API method"}
|
||||||
else:
|
else:
|
||||||
return {"error_message":"API version not supported"}
|
return {"error_message":"API version not supported"}
|
||||||
|
@ -660,8 +660,11 @@ def post_scrobble():
|
|||||||
def sapi(path):
|
def sapi(path):
|
||||||
path = path.split("/")
|
path = path.split("/")
|
||||||
path = list(filter(None,path))
|
path = list(filter(None,path))
|
||||||
keys = FormsDict.decode(request.params)
|
|
||||||
headers = request.headers
|
headers = request.headers
|
||||||
|
if "application/json" in request.get_header("Content-Type"):
|
||||||
|
keys = request.json
|
||||||
|
else:
|
||||||
|
keys = FormsDict.decode(request.params)
|
||||||
auth = request.auth
|
auth = request.auth
|
||||||
return compliant_api.handle(path,keys,headers,auth)
|
return compliant_api.handle(path,keys,headers,auth)
|
||||||
|
|
||||||
|
57
server.py
57
server.py
@ -69,59 +69,6 @@ def customerror(error):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#@webserver.get("/api/<pth:path>")
|
|
||||||
#def api(pth):
|
|
||||||
# return database.handle_get(pth,request)
|
|
||||||
|
|
||||||
#@webserver.post("/api/<pth:path>")
|
|
||||||
#def api_post(pth):
|
|
||||||
# return database.handle_post(pth,request)
|
|
||||||
|
|
||||||
# this is the fallback option. If you run this service behind a reverse proxy, it is recommended to rewrite /db/ requests to the port of the db server
|
|
||||||
# e.g. location /db { rewrite ^/db(.*)$ $1 break; proxy_pass http://yoururl:12349; }
|
|
||||||
|
|
||||||
#@webserver.get("/api/<pth:path>")
|
|
||||||
def database_get(pth):
|
|
||||||
keys = FormsDict.decode(request.query) # The Dal★Shabet handler
|
|
||||||
keystring = "?"
|
|
||||||
for k in keys:
|
|
||||||
keystring += urllib.parse.quote(k) + "=" + urllib.parse.quote(keys[k]) + "&"
|
|
||||||
response.set_header("Access-Control-Allow-Origin","*")
|
|
||||||
try:
|
|
||||||
proxyresponse = urllib.request.urlopen("http://[::1]:" + str(DATABASE_PORT) + "/" + pth + keystring)
|
|
||||||
contents = proxyresponse.read()
|
|
||||||
response.status = proxyresponse.getcode()
|
|
||||||
response.content_type = "application/json"
|
|
||||||
return contents
|
|
||||||
except HTTPError as e:
|
|
||||||
response.status = e.code
|
|
||||||
return
|
|
||||||
|
|
||||||
#@webserver.post("/api/<pth:path>")
|
|
||||||
def database_post(pth):
|
|
||||||
#print(request.headers)
|
|
||||||
#response.set_header("Access-Control-Allow-Origin","*")
|
|
||||||
try:
|
|
||||||
proxyrequest = urllib.request.Request(
|
|
||||||
url="http://[::1]:" + str(DATABASE_PORT) + "/" + pth,
|
|
||||||
data=request.body,
|
|
||||||
headers=request.headers,
|
|
||||||
method="POST"
|
|
||||||
)
|
|
||||||
proxyresponse = urllib.request.urlopen(proxyrequest)
|
|
||||||
|
|
||||||
contents = proxyresponse.read()
|
|
||||||
response.status = proxyresponse.getcode()
|
|
||||||
response.headers = proxyresponse.headers
|
|
||||||
response.content_type = "application/json"
|
|
||||||
return contents
|
|
||||||
except HTTPError as e:
|
|
||||||
response.status = e.code
|
|
||||||
return
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def graceful_exit(sig=None,frame=None):
|
def graceful_exit(sig=None,frame=None):
|
||||||
#urllib.request.urlopen("http://[::1]:" + str(DATABASE_PORT) + "/sync")
|
#urllib.request.urlopen("http://[::1]:" + str(DATABASE_PORT) + "/sync")
|
||||||
database.sync()
|
database.sync()
|
||||||
@ -231,9 +178,7 @@ signal.signal(signal.SIGTERM, graceful_exit)
|
|||||||
#rename process, this is now required for the daemon manager to work
|
#rename process, this is now required for the daemon manager to work
|
||||||
setproctitle.setproctitle("Maloja")
|
setproctitle.setproctitle("Maloja")
|
||||||
|
|
||||||
## start database server
|
## start database
|
||||||
#_thread.start_new_thread(SourceFileLoader("database","database.py").load_module().runserver,(DATABASE_PORT,))
|
|
||||||
#_thread.start_new_thread(database.runserver,(DATABASE_PORT,))
|
|
||||||
database.start_db()
|
database.start_db()
|
||||||
database.register_subroutes(webserver,"/api")
|
database.register_subroutes(webserver,"/api")
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
If you use Vivaldi, Brave, Iridium or any other Chromium-based browser and listen to music on Plex or YouTube Music, download the extension and simply enter the server URL as well as your API key in the relevant fields. They will turn green if the server is accessible.
|
If you use Vivaldi, Brave, Iridium or any other Chromium-based browser and listen to music on Plex or YouTube Music, download the extension and simply enter the server URL as well as your API key in the relevant fields. They will turn green if the server is accessible.
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
You can also use any GNUFM-compliant scrobbler. Enter <span class="stats"><span name="serverurl">yourserver.tld</span>/api/s/audioscrobbler</span> as your Gnukebox server and your API key as the password.
|
You can also use any standard-compliant scrobbler. For GNUFM (audioscrobbler) scrobblers, enter <span class="stats"><span name="serverurl">yourserver.tld</span>/api/s/audioscrobbler</span> as your Gnukebox server and your API key as the password. For Listenbrainz scrobblers, use <span class="stats"><span name="serverurl">yourserver.tld</span>/api/s/listenbrainz</span> as the API URL and your API key as token.
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
If you use another browser or another music player, you could try to code your own extension. The API is super simple! Just send a POST HTTP request to
|
If you use another browser or another music player, you could try to code your own extension. The API is super simple! Just send a POST HTTP request to
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user