We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
qBittorrent 4.2.0 can't work
Hi
  I've upgrade to qBittorrent 4.2.0 and flexget can't add new tasks to qBittorrent.
  
FlexGet version: 3.0.11
Python version: 3.7.5
qBittorrent 4.2.0 can't work
Hi
  I've upgrade to qBittorrent 4.2.0 and flexget can't add new tasks to qBittorrent.
  
FlexGet version: 3.0.11
Python version: 3.7.5

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `flexget/plugins/clients/qbittorrent.py`
Content:
```
1 import logging
2 import os
3 
4 from requests import Session
5 from requests.exceptions import RequestException
6 
7 from flexget import plugin
8 from flexget.event import event
9 from flexget.utils.template import RenderError
10 
11 log = logging.getLogger('qbittorrent')
12 
13 
14 class OutputQBitTorrent:
15     """
16     Example:
17 
18       qbittorrent:
19         username: <USERNAME> (default: (none))
20         password: <PASSWORD> (default: (none))
21         host: <HOSTNAME> (default: localhost)
22         port: <PORT> (default: 8080)
23         use_ssl: <SSL> (default: False)
24         verify_cert: <VERIFY> (default: True)
25         path: <OUTPUT_DIR> (default: (none))
26         label: <LABEL> (default: (none))
27         maxupspeed: <torrent upload speed limit> (default: 0)
28         maxdownspeed: <torrent download speed limit> (default: 0)
29         add_paused: <ADD_PAUSED> (default: False)
30     """
31 
32     schema = {
33         'anyOf': [
34             {'type': 'boolean'},
35             {
36                 'type': 'object',
37                 'properties': {
38                     'username': {'type': 'string'},
39                     'password': {'type': 'string'},
40                     'host': {'type': 'string'},
41                     'port': {'type': 'integer'},
42                     'use_ssl': {'type': 'boolean'},
43                     'verify_cert': {'type': 'boolean'},
44                     'path': {'type': 'string'},
45                     'label': {'type': 'string'},
46                     'maxupspeed': {'type': 'integer'},
47                     'maxdownspeed': {'type': 'integer'},
48                     'fail_html': {'type': 'boolean'},
49                     'add_paused': {'type': 'boolean'},
50                 },
51                 'additionalProperties': False,
52             },
53         ]
54     }
55 
56     def _request(self, method, url, msg_on_fail=None, **kwargs):
57         try:
58             response = self.session.request(method, url, **kwargs)
59             if response == 'Fails.':
60                 msg = (
61                     'Failure. URL: {}, data: {}'.format(url, kwargs)
62                     if not msg_on_fail
63                     else msg_on_fail
64                 )
65             else:
66                 return response
67         except RequestException as e:
68             msg = str(e)
69         raise plugin.PluginError(
70             'Error when trying to send request to qBittorrent: {}'.format(msg)
71         )
72 
73     def connect(self, config):
74         """
75         Connect to qBittorrent Web UI. Username and password not necessary
76         if 'Bypass authentication for localhost' is checked and host is
77         'localhost'.
78         """
79         self.session = Session()
80         self.url = '{}://{}:{}'.format(
81             'https' if config['use_ssl'] else 'http', config['host'], config['port']
82         )
83         if config.get('username') and config.get('password'):
84             data = {'username': config['username'], 'password': config['password']}
85             self._request(
86                 'post',
87                 self.url + '/login',
88                 data=data,
89                 msg_on_fail='Authentication failed.',
90                 verify=config['verify_cert'],
91             )
92         log.debug('Successfully connected to qBittorrent')
93         self.connected = True
94 
95     def add_torrent_file(self, file_path, data, verify_cert):
96         if not self.connected:
97             raise plugin.PluginError('Not connected.')
98         multipart_data = {k: (None, v) for k, v in data.items()}
99         with open(file_path, 'rb') as f:
100             multipart_data['torrents'] = f
101             self._request(
102                 'post',
103                 self.url + '/command/upload',
104                 msg_on_fail='Failed to add file to qBittorrent',
105                 files=multipart_data,
106                 verify=verify_cert,
107             )
108         log.debug('Added torrent file %s to qBittorrent', file_path)
109 
110     def add_torrent_url(self, url, data, verify_cert):
111         if not self.connected:
112             raise plugin.PluginError('Not connected.')
113         data['urls'] = url
114         multipart_data = {k: (None, v) for k, v in data.items()}
115         self._request(
116             'post',
117             self.url + '/command/download',
118             msg_on_fail='Failed to add file to qBittorrent',
119             files=multipart_data,
120             verify=verify_cert,
121         )
122         log.debug('Added url %s to qBittorrent', url)
123 
124     def prepare_config(self, config):
125         if isinstance(config, bool):
126             config = {'enabled': config}
127         config.setdefault('enabled', True)
128         config.setdefault('host', 'localhost')
129         config.setdefault('port', 8080)
130         config.setdefault('use_ssl', False)
131         config.setdefault('verify_cert', True)
132         config.setdefault('label', '')
133         config.setdefault('maxupspeed', 0)
134         config.setdefault('maxdownspeed', 0)
135         config.setdefault('fail_html', True)
136         return config
137 
138     def add_entries(self, task, config):
139         for entry in task.accepted:
140             form_data = {}
141             try:
142                 save_path = entry.render(entry.get('path', config.get('path', '')))
143                 if save_path:
144                     form_data['savepath'] = save_path
145             except RenderError as e:
146                 log.error('Error setting path for %s: %s', entry['title'], e)
147 
148             label = entry.get('label', config.get('label'))
149             if label:
150                 form_data['label'] = label  # qBittorrent v3.3.3-
151                 form_data['category'] = label  # qBittorrent v3.3.4+
152 
153             add_paused = entry.get('add_paused', config.get('add_paused'))
154             if add_paused:
155                 form_data['paused'] = 'true'
156 
157             maxupspeed = entry.get('maxupspeed', config.get('maxupspeed'))
158             if maxupspeed:
159                 form_data['upLimit'] = maxupspeed * 1024
160 
161             maxdownspeed = entry.get('maxdownspeed', config.get('maxdownspeed'))
162             if maxdownspeed:
163                 form_data['dlLimit'] = maxdownspeed * 1024
164 
165             is_magnet = entry['url'].startswith('magnet:')
166 
167             if task.manager.options.test:
168                 log.info('Test mode.')
169                 log.info('Would add torrent to qBittorrent with:')
170                 if not is_magnet:
171                     log.info('File: %s', entry.get('file'))
172                 else:
173                     log.info('Url: %s', entry.get('url'))
174                 log.info('Save path: %s', form_data.get('savepath'))
175                 log.info('Label: %s', form_data.get('label'))
176                 log.info('Paused: %s', form_data.get('paused', 'false'))
177                 if maxupspeed:
178                     log.info('Upload Speed Limit: %d', form_data.get('upLimit'))
179                 if maxdownspeed:
180                     log.info('Download Speed Limit: %d', form_data.get('dlLimit'))
181                 continue
182 
183             if not is_magnet:
184                 if 'file' not in entry:
185                     entry.fail('File missing?')
186                     continue
187                 if not os.path.exists(entry['file']):
188                     tmp_path = os.path.join(task.manager.config_base, 'temp')
189                     log.debug('entry: %s', entry)
190                     log.debug('temp: %s', ', '.join(os.listdir(tmp_path)))
191                     entry.fail("Downloaded temp file '%s' doesn't exist!?" % entry['file'])
192                     continue
193                 self.add_torrent_file(entry['file'], form_data, config['verify_cert'])
194             else:
195                 self.add_torrent_url(entry['url'], form_data, config['verify_cert'])
196 
197     @plugin.priority(120)
198     def on_task_download(self, task, config):
199         """
200         Call download plugin to generate torrent files to load into
201         qBittorrent.
202         """
203         config = self.prepare_config(config)
204         if not config['enabled']:
205             return
206         if 'download' not in task.config:
207             download = plugin.get('download', self)
208             download.get_temp_files(task, handle_magnets=True, fail_html=config['fail_html'])
209 
210     @plugin.priority(135)
211     def on_task_output(self, task, config):
212         """Add torrents to qBittorrent at exit."""
213         if task.accepted:
214             config = self.prepare_config(config)
215             self.connect(config)
216             self.add_entries(task, config)
217 
218 
219 @event('plugin.register')
220 def register_plugin():
221     plugin.register(OutputQBitTorrent, 'qbittorrent', api_ver=2)
222
```
--- 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/flexget/plugins/clients/qbittorrent.py b/flexget/plugins/clients/qbittorrent.py
--- a/flexget/plugins/clients/qbittorrent.py
+++ b/flexget/plugins/clients/qbittorrent.py
@@ -56,14 +56,41 @@
     def _request(self, method, url, msg_on_fail=None, **kwargs):
         try:
             response = self.session.request(method, url, **kwargs)
-            if response == 'Fails.':
+            if response.text == "Ok.":
+                return response       
+            else:
                 msg = (
                     'Failure. URL: {}, data: {}'.format(url, kwargs)
                     if not msg_on_fail
                     else msg_on_fail
                 )
-            else:
-                return response
+        except RequestException as e:
+            msg = str(e)
+        raise plugin.PluginError(
+            'Error when trying to send request to qBittorrent: {}'.format(msg)
+        )
+        
+    def check_api_version(self, msg_on_fail):
+        try:
+            url = self.url + "/api/v2/app/webapiVersion"
+            response = self.session.request('get', url)
+            if response.status_code != 404:
+                self.api_url_login = '/api/v2/auth/login'
+                self.api_url_add = '/api/v2/torrents/add'
+                return response         
+            
+            url = self.url + "/version/api"
+            response = self.session.request('get', url)
+            if response.status_code != 404:
+                self.api_url_login = '/login'
+                self.api_url_add = '/command/upload'
+                return response         
+            
+            msg = (
+                'Failure. URL: {}'.format(url)
+                if not msg_on_fail
+                else msg_on_fail
+            )
         except RequestException as e:
             msg = str(e)
         raise plugin.PluginError(
@@ -80,11 +107,12 @@
         self.url = '{}://{}:{}'.format(
             'https' if config['use_ssl'] else 'http', config['host'], config['port']
         )
+        self.check_api_version('Check API version failed.')
         if config.get('username') and config.get('password'):
             data = {'username': config['username'], 'password': config['password']}
             self._request(
                 'post',
-                self.url + '/login',
+                self.url + self.api_url_login,
                 data=data,
                 msg_on_fail='Authentication failed.',
                 verify=config['verify_cert'],
@@ -100,7 +128,7 @@
             multipart_data['torrents'] = f
             self._request(
                 'post',
-                self.url + '/command/upload',
+                self.url + self.api_url_add,
                 msg_on_fail='Failed to add file to qBittorrent',
                 files=multipart_data,
                 verify=verify_cert,
@@ -114,7 +142,7 @@
         multipart_data = {k: (None, v) for k, v in data.items()}
         self._request(
             'post',
-            self.url + '/command/download',
+            self.url + self.api_url_add,
             msg_on_fail='Failed to add file to qBittorrent',
             files=multipart_data,
             verify=verify_cert,

{"golden_diff": "diff --git a/flexget/plugins/clients/qbittorrent.py b/flexget/plugins/clients/qbittorrent.py\n--- a/flexget/plugins/clients/qbittorrent.py\n+++ b/flexget/plugins/clients/qbittorrent.py\n@@ -56,14 +56,41 @@\n     def _request(self, method, url, msg_on_fail=None, **kwargs):\n         try:\n             response = self.session.request(method, url, **kwargs)\n-            if response == 'Fails.':\n+            if response.text == \"Ok.\":\n+                return response       \n+            else:\n                 msg = (\n                     'Failure. URL: {}, data: {}'.format(url, kwargs)\n                     if not msg_on_fail\n                     else msg_on_fail\n                 )\n-            else:\n-                return response\n+        except RequestException as e:\n+            msg = str(e)\n+        raise plugin.PluginError(\n+            'Error when trying to send request to qBittorrent: {}'.format(msg)\n+        )\n+        \n+    def check_api_version(self, msg_on_fail):\n+        try:\n+            url = self.url + \"/api/v2/app/webapiVersion\"\n+            response = self.session.request('get', url)\n+            if response.status_code != 404:\n+                self.api_url_login = '/api/v2/auth/login'\n+                self.api_url_add = '/api/v2/torrents/add'\n+                return response         \n+            \n+            url = self.url + \"/version/api\"\n+            response = self.session.request('get', url)\n+            if response.status_code != 404:\n+                self.api_url_login = '/login'\n+                self.api_url_add = '/command/upload'\n+                return response         \n+            \n+            msg = (\n+                'Failure. URL: {}'.format(url)\n+                if not msg_on_fail\n+                else msg_on_fail\n+            )\n         except RequestException as e:\n             msg = str(e)\n         raise plugin.PluginError(\n@@ -80,11 +107,12 @@\n         self.url = '{}://{}:{}'.format(\n             'https' if config['use_ssl'] else 'http', config['host'], config['port']\n         )\n+        self.check_api_version('Check API version failed.')\n         if config.get('username') and config.get('password'):\n             data = {'username': config['username'], 'password': config['password']}\n             self._request(\n                 'post',\n-                self.url + '/login',\n+                self.url + self.api_url_login,\n                 data=data,\n                 msg_on_fail='Authentication failed.',\n                 verify=config['verify_cert'],\n@@ -100,7 +128,7 @@\n             multipart_data['torrents'] = f\n             self._request(\n                 'post',\n-                self.url + '/command/upload',\n+                self.url + self.api_url_add,\n                 msg_on_fail='Failed to add file to qBittorrent',\n                 files=multipart_data,\n                 verify=verify_cert,\n@@ -114,7 +142,7 @@\n         multipart_data = {k: (None, v) for k, v in data.items()}\n         self._request(\n             'post',\n-            self.url + '/command/download',\n+            self.url + self.api_url_add,\n             msg_on_fail='Failed to add file to qBittorrent',\n             files=multipart_data,\n             verify=verify_cert,\n", "issue": "qBittorrent 4.2.0 can't work\nHi\r\n  I've upgrade to qBittorrent 4.2.0 and flexget can't add new tasks to qBittorrent.\r\n  \r\nFlexGet version: 3.0.11\r\nPython version: 3.7.5\nqBittorrent 4.2.0 can't work\nHi\r\n  I've upgrade to qBittorrent 4.2.0 and flexget can't add new tasks to qBittorrent.\r\n  \r\nFlexGet version: 3.0.11\r\nPython version: 3.7.5\n", "before_files": [{"content": "import logging\nimport os\n\nfrom requests import Session\nfrom requests.exceptions import RequestException\n\nfrom flexget import plugin\nfrom flexget.event import event\nfrom flexget.utils.template import RenderError\n\nlog = logging.getLogger('qbittorrent')\n\n\nclass OutputQBitTorrent:\n    \"\"\"\n    Example:\n\n      qbittorrent:\n        username: <USERNAME> (default: (none))\n        password: <PASSWORD> (default: (none))\n        host: <HOSTNAME> (default: localhost)\n        port: <PORT> (default: 8080)\n        use_ssl: <SSL> (default: False)\n        verify_cert: <VERIFY> (default: True)\n        path: <OUTPUT_DIR> (default: (none))\n        label: <LABEL> (default: (none))\n        maxupspeed: <torrent upload speed limit> (default: 0)\n        maxdownspeed: <torrent download speed limit> (default: 0)\n        add_paused: <ADD_PAUSED> (default: False)\n    \"\"\"\n\n    schema = {\n        'anyOf': [\n            {'type': 'boolean'},\n            {\n                'type': 'object',\n                'properties': {\n                    'username': {'type': 'string'},\n                    'password': {'type': 'string'},\n                    'host': {'type': 'string'},\n                    'port': {'type': 'integer'},\n                    'use_ssl': {'type': 'boolean'},\n                    'verify_cert': {'type': 'boolean'},\n                    'path': {'type': 'string'},\n                    'label': {'type': 'string'},\n                    'maxupspeed': {'type': 'integer'},\n                    'maxdownspeed': {'type': 'integer'},\n                    'fail_html': {'type': 'boolean'},\n                    'add_paused': {'type': 'boolean'},\n                },\n                'additionalProperties': False,\n            },\n        ]\n    }\n\n    def _request(self, method, url, msg_on_fail=None, **kwargs):\n        try:\n            response = self.session.request(method, url, **kwargs)\n            if response == 'Fails.':\n                msg = (\n                    'Failure. URL: {}, data: {}'.format(url, kwargs)\n                    if not msg_on_fail\n                    else msg_on_fail\n                )\n            else:\n                return response\n        except RequestException as e:\n            msg = str(e)\n        raise plugin.PluginError(\n            'Error when trying to send request to qBittorrent: {}'.format(msg)\n        )\n\n    def connect(self, config):\n        \"\"\"\n        Connect to qBittorrent Web UI. Username and password not necessary\n        if 'Bypass authentication for localhost' is checked and host is\n        'localhost'.\n        \"\"\"\n        self.session = Session()\n        self.url = '{}://{}:{}'.format(\n            'https' if config['use_ssl'] else 'http', config['host'], config['port']\n        )\n        if config.get('username') and config.get('password'):\n            data = {'username': config['username'], 'password': config['password']}\n            self._request(\n                'post',\n                self.url + '/login',\n                data=data,\n                msg_on_fail='Authentication failed.',\n                verify=config['verify_cert'],\n            )\n        log.debug('Successfully connected to qBittorrent')\n        self.connected = True\n\n    def add_torrent_file(self, file_path, data, verify_cert):\n        if not self.connected:\n            raise plugin.PluginError('Not connected.')\n        multipart_data = {k: (None, v) for k, v in data.items()}\n        with open(file_path, 'rb') as f:\n            multipart_data['torrents'] = f\n            self._request(\n                'post',\n                self.url + '/command/upload',\n                msg_on_fail='Failed to add file to qBittorrent',\n                files=multipart_data,\n                verify=verify_cert,\n            )\n        log.debug('Added torrent file %s to qBittorrent', file_path)\n\n    def add_torrent_url(self, url, data, verify_cert):\n        if not self.connected:\n            raise plugin.PluginError('Not connected.')\n        data['urls'] = url\n        multipart_data = {k: (None, v) for k, v in data.items()}\n        self._request(\n            'post',\n            self.url + '/command/download',\n            msg_on_fail='Failed to add file to qBittorrent',\n            files=multipart_data,\n            verify=verify_cert,\n        )\n        log.debug('Added url %s to qBittorrent', url)\n\n    def prepare_config(self, config):\n        if isinstance(config, bool):\n            config = {'enabled': config}\n        config.setdefault('enabled', True)\n        config.setdefault('host', 'localhost')\n        config.setdefault('port', 8080)\n        config.setdefault('use_ssl', False)\n        config.setdefault('verify_cert', True)\n        config.setdefault('label', '')\n        config.setdefault('maxupspeed', 0)\n        config.setdefault('maxdownspeed', 0)\n        config.setdefault('fail_html', True)\n        return config\n\n    def add_entries(self, task, config):\n        for entry in task.accepted:\n            form_data = {}\n            try:\n                save_path = entry.render(entry.get('path', config.get('path', '')))\n                if save_path:\n                    form_data['savepath'] = save_path\n            except RenderError as e:\n                log.error('Error setting path for %s: %s', entry['title'], e)\n\n            label = entry.get('label', config.get('label'))\n            if label:\n                form_data['label'] = label  # qBittorrent v3.3.3-\n                form_data['category'] = label  # qBittorrent v3.3.4+\n\n            add_paused = entry.get('add_paused', config.get('add_paused'))\n            if add_paused:\n                form_data['paused'] = 'true'\n\n            maxupspeed = entry.get('maxupspeed', config.get('maxupspeed'))\n            if maxupspeed:\n                form_data['upLimit'] = maxupspeed * 1024\n\n            maxdownspeed = entry.get('maxdownspeed', config.get('maxdownspeed'))\n            if maxdownspeed:\n                form_data['dlLimit'] = maxdownspeed * 1024\n\n            is_magnet = entry['url'].startswith('magnet:')\n\n            if task.manager.options.test:\n                log.info('Test mode.')\n                log.info('Would add torrent to qBittorrent with:')\n                if not is_magnet:\n                    log.info('File: %s', entry.get('file'))\n                else:\n                    log.info('Url: %s', entry.get('url'))\n                log.info('Save path: %s', form_data.get('savepath'))\n                log.info('Label: %s', form_data.get('label'))\n                log.info('Paused: %s', form_data.get('paused', 'false'))\n                if maxupspeed:\n                    log.info('Upload Speed Limit: %d', form_data.get('upLimit'))\n                if maxdownspeed:\n                    log.info('Download Speed Limit: %d', form_data.get('dlLimit'))\n                continue\n\n            if not is_magnet:\n                if 'file' not in entry:\n                    entry.fail('File missing?')\n                    continue\n                if not os.path.exists(entry['file']):\n                    tmp_path = os.path.join(task.manager.config_base, 'temp')\n                    log.debug('entry: %s', entry)\n                    log.debug('temp: %s', ', '.join(os.listdir(tmp_path)))\n                    entry.fail(\"Downloaded temp file '%s' doesn't exist!?\" % entry['file'])\n                    continue\n                self.add_torrent_file(entry['file'], form_data, config['verify_cert'])\n            else:\n                self.add_torrent_url(entry['url'], form_data, config['verify_cert'])\n\n    @plugin.priority(120)\n    def on_task_download(self, task, config):\n        \"\"\"\n        Call download plugin to generate torrent files to load into\n        qBittorrent.\n        \"\"\"\n        config = self.prepare_config(config)\n        if not config['enabled']:\n            return\n        if 'download' not in task.config:\n            download = plugin.get('download', self)\n            download.get_temp_files(task, handle_magnets=True, fail_html=config['fail_html'])\n\n    @plugin.priority(135)\n    def on_task_output(self, task, config):\n        \"\"\"Add torrents to qBittorrent at exit.\"\"\"\n        if task.accepted:\n            config = self.prepare_config(config)\n            self.connect(config)\n            self.add_entries(task, config)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(OutputQBitTorrent, 'qbittorrent', api_ver=2)\n", "path": "flexget/plugins/clients/qbittorrent.py"}], "after_files": [{"content": "import logging\nimport os\n\nfrom requests import Session\nfrom requests.exceptions import RequestException\n\nfrom flexget import plugin\nfrom flexget.event import event\nfrom flexget.utils.template import RenderError\n\nlog = logging.getLogger('qbittorrent')\n\n\nclass OutputQBitTorrent:\n    \"\"\"\n    Example:\n\n      qbittorrent:\n        username: <USERNAME> (default: (none))\n        password: <PASSWORD> (default: (none))\n        host: <HOSTNAME> (default: localhost)\n        port: <PORT> (default: 8080)\n        use_ssl: <SSL> (default: False)\n        verify_cert: <VERIFY> (default: True)\n        path: <OUTPUT_DIR> (default: (none))\n        label: <LABEL> (default: (none))\n        maxupspeed: <torrent upload speed limit> (default: 0)\n        maxdownspeed: <torrent download speed limit> (default: 0)\n        add_paused: <ADD_PAUSED> (default: False)\n    \"\"\"\n\n    schema = {\n        'anyOf': [\n            {'type': 'boolean'},\n            {\n                'type': 'object',\n                'properties': {\n                    'username': {'type': 'string'},\n                    'password': {'type': 'string'},\n                    'host': {'type': 'string'},\n                    'port': {'type': 'integer'},\n                    'use_ssl': {'type': 'boolean'},\n                    'verify_cert': {'type': 'boolean'},\n                    'path': {'type': 'string'},\n                    'label': {'type': 'string'},\n                    'maxupspeed': {'type': 'integer'},\n                    'maxdownspeed': {'type': 'integer'},\n                    'fail_html': {'type': 'boolean'},\n                    'add_paused': {'type': 'boolean'},\n                },\n                'additionalProperties': False,\n            },\n        ]\n    }\n\n    def _request(self, method, url, msg_on_fail=None, **kwargs):\n        try:\n            response = self.session.request(method, url, **kwargs)\n            if response.text == \"Ok.\":\n                return response       \n            else:\n                msg = (\n                    'Failure. URL: {}, data: {}'.format(url, kwargs)\n                    if not msg_on_fail\n                    else msg_on_fail\n                )\n        except RequestException as e:\n            msg = str(e)\n        raise plugin.PluginError(\n            'Error when trying to send request to qBittorrent: {}'.format(msg)\n        )\n        \n    def check_api_version(self, msg_on_fail):\n        try:\n            url = self.url + \"/api/v2/app/webapiVersion\"\n            response = self.session.request('get', url)\n            if response.status_code != 404:\n                self.api_url_login = '/api/v2/auth/login'\n                self.api_url_add = '/api/v2/torrents/add'\n                return response         \n            \n            url = self.url + \"/version/api\"\n            response = self.session.request('get', url)\n            if response.status_code != 404:\n                self.api_url_login = '/login'\n                self.api_url_add = '/command/upload'\n                return response         \n            \n            msg = (\n                'Failure. URL: {}'.format(url)\n                if not msg_on_fail\n                else msg_on_fail\n            )\n        except RequestException as e:\n            msg = str(e)\n        raise plugin.PluginError(\n            'Error when trying to send request to qBittorrent: {}'.format(msg)\n        )\n\n    def connect(self, config):\n        \"\"\"\n        Connect to qBittorrent Web UI. Username and password not necessary\n        if 'Bypass authentication for localhost' is checked and host is\n        'localhost'.\n        \"\"\"\n        self.session = Session()\n        self.url = '{}://{}:{}'.format(\n            'https' if config['use_ssl'] else 'http', config['host'], config['port']\n        )\n        self.check_api_version('Check API version failed.')\n        if config.get('username') and config.get('password'):\n            data = {'username': config['username'], 'password': config['password']}\n            self._request(\n                'post',\n                self.url + self.api_url_login,\n                data=data,\n                msg_on_fail='Authentication failed.',\n                verify=config['verify_cert'],\n            )\n        log.debug('Successfully connected to qBittorrent')\n        self.connected = True\n\n    def add_torrent_file(self, file_path, data, verify_cert):\n        if not self.connected:\n            raise plugin.PluginError('Not connected.')\n        multipart_data = {k: (None, v) for k, v in data.items()}\n        with open(file_path, 'rb') as f:\n            multipart_data['torrents'] = f\n            self._request(\n                'post',\n                self.url + self.api_url_add,\n                msg_on_fail='Failed to add file to qBittorrent',\n                files=multipart_data,\n                verify=verify_cert,\n            )\n        log.debug('Added torrent file %s to qBittorrent', file_path)\n\n    def add_torrent_url(self, url, data, verify_cert):\n        if not self.connected:\n            raise plugin.PluginError('Not connected.')\n        data['urls'] = url\n        multipart_data = {k: (None, v) for k, v in data.items()}\n        self._request(\n            'post',\n            self.url + self.api_url_add,\n            msg_on_fail='Failed to add file to qBittorrent',\n            files=multipart_data,\n            verify=verify_cert,\n        )\n        log.debug('Added url %s to qBittorrent', url)\n\n    def prepare_config(self, config):\n        if isinstance(config, bool):\n            config = {'enabled': config}\n        config.setdefault('enabled', True)\n        config.setdefault('host', 'localhost')\n        config.setdefault('port', 8080)\n        config.setdefault('use_ssl', False)\n        config.setdefault('verify_cert', True)\n        config.setdefault('label', '')\n        config.setdefault('maxupspeed', 0)\n        config.setdefault('maxdownspeed', 0)\n        config.setdefault('fail_html', True)\n        return config\n\n    def add_entries(self, task, config):\n        for entry in task.accepted:\n            form_data = {}\n            try:\n                save_path = entry.render(entry.get('path', config.get('path', '')))\n                if save_path:\n                    form_data['savepath'] = save_path\n            except RenderError as e:\n                log.error('Error setting path for %s: %s', entry['title'], e)\n\n            label = entry.get('label', config.get('label'))\n            if label:\n                form_data['label'] = label  # qBittorrent v3.3.3-\n                form_data['category'] = label  # qBittorrent v3.3.4+\n\n            add_paused = entry.get('add_paused', config.get('add_paused'))\n            if add_paused:\n                form_data['paused'] = 'true'\n\n            maxupspeed = entry.get('maxupspeed', config.get('maxupspeed'))\n            if maxupspeed:\n                form_data['upLimit'] = maxupspeed * 1024\n\n            maxdownspeed = entry.get('maxdownspeed', config.get('maxdownspeed'))\n            if maxdownspeed:\n                form_data['dlLimit'] = maxdownspeed * 1024\n\n            is_magnet = entry['url'].startswith('magnet:')\n\n            if task.manager.options.test:\n                log.info('Test mode.')\n                log.info('Would add torrent to qBittorrent with:')\n                if not is_magnet:\n                    log.info('File: %s', entry.get('file'))\n                else:\n                    log.info('Url: %s', entry.get('url'))\n                log.info('Save path: %s', form_data.get('savepath'))\n                log.info('Label: %s', form_data.get('label'))\n                log.info('Paused: %s', form_data.get('paused', 'false'))\n                if maxupspeed:\n                    log.info('Upload Speed Limit: %d', form_data.get('upLimit'))\n                if maxdownspeed:\n                    log.info('Download Speed Limit: %d', form_data.get('dlLimit'))\n                continue\n\n            if not is_magnet:\n                if 'file' not in entry:\n                    entry.fail('File missing?')\n                    continue\n                if not os.path.exists(entry['file']):\n                    tmp_path = os.path.join(task.manager.config_base, 'temp')\n                    log.debug('entry: %s', entry)\n                    log.debug('temp: %s', ', '.join(os.listdir(tmp_path)))\n                    entry.fail(\"Downloaded temp file '%s' doesn't exist!?\" % entry['file'])\n                    continue\n                self.add_torrent_file(entry['file'], form_data, config['verify_cert'])\n            else:\n                self.add_torrent_url(entry['url'], form_data, config['verify_cert'])\n\n    @plugin.priority(120)\n    def on_task_download(self, task, config):\n        \"\"\"\n        Call download plugin to generate torrent files to load into\n        qBittorrent.\n        \"\"\"\n        config = self.prepare_config(config)\n        if not config['enabled']:\n            return\n        if 'download' not in task.config:\n            download = plugin.get('download', self)\n            download.get_temp_files(task, handle_magnets=True, fail_html=config['fail_html'])\n\n    @plugin.priority(135)\n    def on_task_output(self, task, config):\n        \"\"\"Add torrents to qBittorrent at exit.\"\"\"\n        if task.accepted:\n            config = self.prepare_config(config)\n            self.connect(config)\n            self.add_entries(task, config)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(OutputQBitTorrent, 'qbittorrent', api_ver=2)\n", "path": "flexget/plugins/clients/qbittorrent.py"}]}