Experimental support for third party GNUFM scrobblers

This commit is contained in:
Krateng 2019-05-12 11:46:25 +02:00
parent 3fce682c00
commit 144c11c5c6
3 changed files with 114 additions and 4 deletions

View File

@ -21,7 +21,7 @@ Also neat: You can use your **custom artist or track images**.
* [python3](https://www.python.org/) - [GitHub](https://github.com/python/cpython)
* [bottle.py](https://bottlepy.org/) - [GitHub](https://github.com/bottlepy/bottle)
* [waitress](https://docs.pylonsproject.org/projects/waitress/) - [GitHub](https://github.com/Pylons/waitress)
* [doreah](https://pypi.org/project/doreah/) - [GitHub](https://github.com/krateng/doreah) (at least Version 0.6.1)
* [doreah](https://pypi.org/project/doreah/) - [GitHub](https://github.com/krateng/doreah) (at least Version 0.7.2)
* If you'd like to display images, you will need API keys for [Last.fm](https://www.last.fm/api/account/create) and [Fanart.tv](https://fanart.tv/get-an-api-key/). These are free of charge!
## How to install
@ -51,15 +51,14 @@ Also neat: You can use your **custom artist or track images**.
If you didn't install Maloja from the package (and therefore don't have it in `/opt/maloja`), every command needs to be executed from the Maloja directory and led with `./`. Otherwise, all commands work in any location and without the prefix.
1) In order to scrobble your music from Plex Web or YouTube Music, install the included Chrome extension. Make sure to enter the random key Maloja generates on first startup in the extension. If you use another music player, Maloja has a very simple API to create your own scrobbler.
2) If you would like to import all your previous last.fm scrobbles, use [benfoxall's website](https://benjaminbenben.com/lastfm-to-csv/) ([GitHub page](https://github.com/benfoxall/lastfm-to-csv)). Use the command
1) If you would like to import all your previous last.fm scrobbles, use [benfoxall's website](https://benjaminbenben.com/lastfm-to-csv/) ([GitHub page](https://github.com/benfoxall/lastfm-to-csv)). Use the command
maloja import *filename*
to import the downloaded file into Maloja.
3) You can interact with the server at any time with the commands
2) You can interact with the server at any time with the commands
maloja stop
maloja restart
@ -67,3 +66,14 @@ If you didn't install Maloja from the package (and therefore don't have it in `/
maloja update
The `update` command will always fetch the latest version, while packages are only offered for release versions.
## How to scrobble
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)

79
compliant_api.py Normal file
View File

@ -0,0 +1,79 @@
from doreah.logging import log
import hashlib
import random
import database
from cleanup import CleanerAgent
## GNU-FM-compliant scrobbling
cla = CleanerAgent()
def md5(input):
m = hashlib.md5()
m.update(bytes(input,encoding="utf-8"))
return m.hexdigest()
#def check_sig(keys):
# try:
# sig = keys.pop("api_sig")
# text = "".join([key + keys[key] for key in sorted(keys.keys())]) + # secret
# assert sig == md5(text)
# return True
# except:
# return False
def handle(path,keys):
# log("API REQUEST")
# log(str(path))
# for k in keys:
# log(str(k) + ": " + str(keys.getall(k)))
if path[0] == "audioscrobbler":
return handle_audioscrobbler(path[1:],keys)
# no need to save these on disk, clients can always request a new session
mobile_sessions = []
def handle_audioscrobbler(path,keys):
if path[0] == "2.0":
if keys.get("method") == "auth.getMobileSession":
token = keys.get("authToken")
user = keys.get("username")
for key in database.allAPIkeys():
if md5(user + md5(key)) == token:
sessionkey = ""
for i in range(64):
sessionkey += str(random.choice(list(range(10)) + list("abcdefghijklmnopqrstuvwxyz") + list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")))
mobile_sessions.append(sessionkey)
return {"session":{"key":sessionkey}}
return {"error":4}
elif keys.get("method") == "track.scrobble":
if keys.get("sk") is None or keys.get("sk") not in mobile_sessions:
return {"error":9}
else:
if "track" in keys and "artist" in keys:
artiststr,titlestr = keys["artist"], keys["track"]
(artists,title) = cla.fullclean(artiststr,titlestr)
timestamp = int(keys["timestamp"])
database.createScrobble(artists,title,timestamp)
return {"scrobbles":{"@attr":{"ignored":0}}}
else:
for num in range(50):
if "track[" + str(num) + "]" in keys:
artiststr,titlestr = keys["artist[" + str(num) + "]"], keys["track[" + str(num) + "]"]
(artists,title) = cla.fullclean(artiststr,titlestr)
timestamp = int(keys["timestamp[" + str(num) + "]"])
database.createScrobble(artists,title,timestamp)
return {"scrobbles":{"@attr":{"ignored":0}}}
return {"error":3}

View File

@ -6,6 +6,7 @@ from cleanup import *
from utilities import *
from malojatime import *
from urihandler import uri_to_internal
import compliant_api
# doreah toolkit
from doreah.logging import log
from doreah import tsv
@ -73,6 +74,8 @@ def loadAPIkeys():
def checkAPIkey(k):
return (k in [k for [k,d] in clients])
def allAPIkeys():
return [k for [k,d] in clients]
####
@ -610,6 +613,24 @@ def post_scrobble():
return ""
# standard-compliant scrobbling methods
@dbserver.post("/s/<path:path>")
def sapi(path):
path = path.split("/")
keys = FormsDict.decode(request.forms)
return compliant_api.handle(path,keys)
@dbserver.get("/s/<path:path>")
def sapi(path):
path = path.split("/")
keys = FormsDict.decode(request.query)
return compliant_api.handle(path,keys)
@dbserver.route("/sync")
def abouttoshutdown():
sync()