We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Subsonicupdate plugin broken in multiple paces
### Problem

Running the latest git version of beets causes the subsonicupdate plugin to fail with a generic "Error: 1".
The current code is broken in 2 places:

1. `def __get_version(self):`
Code is trying to retrieve the version in order to decide whether to authenticate with token or password: a much better choice than my original plan of assuming everyone would use an updated version and/or prefer token over password due to additional security.
In the current code, the REST API is called by passing only parameters 'c' and 'f': this API fails because it's not complete and the plugin stops processing.

2. `def start_scan(self):`
Assuming the authentication would go through, this call would fail anyway since the current code is splitting the API version in 3 values and passing them separately, e.g. `&v=1&v=61&v=1`, rather than `&v=1.61.1`

I have always been running an ancient version of beets with my original code for the plugin and I noticed this just today as I set up a new machine and installed beets form git repo through AUR.
It also seems I am the only user of this plugin given no other feedback has been filed so far, so I can understand if this fix doesn't get high priority.

### Setup

* OS: Arch Linux
* Python version: 3.9.6
* beets version: 1.5.0
* Turning off plugins made problem go away (yes/no):  disabling subsonicupdate plugin will prevent the error from happening

### Additional Info
Subsonic API reference: http://www.subsonic.org/pages/api.jsp


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `beetsplug/subsonicupdate.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # This file is part of beets.
3 # Copyright 2016, Adrian Sampson.
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
15 
16 """Updates Subsonic library on Beets import
17 Your Beets configuration file should contain
18 a "subsonic" section like the following:
19     subsonic:
20         url: https://mydomain.com:443/subsonic
21         user: username
22         pass: password
23 """
24 from __future__ import division, absolute_import, print_function
25 
26 import hashlib
27 import random
28 import string
29 
30 import requests
31 
32 from binascii import hexlify
33 from beets import config
34 from beets.plugins import BeetsPlugin
35 
36 __author__ = 'https://github.com/maffo999'
37 AUTH_TOKEN_VERSION = (1, 12)
38 
39 
40 class SubsonicUpdate(BeetsPlugin):
41     def __init__(self):
42         super(SubsonicUpdate, self).__init__()
43         # Set default configuration values
44         config['subsonic'].add({
45             'user': 'admin',
46             'pass': 'admin',
47             'url': 'http://localhost:4040',
48         })
49         config['subsonic']['pass'].redact = True
50         self._version = None
51         self._auth = None
52         self.register_listener('import', self.start_scan)
53 
54     @property
55     def version(self):
56         if self._version is None:
57             self._version = self.__get_version()
58         return self._version
59 
60     @property
61     def auth(self):
62         if self._auth is None:
63             if self.version is not None:
64                 if self.version > AUTH_TOKEN_VERSION:
65                     self._auth = "token"
66                 else:
67                     self._auth = "password"
68             self._log.info(
69                 u"using '{}' authentication method".format(self._auth))
70         return self._auth
71 
72     @staticmethod
73     def __create_token():
74         """Create salt and token from given password.
75 
76         :return: The generated salt and hashed token
77         """
78         password = config['subsonic']['pass'].as_str()
79 
80         # Pick the random sequence and salt the password
81         r = string.ascii_letters + string.digits
82         salt = "".join([random.choice(r) for _ in range(6)])
83         salted_password = password + salt
84         token = hashlib.md5(salted_password.encode('utf-8')).hexdigest()
85 
86         # Put together the payload of the request to the server and the URL
87         return salt, token
88 
89     @staticmethod
90     def __format_url(endpoint):
91         """Get the Subsonic URL to trigger the given endpoint.
92         Uses either the url config option or the deprecated host, port,
93         and context_path config options together.
94 
95         :return: Endpoint for updating Subsonic
96         """
97 
98         url = config['subsonic']['url'].as_str()
99         if url and url.endswith('/'):
100             url = url[:-1]
101 
102         # @deprecated("Use url config option instead")
103         if not url:
104             host = config['subsonic']['host'].as_str()
105             port = config['subsonic']['port'].get(int)
106             context_path = config['subsonic']['contextpath'].as_str()
107             if context_path == '/':
108                 context_path = ''
109             url = "http://{}:{}{}".format(host, port, context_path)
110 
111         return url + '/rest/{}'.format(endpoint)
112 
113     def __get_version(self):
114         url = self.__format_url("ping.view")
115         payload = {
116             'c': 'beets',
117             'f': 'json'
118         }
119         try:
120             response = requests.get(url, params=payload)
121             if response.status_code == 200:
122                 json = response.json()
123                 version = json['subsonic-response']['version']
124                 self._log.info(
125                     u'subsonic version:{0} '.format(version))
126                 return tuple(int(s) for s in version.split('.'))
127             else:
128                 self._log.error(u'Error: {0}', json)
129                 return None
130         except Exception as error:
131             self._log.error(u'Error: {0}'.format(error))
132             return None
133 
134     def start_scan(self):
135         user = config['subsonic']['user'].as_str()
136         url = self.__format_url("startScan.view")
137 
138         if self.auth == 'token':
139             salt, token = self.__create_token()
140             payload = {
141                 'u': user,
142                 't': token,
143                 's': salt,
144                 'v': self.version,  # Subsonic 6.1 and newer.
145                 'c': 'beets',
146                 'f': 'json'
147             }
148         elif self.auth == 'password':
149             password = config['subsonic']['pass'].as_str()
150             encpass = hexlify(password.encode()).decode()
151             payload = {
152                 'u': user,
153                 'p': 'enc:{}'.format(encpass),
154                 'v': self.version,
155                 'c': 'beets',
156                 'f': 'json'
157             }
158         else:
159             return
160         try:
161             response = requests.get(url, params=payload)
162             json = response.json()
163 
164             if response.status_code == 200 and \
165                     json['subsonic-response']['status'] == "ok":
166                 count = json['subsonic-response']['scanStatus']['count']
167                 self._log.info(
168                     u'Updating Subsonic; scanning {0} tracks'.format(count))
169             elif response.status_code == 200 and \
170                     json['subsonic-response']['status'] == "failed":
171                 error_message = json['subsonic-response']['error']['message']
172                 self._log.error(u'Error: {0}'.format(error_message))
173             else:
174                 self._log.error(u'Error: {0}', json)
175         except Exception as error:
176             self._log.error(u'Error: {0}'.format(error))
177
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/beetsplug/subsonicupdate.py b/beetsplug/subsonicupdate.py
--- a/beetsplug/subsonicupdate.py
+++ b/beetsplug/subsonicupdate.py
@@ -20,6 +20,14 @@
         url: https://mydomain.com:443/subsonic
         user: username
         pass: password
+        auth: token
+For older Subsonic versions, token authentication
+is not supported, use password instead:
+    subsonic:
+        url: https://mydomain.com:443/subsonic
+        user: username
+        pass: password
+        auth: pass
 """
 from __future__ import division, absolute_import, print_function
 
@@ -34,7 +42,6 @@
 from beets.plugins import BeetsPlugin
 
 __author__ = 'https://github.com/maffo999'
-AUTH_TOKEN_VERSION = (1, 12)
 
 
 class SubsonicUpdate(BeetsPlugin):
@@ -45,30 +52,11 @@
             'user': 'admin',
             'pass': 'admin',
             'url': 'http://localhost:4040',
+            'auth': 'token',
         })
         config['subsonic']['pass'].redact = True
-        self._version = None
-        self._auth = None
         self.register_listener('import', self.start_scan)
 
-    @property
-    def version(self):
-        if self._version is None:
-            self._version = self.__get_version()
-        return self._version
-
-    @property
-    def auth(self):
-        if self._auth is None:
-            if self.version is not None:
-                if self.version > AUTH_TOKEN_VERSION:
-                    self._auth = "token"
-                else:
-                    self._auth = "password"
-            self._log.info(
-                u"using '{}' authentication method".format(self._auth))
-        return self._auth
-
     @staticmethod
     def __create_token():
         """Create salt and token from given password.
@@ -110,48 +98,30 @@
 
         return url + '/rest/{}'.format(endpoint)
 
-    def __get_version(self):
-        url = self.__format_url("ping.view")
-        payload = {
-            'c': 'beets',
-            'f': 'json'
-        }
-        try:
-            response = requests.get(url, params=payload)
-            if response.status_code == 200:
-                json = response.json()
-                version = json['subsonic-response']['version']
-                self._log.info(
-                    u'subsonic version:{0} '.format(version))
-                return tuple(int(s) for s in version.split('.'))
-            else:
-                self._log.error(u'Error: {0}', json)
-                return None
-        except Exception as error:
-            self._log.error(u'Error: {0}'.format(error))
-            return None
-
     def start_scan(self):
         user = config['subsonic']['user'].as_str()
-        url = self.__format_url("startScan.view")
+        auth = config['subsonic']['auth'].as_str()
+        url = self.__format_url("startScan")
+        self._log.debug(u'URL is {0}', url)
+        self._log.debug(u'auth type is {0}', config['subsonic']['auth'])
 
-        if self.auth == 'token':
+        if auth == "token":
             salt, token = self.__create_token()
             payload = {
                 'u': user,
                 't': token,
                 's': salt,
-                'v': self.version,  # Subsonic 6.1 and newer.
+                'v': '1.13.0',  # Subsonic 5.3 and newer
                 'c': 'beets',
                 'f': 'json'
             }
-        elif self.auth == 'password':
+        elif auth == "password":
             password = config['subsonic']['pass'].as_str()
             encpass = hexlify(password.encode()).decode()
             payload = {
                 'u': user,
                 'p': 'enc:{}'.format(encpass),
-                'v': self.version,
+                'v': '1.12.0',
                 'c': 'beets',
                 'f': 'json'
             }

{"golden_diff": "diff --git a/beetsplug/subsonicupdate.py b/beetsplug/subsonicupdate.py\n--- a/beetsplug/subsonicupdate.py\n+++ b/beetsplug/subsonicupdate.py\n@@ -20,6 +20,14 @@\n         url: https://mydomain.com:443/subsonic\n         user: username\n         pass: password\n+        auth: token\n+For older Subsonic versions, token authentication\n+is not supported, use password instead:\n+    subsonic:\n+        url: https://mydomain.com:443/subsonic\n+        user: username\n+        pass: password\n+        auth: pass\n \"\"\"\n from __future__ import division, absolute_import, print_function\n \n@@ -34,7 +42,6 @@\n from beets.plugins import BeetsPlugin\n \n __author__ = 'https://github.com/maffo999'\n-AUTH_TOKEN_VERSION = (1, 12)\n \n \n class SubsonicUpdate(BeetsPlugin):\n@@ -45,30 +52,11 @@\n             'user': 'admin',\n             'pass': 'admin',\n             'url': 'http://localhost:4040',\n+            'auth': 'token',\n         })\n         config['subsonic']['pass'].redact = True\n-        self._version = None\n-        self._auth = None\n         self.register_listener('import', self.start_scan)\n \n-    @property\n-    def version(self):\n-        if self._version is None:\n-            self._version = self.__get_version()\n-        return self._version\n-\n-    @property\n-    def auth(self):\n-        if self._auth is None:\n-            if self.version is not None:\n-                if self.version > AUTH_TOKEN_VERSION:\n-                    self._auth = \"token\"\n-                else:\n-                    self._auth = \"password\"\n-            self._log.info(\n-                u\"using '{}' authentication method\".format(self._auth))\n-        return self._auth\n-\n     @staticmethod\n     def __create_token():\n         \"\"\"Create salt and token from given password.\n@@ -110,48 +98,30 @@\n \n         return url + '/rest/{}'.format(endpoint)\n \n-    def __get_version(self):\n-        url = self.__format_url(\"ping.view\")\n-        payload = {\n-            'c': 'beets',\n-            'f': 'json'\n-        }\n-        try:\n-            response = requests.get(url, params=payload)\n-            if response.status_code == 200:\n-                json = response.json()\n-                version = json['subsonic-response']['version']\n-                self._log.info(\n-                    u'subsonic version:{0} '.format(version))\n-                return tuple(int(s) for s in version.split('.'))\n-            else:\n-                self._log.error(u'Error: {0}', json)\n-                return None\n-        except Exception as error:\n-            self._log.error(u'Error: {0}'.format(error))\n-            return None\n-\n     def start_scan(self):\n         user = config['subsonic']['user'].as_str()\n-        url = self.__format_url(\"startScan.view\")\n+        auth = config['subsonic']['auth'].as_str()\n+        url = self.__format_url(\"startScan\")\n+        self._log.debug(u'URL is {0}', url)\n+        self._log.debug(u'auth type is {0}', config['subsonic']['auth'])\n \n-        if self.auth == 'token':\n+        if auth == \"token\":\n             salt, token = self.__create_token()\n             payload = {\n                 'u': user,\n                 't': token,\n                 's': salt,\n-                'v': self.version,  # Subsonic 6.1 and newer.\n+                'v': '1.13.0',  # Subsonic 5.3 and newer\n                 'c': 'beets',\n                 'f': 'json'\n             }\n-        elif self.auth == 'password':\n+        elif auth == \"password\":\n             password = config['subsonic']['pass'].as_str()\n             encpass = hexlify(password.encode()).decode()\n             payload = {\n                 'u': user,\n                 'p': 'enc:{}'.format(encpass),\n-                'v': self.version,\n+                'v': '1.12.0',\n                 'c': 'beets',\n                 'f': 'json'\n             }\n", "issue": "Subsonicupdate plugin broken in multiple paces\n### Problem\r\n\r\nRunning the latest git version of beets causes the subsonicupdate plugin to fail with a generic \"Error: 1\".\r\nThe current code is broken in 2 places:\r\n\r\n1. `def __get_version(self):`\r\nCode is trying to retrieve the version in order to decide whether to authenticate with token or password: a much better choice than my original plan of assuming everyone would use an updated version and/or prefer token over password due to additional security.\r\nIn the current code, the REST API is called by passing only parameters 'c' and 'f': this API fails because it's not complete and the plugin stops processing.\r\n\r\n2. `def start_scan(self):`\r\nAssuming the authentication would go through, this call would fail anyway since the current code is splitting the API version in 3 values and passing them separately, e.g. `&v=1&v=61&v=1`, rather than `&v=1.61.1`\r\n\r\nI have always been running an ancient version of beets with my original code for the plugin and I noticed this just today as I set up a new machine and installed beets form git repo through AUR.\r\nIt also seems I am the only user of this plugin given no other feedback has been filed so far, so I can understand if this fix doesn't get high priority.\r\n\r\n### Setup\r\n\r\n* OS: Arch Linux\r\n* Python version: 3.9.6\r\n* beets version: 1.5.0\r\n* Turning off plugins made problem go away (yes/no):  disabling subsonicupdate plugin will prevent the error from happening\r\n\r\n### Additional Info\r\nSubsonic API reference: http://www.subsonic.org/pages/api.jsp\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# This file is part of beets.\n# Copyright 2016, Adrian Sampson.\n#\n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n\n\"\"\"Updates Subsonic library on Beets import\nYour Beets configuration file should contain\na \"subsonic\" section like the following:\n    subsonic:\n        url: https://mydomain.com:443/subsonic\n        user: username\n        pass: password\n\"\"\"\nfrom __future__ import division, absolute_import, print_function\n\nimport hashlib\nimport random\nimport string\n\nimport requests\n\nfrom binascii import hexlify\nfrom beets import config\nfrom beets.plugins import BeetsPlugin\n\n__author__ = 'https://github.com/maffo999'\nAUTH_TOKEN_VERSION = (1, 12)\n\n\nclass SubsonicUpdate(BeetsPlugin):\n    def __init__(self):\n        super(SubsonicUpdate, self).__init__()\n        # Set default configuration values\n        config['subsonic'].add({\n            'user': 'admin',\n            'pass': 'admin',\n            'url': 'http://localhost:4040',\n        })\n        config['subsonic']['pass'].redact = True\n        self._version = None\n        self._auth = None\n        self.register_listener('import', self.start_scan)\n\n    @property\n    def version(self):\n        if self._version is None:\n            self._version = self.__get_version()\n        return self._version\n\n    @property\n    def auth(self):\n        if self._auth is None:\n            if self.version is not None:\n                if self.version > AUTH_TOKEN_VERSION:\n                    self._auth = \"token\"\n                else:\n                    self._auth = \"password\"\n            self._log.info(\n                u\"using '{}' authentication method\".format(self._auth))\n        return self._auth\n\n    @staticmethod\n    def __create_token():\n        \"\"\"Create salt and token from given password.\n\n        :return: The generated salt and hashed token\n        \"\"\"\n        password = config['subsonic']['pass'].as_str()\n\n        # Pick the random sequence and salt the password\n        r = string.ascii_letters + string.digits\n        salt = \"\".join([random.choice(r) for _ in range(6)])\n        salted_password = password + salt\n        token = hashlib.md5(salted_password.encode('utf-8')).hexdigest()\n\n        # Put together the payload of the request to the server and the URL\n        return salt, token\n\n    @staticmethod\n    def __format_url(endpoint):\n        \"\"\"Get the Subsonic URL to trigger the given endpoint.\n        Uses either the url config option or the deprecated host, port,\n        and context_path config options together.\n\n        :return: Endpoint for updating Subsonic\n        \"\"\"\n\n        url = config['subsonic']['url'].as_str()\n        if url and url.endswith('/'):\n            url = url[:-1]\n\n        # @deprecated(\"Use url config option instead\")\n        if not url:\n            host = config['subsonic']['host'].as_str()\n            port = config['subsonic']['port'].get(int)\n            context_path = config['subsonic']['contextpath'].as_str()\n            if context_path == '/':\n                context_path = ''\n            url = \"http://{}:{}{}\".format(host, port, context_path)\n\n        return url + '/rest/{}'.format(endpoint)\n\n    def __get_version(self):\n        url = self.__format_url(\"ping.view\")\n        payload = {\n            'c': 'beets',\n            'f': 'json'\n        }\n        try:\n            response = requests.get(url, params=payload)\n            if response.status_code == 200:\n                json = response.json()\n                version = json['subsonic-response']['version']\n                self._log.info(\n                    u'subsonic version:{0} '.format(version))\n                return tuple(int(s) for s in version.split('.'))\n            else:\n                self._log.error(u'Error: {0}', json)\n                return None\n        except Exception as error:\n            self._log.error(u'Error: {0}'.format(error))\n            return None\n\n    def start_scan(self):\n        user = config['subsonic']['user'].as_str()\n        url = self.__format_url(\"startScan.view\")\n\n        if self.auth == 'token':\n            salt, token = self.__create_token()\n            payload = {\n                'u': user,\n                't': token,\n                's': salt,\n                'v': self.version,  # Subsonic 6.1 and newer.\n                'c': 'beets',\n                'f': 'json'\n            }\n        elif self.auth == 'password':\n            password = config['subsonic']['pass'].as_str()\n            encpass = hexlify(password.encode()).decode()\n            payload = {\n                'u': user,\n                'p': 'enc:{}'.format(encpass),\n                'v': self.version,\n                'c': 'beets',\n                'f': 'json'\n            }\n        else:\n            return\n        try:\n            response = requests.get(url, params=payload)\n            json = response.json()\n\n            if response.status_code == 200 and \\\n                    json['subsonic-response']['status'] == \"ok\":\n                count = json['subsonic-response']['scanStatus']['count']\n                self._log.info(\n                    u'Updating Subsonic; scanning {0} tracks'.format(count))\n            elif response.status_code == 200 and \\\n                    json['subsonic-response']['status'] == \"failed\":\n                error_message = json['subsonic-response']['error']['message']\n                self._log.error(u'Error: {0}'.format(error_message))\n            else:\n                self._log.error(u'Error: {0}', json)\n        except Exception as error:\n            self._log.error(u'Error: {0}'.format(error))\n", "path": "beetsplug/subsonicupdate.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# This file is part of beets.\n# Copyright 2016, Adrian Sampson.\n#\n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n\n\"\"\"Updates Subsonic library on Beets import\nYour Beets configuration file should contain\na \"subsonic\" section like the following:\n    subsonic:\n        url: https://mydomain.com:443/subsonic\n        user: username\n        pass: password\n        auth: token\nFor older Subsonic versions, token authentication\nis not supported, use password instead:\n    subsonic:\n        url: https://mydomain.com:443/subsonic\n        user: username\n        pass: password\n        auth: pass\n\"\"\"\nfrom __future__ import division, absolute_import, print_function\n\nimport hashlib\nimport random\nimport string\n\nimport requests\n\nfrom binascii import hexlify\nfrom beets import config\nfrom beets.plugins import BeetsPlugin\n\n__author__ = 'https://github.com/maffo999'\n\n\nclass SubsonicUpdate(BeetsPlugin):\n    def __init__(self):\n        super(SubsonicUpdate, self).__init__()\n        # Set default configuration values\n        config['subsonic'].add({\n            'user': 'admin',\n            'pass': 'admin',\n            'url': 'http://localhost:4040',\n            'auth': 'token',\n        })\n        config['subsonic']['pass'].redact = True\n        self.register_listener('import', self.start_scan)\n\n    @staticmethod\n    def __create_token():\n        \"\"\"Create salt and token from given password.\n\n        :return: The generated salt and hashed token\n        \"\"\"\n        password = config['subsonic']['pass'].as_str()\n\n        # Pick the random sequence and salt the password\n        r = string.ascii_letters + string.digits\n        salt = \"\".join([random.choice(r) for _ in range(6)])\n        salted_password = password + salt\n        token = hashlib.md5(salted_password.encode('utf-8')).hexdigest()\n\n        # Put together the payload of the request to the server and the URL\n        return salt, token\n\n    @staticmethod\n    def __format_url(endpoint):\n        \"\"\"Get the Subsonic URL to trigger the given endpoint.\n        Uses either the url config option or the deprecated host, port,\n        and context_path config options together.\n\n        :return: Endpoint for updating Subsonic\n        \"\"\"\n\n        url = config['subsonic']['url'].as_str()\n        if url and url.endswith('/'):\n            url = url[:-1]\n\n        # @deprecated(\"Use url config option instead\")\n        if not url:\n            host = config['subsonic']['host'].as_str()\n            port = config['subsonic']['port'].get(int)\n            context_path = config['subsonic']['contextpath'].as_str()\n            if context_path == '/':\n                context_path = ''\n            url = \"http://{}:{}{}\".format(host, port, context_path)\n\n        return url + '/rest/{}'.format(endpoint)\n\n    def start_scan(self):\n        user = config['subsonic']['user'].as_str()\n        auth = config['subsonic']['auth'].as_str()\n        url = self.__format_url(\"startScan\")\n        self._log.debug(u'URL is {0}', url)\n        self._log.debug(u'auth type is {0}', config['subsonic']['auth'])\n\n        if auth == \"token\":\n            salt, token = self.__create_token()\n            payload = {\n                'u': user,\n                't': token,\n                's': salt,\n                'v': '1.13.0',  # Subsonic 5.3 and newer\n                'c': 'beets',\n                'f': 'json'\n            }\n        elif auth == \"password\":\n            password = config['subsonic']['pass'].as_str()\n            encpass = hexlify(password.encode()).decode()\n            payload = {\n                'u': user,\n                'p': 'enc:{}'.format(encpass),\n                'v': '1.12.0',\n                'c': 'beets',\n                'f': 'json'\n            }\n        else:\n            return\n        try:\n            response = requests.get(url, params=payload)\n            json = response.json()\n\n            if response.status_code == 200 and \\\n                    json['subsonic-response']['status'] == \"ok\":\n                count = json['subsonic-response']['scanStatus']['count']\n                self._log.info(\n                    u'Updating Subsonic; scanning {0} tracks'.format(count))\n            elif response.status_code == 200 and \\\n                    json['subsonic-response']['status'] == \"failed\":\n                error_message = json['subsonic-response']['error']['message']\n                self._log.error(u'Error: {0}'.format(error_message))\n            else:\n                self._log.error(u'Error: {0}', json)\n        except Exception as error:\n            self._log.error(u'Error: {0}'.format(error))\n", "path": "beetsplug/subsonicupdate.py"}]}