From 1690c08e77092257659dda0bfe4124fc47d3f795 Mon Sep 17 00:00:00 2001 From: Jef LeCompte Date: Thu, 5 Dec 2019 22:19:09 -0500 Subject: [PATCH] Added URL to config and deprecated old configuration --- beetsplug/subsonicupdate.py | 107 +++++++++++++++++++++----------- docs/plugins/subsonicupdate.rst | 14 +++++ 2 files changed, 84 insertions(+), 37 deletions(-) diff --git a/beetsplug/subsonicupdate.py b/beetsplug/subsonicupdate.py index bb9e8a952..9cb8758d9 100644 --- a/beetsplug/subsonicupdate.py +++ b/beetsplug/subsonicupdate.py @@ -25,16 +25,68 @@ a "subsonic" section like the following: """ from __future__ import division, absolute_import, print_function -from beets.plugins import BeetsPlugin -from beets import config -import requests -import string import hashlib import random +import string + +import requests + +from beets import config +from beets.plugins import BeetsPlugin __author__ = 'https://github.com/maffo999' +def build_payload(): + """ To avoid sending plaintext passwords, authentication will be + performed via username, a token, and a 6 random + letters/numbers sequence. + The token is the concatenation of your password and the 6 random + letters/numbers (the salt) which is hashed with MD5. + """ + + user = config['subsonic']['user'].as_str() + password = config['subsonic']['pass'].as_str() + + # Pick the random sequence and salt the password + r = string.ascii_letters + string.digits + salt = "".join([random.choice(r) for n in range(6)]) + t = password + salt + token = hashlib.md5() + token.update(t.encode('utf-8')) + + # Put together the payload of the request to the server and the URL + return { + 'u': user, + 't': token.hexdigest(), + 's': salt, + 'v': '1.15.0', # Subsonic 6.1 and newer. + 'c': 'beets' + } + + +def formal_url(): + """ Formats URL to send request to Subsonic + DEPRECATED schema, host, port, contextpath; use ${url} + """ + + host = config['subsonic']['host'].as_str() + port = config['subsonic']['port'].get(int) + + context_path = config['subsonic']['contextpath'].as_str() + if context_path == '/': + context_path = '' + + url = config['subsonic']['url'].as_str() + if url and url.endsWith('/'): + url = url[:-1] + + if not url: + url = "http://{}:{}{}".format(host, port, context_path) + + return url + '/rest/startScan' + + class SubsonicUpdate(BeetsPlugin): def __init__(self): super(SubsonicUpdate, self).__init__() @@ -46,42 +98,23 @@ class SubsonicUpdate(BeetsPlugin): 'user': 'admin', 'pass': 'admin', 'contextpath': '/', + 'url': 'http://localhost:4040' }) + config['subsonic']['pass'].redact = True - self.register_listener('import', self.loaded) + self.register_listener('import', self.start_scan) - def loaded(self): - host = config['subsonic']['host'].as_str() - port = config['subsonic']['port'].get(int) - user = config['subsonic']['user'].as_str() - passw = config['subsonic']['pass'].as_str() - contextpath = config['subsonic']['contextpath'].as_str() + def start_scan(self): + url = formal_url() + payload = build_payload() - # To avoid sending plaintext passwords, authentication will be - # performed via username, a token, and a 6 random - # letters/numbers sequence. - # The token is the concatenation of your password and the 6 random - # letters/numbers (the salt) which is hashed with MD5. - - # Pick the random sequence and salt the password - r = string.ascii_letters + string.digits - salt = "".join([random.choice(r) for n in range(6)]) - t = passw + salt - token = hashlib.md5() - token.update(t.encode('utf-8')) - - # Put together the payload of the request to the server and the URL - payload = { - 'u': user, - 't': token.hexdigest(), - 's': salt, - 'v': '1.15.0', # Subsonic 6.1 and newer. - 'c': 'beets' - } - if contextpath == '/': - contextpath = '' - url = "http://{}:{}{}/rest/startScan".format(host, port, contextpath) response = requests.post(url, params=payload) - if response.status_code != 200: - self._log.error(u'Generic error, please try again later.') + if response.status_code == 403: + self._log.error(u'Server authentication failed') + elif response.status_code == 200: + self._log.debug(u'Updating Subsonic') + else: + self._log.error( + u'Generic error, please try again later [Status Code: {}]' + .format(response.status_code)) diff --git a/docs/plugins/subsonicupdate.rst b/docs/plugins/subsonicupdate.rst index 2d9331b7c..667bceb3e 100644 --- a/docs/plugins/subsonicupdate.rst +++ b/docs/plugins/subsonicupdate.rst @@ -12,6 +12,12 @@ Then, you'll probably want to configure the specifics of your Subsonic server. You can do that using a ``subsonic:`` section in your ``config.yaml``, which looks like this:: + subsonic: + url: https://mydomain.com:443/subsonic + user: username + pass: password + + # DEPRECATED subsonic: host: X.X.X.X port: 4040 @@ -30,6 +36,14 @@ Configuration The available options under the ``subsonic:`` section are: +- **url**: The Subsonic server resource. Default: ``http://localhost:4040`` + +Example: ``https://mydomain.com:443/subsonic`` + +\* Note: context path is optional + +DEPRECATED: + - **host**: The Subsonic server name/IP. Default: ``localhost`` - **port**: The Subsonic server port. Default: ``4040`` - **user**: The Subsonic user. Default: ``admin``