mirror of
https://github.com/beetbox/beets.git
synced 2026-01-30 03:54:21 +01:00
Merge pull request #3598 from jef/jef/fix-str
fix: use `endwith()` instead of `endWith()`
This commit is contained in:
commit
1b4686eebc
2 changed files with 154 additions and 43 deletions
|
|
@ -35,47 +35,6 @@ from beets.plugins import BeetsPlugin
|
|||
__author__ = 'https://github.com/maffo999'
|
||||
|
||||
|
||||
def create_token():
|
||||
"""Create salt and token from given password.
|
||||
|
||||
:return: The generated salt and hashed token
|
||||
"""
|
||||
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 _ in range(6)])
|
||||
salted_password = password + salt
|
||||
token = hashlib.md5().update(salted_password.encode('utf-8')).hexdigest()
|
||||
|
||||
# Put together the payload of the request to the server and the URL
|
||||
return salt, token
|
||||
|
||||
|
||||
def format_url():
|
||||
"""Get the Subsonic URL to trigger a scan. Uses either the url
|
||||
config option or the deprecated host, port, and context_path config
|
||||
options together.
|
||||
|
||||
:return: Endpoint for updating Subsonic
|
||||
"""
|
||||
|
||||
url = config['subsonic']['url'].as_str()
|
||||
if url and url.endsWith('/'):
|
||||
url = url[:-1]
|
||||
|
||||
# @deprecated("Use url config option instead")
|
||||
if not 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 = "http://{}:{}{}".format(host, port, context_path)
|
||||
|
||||
return url + '/rest/startScan'
|
||||
|
||||
|
||||
class SubsonicUpdate(BeetsPlugin):
|
||||
def __init__(self):
|
||||
super(SubsonicUpdate, self).__init__()
|
||||
|
|
@ -90,10 +49,51 @@ class SubsonicUpdate(BeetsPlugin):
|
|||
config['subsonic']['pass'].redact = True
|
||||
self.register_listener('import', self.start_scan)
|
||||
|
||||
@staticmethod
|
||||
def __create_token():
|
||||
"""Create salt and token from given password.
|
||||
|
||||
:return: The generated salt and hashed token
|
||||
"""
|
||||
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 _ in range(6)])
|
||||
salted_password = password + salt
|
||||
token = hashlib.md5(salted_password.encode('utf-8')).hexdigest()
|
||||
|
||||
# Put together the payload of the request to the server and the URL
|
||||
return salt, token
|
||||
|
||||
@staticmethod
|
||||
def __format_url():
|
||||
"""Get the Subsonic URL to trigger a scan. Uses either the url
|
||||
config option or the deprecated host, port, and context_path config
|
||||
options together.
|
||||
|
||||
:return: Endpoint for updating Subsonic
|
||||
"""
|
||||
|
||||
url = config['subsonic']['url'].as_str()
|
||||
if url and url.endswith('/'):
|
||||
url = url[:-1]
|
||||
|
||||
# @deprecated("Use url config option instead")
|
||||
if not 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 = "http://{}:{}{}".format(host, port, context_path)
|
||||
|
||||
return url + '/rest/startScan'
|
||||
|
||||
def start_scan(self):
|
||||
user = config['subsonic']['user'].as_str()
|
||||
url = format_url()
|
||||
salt, token = create_token()
|
||||
url = self.__format_url()
|
||||
salt, token = self.__create_token()
|
||||
|
||||
payload = {
|
||||
'u': user,
|
||||
|
|
|
|||
111
test/test_subsonic.py
Normal file
111
test/test_subsonic.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Tests for the 'subsonic' plugin"""
|
||||
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
import requests
|
||||
import responses
|
||||
import unittest
|
||||
|
||||
from test import _common
|
||||
from beets import config
|
||||
from beetsplug import subsonicupdate
|
||||
from test.helper import TestHelper
|
||||
from six.moves.urllib.parse import parse_qs, urlparse
|
||||
|
||||
|
||||
class ArgumentsMock(object):
|
||||
def __init__(self, mode, show_failures):
|
||||
self.mode = mode
|
||||
self.show_failures = show_failures
|
||||
self.verbose = 1
|
||||
|
||||
|
||||
def _params(url):
|
||||
"""Get the query parameters from a URL."""
|
||||
return parse_qs(urlparse(url).query)
|
||||
|
||||
|
||||
class SubsonicPluginTest(_common.TestCase, TestHelper):
|
||||
@responses.activate
|
||||
def setUp(self):
|
||||
config.clear()
|
||||
self.setup_beets()
|
||||
|
||||
config["subsonic"]["user"] = "admin"
|
||||
config["subsonic"]["pass"] = "admin"
|
||||
config["subsonic"]["url"] = "http://localhost:4040"
|
||||
|
||||
self.subsonicupdate = subsonicupdate.SubsonicUpdate()
|
||||
|
||||
def tearDown(self):
|
||||
self.teardown_beets()
|
||||
|
||||
@responses.activate
|
||||
def test_start_scan(self):
|
||||
responses.add(
|
||||
responses.POST,
|
||||
'http://localhost:4040/rest/startScan',
|
||||
status=200
|
||||
)
|
||||
|
||||
self.subsonicupdate.start_scan()
|
||||
|
||||
@responses.activate
|
||||
def test_url_with_extra_forward_slash_url(self):
|
||||
config["subsonic"]["url"] = "http://localhost:4040/contextPath"
|
||||
|
||||
responses.add(
|
||||
responses.POST,
|
||||
'http://localhost:4040/contextPath/rest/startScan',
|
||||
status=200
|
||||
)
|
||||
|
||||
self.subsonicupdate.start_scan()
|
||||
|
||||
@responses.activate
|
||||
def test_url_with_context_path(self):
|
||||
config["subsonic"]["url"] = "http://localhost:4040/"
|
||||
|
||||
responses.add(
|
||||
responses.POST,
|
||||
'http://localhost:4040/rest/startScan',
|
||||
status=200
|
||||
)
|
||||
|
||||
self.subsonicupdate.start_scan()
|
||||
|
||||
@responses.activate
|
||||
def test_url_with_missing_port(self):
|
||||
config["subsonic"]["url"] = "http://localhost/airsonic"
|
||||
|
||||
responses.add(
|
||||
responses.POST,
|
||||
'http://localhost:4040/rest/startScan',
|
||||
status=200
|
||||
)
|
||||
|
||||
with self.assertRaises(requests.exceptions.ConnectionError):
|
||||
self.subsonicupdate.start_scan()
|
||||
|
||||
@responses.activate
|
||||
def test_url_with_missing_schema(self):
|
||||
config["subsonic"]["url"] = "localhost:4040/airsonic"
|
||||
|
||||
responses.add(
|
||||
responses.POST,
|
||||
'http://localhost:4040/rest/startScan',
|
||||
status=200
|
||||
)
|
||||
|
||||
with self.assertRaises(requests.exceptions.InvalidSchema):
|
||||
self.subsonicupdate.start_scan()
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
Loading…
Reference in a new issue