We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[APP SUBMITTED]: AttributeError: 'NoneType' object has no attribute 'json'

### INFO
**Python Version**: `3.8.5 (default, Aug  2 2020, 15:09:07) [GCC 9.3.0]`
**Operating System**: `Linux-4.9.35-v7+-armv7l-with-glibc2.29`
**Locale**: `UTF-8`
**Branch**: [develop](../tree/develop)
**Database**: `44.18`
**Commit**: pymedusa/Medusa@5c8597b932e7975c5619c0ecc906efce625202dc
**Link to Log**: https://gist.github.com/85c8565a27efbcc61281cbd34dec0a9f
### ERROR
<pre>
2021-04-19 03:55:20 ERROR    SNATCHQUEUE-SNATCH-75978 :: [5c8597b] Transmission: Failed Sending Torrent
Traceback (most recent call last):
  File "/home/pi/Medusa/<a href="../blob/5c8597b932e7975c5619c0ecc906efce625202dc/medusa/clients/torrent/generic.py#L257">medusa/clients/torrent/generic.py</a>", line 257, in send_torrent
    r_code = self._add_torrent_file(result)
  File "/home/pi/Medusa/<a href="../blob/5c8597b932e7975c5619c0ecc906efce625202dc/medusa/clients/torrent/transmission.py#L128">medusa/clients/torrent/transmission.py</a>", line 128, in _add_torrent_file
    return self.check_response()
  File "/home/pi/Medusa/<a href="../blob/5c8597b932e7975c5619c0ecc906efce625202dc/medusa/clients/torrent/transmission.py#L47">medusa/clients/torrent/transmission.py</a>", line 47, in check_response
    return self.response.json()['result'] == 'success'
AttributeError: 'NoneType' object has no attribute 'json'
</pre>
---
_STAFF NOTIFIED_: @pymedusa/support @pymedusa/moderators


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `medusa/providers/torrent/json/privatehd.py`
Content:
```
1 # coding=utf-8
2 
3 """Provider code for PrivateHD."""
4 
5 from __future__ import unicode_literals
6 
7 import logging
8 
9 from medusa import tv
10 from medusa.helper.common import convert_size
11 from medusa.helper.exceptions import AuthException
12 from medusa.logger.adapters.style import BraceAdapter
13 from medusa.providers.torrent.torrent_provider import TorrentProvider
14 
15 from requests.compat import urljoin
16 
17 log = BraceAdapter(logging.getLogger(__name__))
18 log.logger.addHandler(logging.NullHandler())
19 
20 
21 class PrivateHDProvider(TorrentProvider):
22     """PrivateHD Torrent provider."""
23 
24     def __init__(self):
25         """Initialize the class."""
26         super(PrivateHDProvider, self).__init__('PrivateHD')
27 
28         # Credentials
29         self.username = None
30         self.password = None
31         self.pid = None
32         self._token = None
33 
34         # URLs
35         self.url = 'https://privatehd.to'
36         self.urls = {
37             'login': urljoin(self.url, 'api/v1/jackett/auth'),
38             'search': urljoin(self.url, 'api/v1/jackett/torrents'),
39         }
40 
41         # Proper Strings
42         self.proper_strings = ['PROPER', 'REPACK', 'REAL', 'RERIP']
43 
44         # Miscellaneous Options
45         self.freeleech = False
46 
47         # Torrent Stats
48 
49         # Cache
50         self.cache = tv.Cache(self)  # only poll PrivateHD every 10 minutes max
51 
52     def search(self, search_strings, age=0, ep_obj=None, **kwargs):
53         """
54         Search a provider and parse the results.
55 
56         :param search_strings: A dict with mode (key) and the search value (value)
57         :param age: Not used
58         :param ep_obj: Not used
59         :returns: A list of search results (structure)
60         """
61         results = []
62         if not self.login():
63             return results
64 
65         for mode in search_strings:
66             log.debug('Search mode: {0}', mode)
67 
68             for search_string in search_strings[mode]:
69                 if mode != 'RSS':
70                     log.debug('Search string: {search}',
71                               {'search': search_string})
72 
73                 search_params = {
74                     'in': 1,
75                     'search': search_string,
76                     'type': 2,
77                     'discount[]': 1 if self.freeleech else None,
78                     'tv_type[]': {'episode': 1, 'season': 2}.get(mode.lower())
79                 }
80 
81                 if not search_string:
82                     del search_params['search']
83 
84                 headers = {
85                     'Authorization': f'Bearer {self._token}'
86                 }
87 
88                 response = self.session.get(self.urls['search'], params=search_params, headers=headers)
89                 try:
90                     jdata = response.json()
91                     if not jdata.get('data') or not len(jdata['data']):
92                         log.debug('No data returned from provider')
93                         continue
94                 except ValueError:
95                     log.debug('No data returned from provider')
96                     continue
97 
98                 results += self.parse(jdata, mode)
99 
100         return results
101 
102     def parse(self, data, mode):
103         """
104         Parse search results for items.
105 
106         :param data: The raw response from a search
107         :param mode: The current mode used to search, e.g. RSS
108 
109         :return: A list of items found
110         """
111         items = []
112         json_data = data.get('data', [])
113 
114         for row in json_data:
115             try:
116                 title = row.pop('file_name')
117                 download_url = row.pop('download')
118                 if not all([title, download_url]):
119                     continue
120 
121                 seeders = row.pop('seed', 0)
122                 leechers = row.pop('leech', 0)
123 
124                 # Filter unseeded torrent
125                 if seeders < self.minseed:
126                     if mode != 'RSS':
127                         log.debug("Discarding torrent because it doesn't meet the"
128                                   ' minimum seeders: {0}. Seeders: {1}',
129                                   title, seeders)
130                     continue
131 
132                 size = convert_size(row.pop('file_size', None), default=-1)
133                 pubdate_raw = row.pop('created_at')
134                 pubdate = self.parse_pubdate(pubdate_raw)
135 
136                 item = {
137                     'title': title,
138                     'link': download_url,
139                     'size': size,
140                     'seeders': seeders,
141                     'leechers': leechers,
142                     'pubdate': pubdate,
143                 }
144                 if mode != 'RSS':
145                     log.debug('Found result: {0} with {1} seeders and {2} leechers',
146                               title, seeders, leechers)
147 
148                 items.append(item)
149             except (AttributeError, TypeError, KeyError, ValueError, IndexError):
150                 log.exception('Failed parsing provider.')
151         return items
152 
153     def login(self):
154         """Login method used for logging in before doing search and torrent downloads."""
155         login_params = {
156             'pid': self.pid,
157             'username': self.username,
158             'password': self.password
159         }
160 
161         response = self.session.post(self.urls['login'], data=login_params)
162         try:
163             jdata = response.json()
164             if 'message' in jdata:
165                 raise AuthException(f"Error trying to auth, {jdata['message']}")
166         except ValueError:
167             log.debug('No data returned from provider')
168             raise AuthException('Could not get auth token')
169 
170         if 'token' in jdata:
171             self._token = jdata['token']
172             return True
173 
174         return False
175 
176 
177 provider = PrivateHDProvider()
178
```
--- 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/medusa/providers/torrent/json/privatehd.py b/medusa/providers/torrent/json/privatehd.py
--- a/medusa/providers/torrent/json/privatehd.py
+++ b/medusa/providers/torrent/json/privatehd.py
@@ -91,7 +91,7 @@
                     if not jdata.get('data') or not len(jdata['data']):
                         log.debug('No data returned from provider')
                         continue
-                except ValueError:
+                except (AttributeError, ValueError):
                     log.debug('No data returned from provider')
                     continue
 
@@ -163,7 +163,7 @@
             jdata = response.json()
             if 'message' in jdata:
                 raise AuthException(f"Error trying to auth, {jdata['message']}")
-        except ValueError:
+        except (AttributeError, ValueError):
             log.debug('No data returned from provider')
             raise AuthException('Could not get auth token')

{"golden_diff": "diff --git a/medusa/providers/torrent/json/privatehd.py b/medusa/providers/torrent/json/privatehd.py\n--- a/medusa/providers/torrent/json/privatehd.py\n+++ b/medusa/providers/torrent/json/privatehd.py\n@@ -91,7 +91,7 @@\n                     if not jdata.get('data') or not len(jdata['data']):\n                         log.debug('No data returned from provider')\n                         continue\n-                except ValueError:\n+                except (AttributeError, ValueError):\n                     log.debug('No data returned from provider')\n                     continue\n \n@@ -163,7 +163,7 @@\n             jdata = response.json()\n             if 'message' in jdata:\n                 raise AuthException(f\"Error trying to auth, {jdata['message']}\")\n-        except ValueError:\n+        except (AttributeError, ValueError):\n             log.debug('No data returned from provider')\n             raise AuthException('Could not get auth token')\n", "issue": "[APP SUBMITTED]: AttributeError: 'NoneType' object has no attribute 'json'\n\n### INFO\n**Python Version**: `3.8.5 (default, Aug  2 2020, 15:09:07) [GCC 9.3.0]`\n**Operating System**: `Linux-4.9.35-v7+-armv7l-with-glibc2.29`\n**Locale**: `UTF-8`\n**Branch**: [develop](../tree/develop)\n**Database**: `44.18`\n**Commit**: pymedusa/Medusa@5c8597b932e7975c5619c0ecc906efce625202dc\n**Link to Log**: https://gist.github.com/85c8565a27efbcc61281cbd34dec0a9f\n### ERROR\n<pre>\n2021-04-19 03:55:20 ERROR    SNATCHQUEUE-SNATCH-75978 :: [5c8597b] Transmission: Failed Sending Torrent\nTraceback (most recent call last):\n  File \"/home/pi/Medusa/<a href=\"../blob/5c8597b932e7975c5619c0ecc906efce625202dc/medusa/clients/torrent/generic.py#L257\">medusa/clients/torrent/generic.py</a>\", line 257, in send_torrent\n    r_code = self._add_torrent_file(result)\n  File \"/home/pi/Medusa/<a href=\"../blob/5c8597b932e7975c5619c0ecc906efce625202dc/medusa/clients/torrent/transmission.py#L128\">medusa/clients/torrent/transmission.py</a>\", line 128, in _add_torrent_file\n    return self.check_response()\n  File \"/home/pi/Medusa/<a href=\"../blob/5c8597b932e7975c5619c0ecc906efce625202dc/medusa/clients/torrent/transmission.py#L47\">medusa/clients/torrent/transmission.py</a>\", line 47, in check_response\n    return self.response.json()['result'] == 'success'\nAttributeError: 'NoneType' object has no attribute 'json'\n</pre>\n---\n_STAFF NOTIFIED_: @pymedusa/support @pymedusa/moderators\n\n", "before_files": [{"content": "# coding=utf-8\n\n\"\"\"Provider code for PrivateHD.\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport logging\n\nfrom medusa import tv\nfrom medusa.helper.common import convert_size\nfrom medusa.helper.exceptions import AuthException\nfrom medusa.logger.adapters.style import BraceAdapter\nfrom medusa.providers.torrent.torrent_provider import TorrentProvider\n\nfrom requests.compat import urljoin\n\nlog = BraceAdapter(logging.getLogger(__name__))\nlog.logger.addHandler(logging.NullHandler())\n\n\nclass PrivateHDProvider(TorrentProvider):\n    \"\"\"PrivateHD Torrent provider.\"\"\"\n\n    def __init__(self):\n        \"\"\"Initialize the class.\"\"\"\n        super(PrivateHDProvider, self).__init__('PrivateHD')\n\n        # Credentials\n        self.username = None\n        self.password = None\n        self.pid = None\n        self._token = None\n\n        # URLs\n        self.url = 'https://privatehd.to'\n        self.urls = {\n            'login': urljoin(self.url, 'api/v1/jackett/auth'),\n            'search': urljoin(self.url, 'api/v1/jackett/torrents'),\n        }\n\n        # Proper Strings\n        self.proper_strings = ['PROPER', 'REPACK', 'REAL', 'RERIP']\n\n        # Miscellaneous Options\n        self.freeleech = False\n\n        # Torrent Stats\n\n        # Cache\n        self.cache = tv.Cache(self)  # only poll PrivateHD every 10 minutes max\n\n    def search(self, search_strings, age=0, ep_obj=None, **kwargs):\n        \"\"\"\n        Search a provider and parse the results.\n\n        :param search_strings: A dict with mode (key) and the search value (value)\n        :param age: Not used\n        :param ep_obj: Not used\n        :returns: A list of search results (structure)\n        \"\"\"\n        results = []\n        if not self.login():\n            return results\n\n        for mode in search_strings:\n            log.debug('Search mode: {0}', mode)\n\n            for search_string in search_strings[mode]:\n                if mode != 'RSS':\n                    log.debug('Search string: {search}',\n                              {'search': search_string})\n\n                search_params = {\n                    'in': 1,\n                    'search': search_string,\n                    'type': 2,\n                    'discount[]': 1 if self.freeleech else None,\n                    'tv_type[]': {'episode': 1, 'season': 2}.get(mode.lower())\n                }\n\n                if not search_string:\n                    del search_params['search']\n\n                headers = {\n                    'Authorization': f'Bearer {self._token}'\n                }\n\n                response = self.session.get(self.urls['search'], params=search_params, headers=headers)\n                try:\n                    jdata = response.json()\n                    if not jdata.get('data') or not len(jdata['data']):\n                        log.debug('No data returned from provider')\n                        continue\n                except ValueError:\n                    log.debug('No data returned from provider')\n                    continue\n\n                results += self.parse(jdata, mode)\n\n        return results\n\n    def parse(self, data, mode):\n        \"\"\"\n        Parse search results for items.\n\n        :param data: The raw response from a search\n        :param mode: The current mode used to search, e.g. RSS\n\n        :return: A list of items found\n        \"\"\"\n        items = []\n        json_data = data.get('data', [])\n\n        for row in json_data:\n            try:\n                title = row.pop('file_name')\n                download_url = row.pop('download')\n                if not all([title, download_url]):\n                    continue\n\n                seeders = row.pop('seed', 0)\n                leechers = row.pop('leech', 0)\n\n                # Filter unseeded torrent\n                if seeders < self.minseed:\n                    if mode != 'RSS':\n                        log.debug(\"Discarding torrent because it doesn't meet the\"\n                                  ' minimum seeders: {0}. Seeders: {1}',\n                                  title, seeders)\n                    continue\n\n                size = convert_size(row.pop('file_size', None), default=-1)\n                pubdate_raw = row.pop('created_at')\n                pubdate = self.parse_pubdate(pubdate_raw)\n\n                item = {\n                    'title': title,\n                    'link': download_url,\n                    'size': size,\n                    'seeders': seeders,\n                    'leechers': leechers,\n                    'pubdate': pubdate,\n                }\n                if mode != 'RSS':\n                    log.debug('Found result: {0} with {1} seeders and {2} leechers',\n                              title, seeders, leechers)\n\n                items.append(item)\n            except (AttributeError, TypeError, KeyError, ValueError, IndexError):\n                log.exception('Failed parsing provider.')\n        return items\n\n    def login(self):\n        \"\"\"Login method used for logging in before doing search and torrent downloads.\"\"\"\n        login_params = {\n            'pid': self.pid,\n            'username': self.username,\n            'password': self.password\n        }\n\n        response = self.session.post(self.urls['login'], data=login_params)\n        try:\n            jdata = response.json()\n            if 'message' in jdata:\n                raise AuthException(f\"Error trying to auth, {jdata['message']}\")\n        except ValueError:\n            log.debug('No data returned from provider')\n            raise AuthException('Could not get auth token')\n\n        if 'token' in jdata:\n            self._token = jdata['token']\n            return True\n\n        return False\n\n\nprovider = PrivateHDProvider()\n", "path": "medusa/providers/torrent/json/privatehd.py"}], "after_files": [{"content": "# coding=utf-8\n\n\"\"\"Provider code for PrivateHD.\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport logging\n\nfrom medusa import tv\nfrom medusa.helper.common import convert_size\nfrom medusa.helper.exceptions import AuthException\nfrom medusa.logger.adapters.style import BraceAdapter\nfrom medusa.providers.torrent.torrent_provider import TorrentProvider\n\nfrom requests.compat import urljoin\n\nlog = BraceAdapter(logging.getLogger(__name__))\nlog.logger.addHandler(logging.NullHandler())\n\n\nclass PrivateHDProvider(TorrentProvider):\n    \"\"\"PrivateHD Torrent provider.\"\"\"\n\n    def __init__(self):\n        \"\"\"Initialize the class.\"\"\"\n        super(PrivateHDProvider, self).__init__('PrivateHD')\n\n        # Credentials\n        self.username = None\n        self.password = None\n        self.pid = None\n        self._token = None\n\n        # URLs\n        self.url = 'https://privatehd.to'\n        self.urls = {\n            'login': urljoin(self.url, 'api/v1/jackett/auth'),\n            'search': urljoin(self.url, 'api/v1/jackett/torrents'),\n        }\n\n        # Proper Strings\n        self.proper_strings = ['PROPER', 'REPACK', 'REAL', 'RERIP']\n\n        # Miscellaneous Options\n        self.freeleech = False\n\n        # Torrent Stats\n\n        # Cache\n        self.cache = tv.Cache(self)  # only poll PrivateHD every 10 minutes max\n\n    def search(self, search_strings, age=0, ep_obj=None, **kwargs):\n        \"\"\"\n        Search a provider and parse the results.\n\n        :param search_strings: A dict with mode (key) and the search value (value)\n        :param age: Not used\n        :param ep_obj: Not used\n        :returns: A list of search results (structure)\n        \"\"\"\n        results = []\n        if not self.login():\n            return results\n\n        for mode in search_strings:\n            log.debug('Search mode: {0}', mode)\n\n            for search_string in search_strings[mode]:\n                if mode != 'RSS':\n                    log.debug('Search string: {search}',\n                              {'search': search_string})\n\n                search_params = {\n                    'in': 1,\n                    'search': search_string,\n                    'type': 2,\n                    'discount[]': 1 if self.freeleech else None,\n                    'tv_type[]': {'episode': 1, 'season': 2}.get(mode.lower())\n                }\n\n                if not search_string:\n                    del search_params['search']\n\n                headers = {\n                    'Authorization': f'Bearer {self._token}'\n                }\n\n                response = self.session.get(self.urls['search'], params=search_params, headers=headers)\n                try:\n                    jdata = response.json()\n                    if not jdata.get('data') or not len(jdata['data']):\n                        log.debug('No data returned from provider')\n                        continue\n                except (AttributeError, ValueError):\n                    log.debug('No data returned from provider')\n                    continue\n\n                results += self.parse(jdata, mode)\n\n        return results\n\n    def parse(self, data, mode):\n        \"\"\"\n        Parse search results for items.\n\n        :param data: The raw response from a search\n        :param mode: The current mode used to search, e.g. RSS\n\n        :return: A list of items found\n        \"\"\"\n        items = []\n        json_data = data.get('data', [])\n\n        for row in json_data:\n            try:\n                title = row.pop('file_name')\n                download_url = row.pop('download')\n                if not all([title, download_url]):\n                    continue\n\n                seeders = row.pop('seed', 0)\n                leechers = row.pop('leech', 0)\n\n                # Filter unseeded torrent\n                if seeders < self.minseed:\n                    if mode != 'RSS':\n                        log.debug(\"Discarding torrent because it doesn't meet the\"\n                                  ' minimum seeders: {0}. Seeders: {1}',\n                                  title, seeders)\n                    continue\n\n                size = convert_size(row.pop('file_size', None), default=-1)\n                pubdate_raw = row.pop('created_at')\n                pubdate = self.parse_pubdate(pubdate_raw)\n\n                item = {\n                    'title': title,\n                    'link': download_url,\n                    'size': size,\n                    'seeders': seeders,\n                    'leechers': leechers,\n                    'pubdate': pubdate,\n                }\n                if mode != 'RSS':\n                    log.debug('Found result: {0} with {1} seeders and {2} leechers',\n                              title, seeders, leechers)\n\n                items.append(item)\n            except (AttributeError, TypeError, KeyError, ValueError, IndexError):\n                log.exception('Failed parsing provider.')\n        return items\n\n    def login(self):\n        \"\"\"Login method used for logging in before doing search and torrent downloads.\"\"\"\n        login_params = {\n            'pid': self.pid,\n            'username': self.username,\n            'password': self.password\n        }\n\n        response = self.session.post(self.urls['login'], data=login_params)\n        try:\n            jdata = response.json()\n            if 'message' in jdata:\n                raise AuthException(f\"Error trying to auth, {jdata['message']}\")\n        except (AttributeError, ValueError):\n            log.debug('No data returned from provider')\n            raise AuthException('Could not get auth token')\n\n        if 'token' in jdata:\n            self._token = jdata['token']\n            return True\n\n        return False\n\n\nprovider = PrivateHDProvider()\n", "path": "medusa/providers/torrent/json/privatehd.py"}]}