mirror of
https://github.com/krateng/maloja.git
synced 2023-08-10 21:12:55 +03:00
Experimental support for third party GNUFM scrobblers
This commit is contained in:
parent
3fce682c00
commit
144c11c5c6
18
README.md
18
README.md
@ -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
79
compliant_api.py
Normal 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}
|
21
database.py
21
database.py
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user