We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pirate Bay Plugin: Error searching with piratebay: Expecting value: line 1 column 1 (char 0)
When searching with the Pirate Bay plugin for Movies I get an error every time. I didn't change anything in my Config. It used to search just fine. Been getting this error since Version 3.1.75 or .76. 


#### Config:
```yaml
download-movies: 
    priority: 4   
    imdb_lookup: yes  # can also use imdb_lookup or tmdb_lookup
    discover:
      what:
        - movie_list: watchlist
      from:
        - piratebay:
            sort_by: seeds
            category: video
            url: https://www1.thepiratebay3.to/
        - rarbg:
            category: [48, 44, 14, 45, 17]
            sorted_by: seeders
      interval: 30 minutes        
```
  
#### Log:
<details>
 <summary>(click to expand)</summary>

```
2020-10-18 13:42:42 VERBOSE  discover      download-movies Searching for `The Net (2016)` with plugin `piratebay` (1 of 3)
2020-10-18 13:42:43 ERROR    discover      download-movies Error searching with piratebay: Expecting value: line 1 column 1 (char 0)
2020-10-18 13:42:43 VERBOSE  discover      download-movies Searching for `The Net (2016)` with plugin `rarbg` (1 of 3)
2020-10-18 13:42:46 VERBOSE  discover      download-movies No search results for `The Net (2016)`
2020-10-18 13:42:46 VERBOSE  discover      download-movies Searching for `Angelo (2019)` with plugin `piratebay` (2 of 3)
2020-10-18 13:42:46 ERROR    discover      download-movies Error searching with piratebay: Expecting value: line 1 column 1 (char 0)
2020-10-18 13:42:46 VERBOSE  discover      download-movies Searching for `Angelo (2019)` with plugin `rarbg` (2 of 3)
```
</details>

### Additional information:

- FlexGet version: 3.1.77
- Python version:
- Installation method: 
- Using daemon (yes/no): yes
- OS and version: DietPi rasperryPi Debian

--- 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/components/sites/sites/piratebay.py`
Content:
```
1 import re
2 from urllib.parse import urlencode, urlparse
3 
4 from loguru import logger
5 
6 from flexget import plugin
7 from flexget.components.sites.urlrewriting import UrlRewritingError
8 from flexget.components.sites.utils import normalize_unicode, torrent_availability
9 from flexget.entry import Entry
10 from flexget.event import event
11 
12 logger = logger.bind(name='piratebay')
13 
14 URL = 'https://apibay.org'  # for TOR: http://piratebayztemzmv.onion
15 
16 CATEGORIES = {
17     'all': 0,
18     'audio': 100,
19     'music': 101,
20     'video': 200,
21     'movies': 201,
22     'tv': 205,
23     'highres movies': 207,
24     'highres tv': 208,
25     'comics': 602,
26 }
27 
28 # try to maintain compatibility with old config
29 SORT = {
30     'default': 'torrent_availability',
31     'date': 'torrent_timestamp',
32     'size': 'content_size',
33     'seeds': 'torrent_seeds',
34     'leechers': 'torrent_leeches',
35 }
36 
37 # default trackers for magnet links
38 TRACKERS = [
39     'udp://tracker.coppersurfer.tk:6969/announce',
40     'udp://9.rarbg.to:2920/announce',
41     'udp://tracker.opentrackr.org:1337',
42     'udp://tracker.internetwarriors.net:1337/announce',
43     'udp://tracker.leechers-paradise.org:6969/announce',
44     'udp://tracker.coppersurfer.tk:6969/announce',
45     'udp://tracker.pirateparty.gr:6969/announce',
46     'udp://tracker.cyberia.is:6969/announce',
47 ]
48 
49 
50 class UrlRewritePirateBay:
51     """PirateBay urlrewriter."""
52 
53     schema = {
54         'oneOf': [
55             {'type': 'boolean'},
56             {
57                 'type': 'object',
58                 'properties': {
59                     'url': {'type': 'string', 'default': URL, 'format': 'url'},
60                     'category': {
61                         'oneOf': [
62                             {'type': 'string', 'enum': list(CATEGORIES)},
63                             {'type': 'integer'},
64                         ]
65                     },
66                     'sort_by': {'type': 'string', 'enum': list(SORT)},
67                     'sort_reverse': {'type': 'boolean'},
68                 },
69                 'additionalProperties': False,
70             },
71         ]
72     }
73 
74     url = None
75 
76     def __init__(self):
77         self.set_urls(URL)
78 
79     def on_task_start(self, task, config=None):
80         if not isinstance(config, dict):
81             config = {}
82         self.set_urls(config.get('url', URL))
83 
84     def set_urls(self, url):
85         url = url.rstrip('/')
86         if self.url != url:
87             self.url = url
88             parsed_url = urlparse(url)
89             escaped_url_scheme = re.escape(parsed_url.scheme)
90             escaped_url_netloc = re.escape(parsed_url.netloc)
91             # most api mirrors share the same domain with frontend, except thepiratebay.org which uses apibay.org
92             # some api mirrors might contain path, for ex https://pirateproxy.surf/api?url=/q.php?q=ubuntu&cat=0
93             # valid URLs are https://piratebay.org/description.php?id=\d+ and https://apibay.org/description.php?id=\d+
94             self.url_match = re.compile(
95                 fr'^{escaped_url_scheme}://(?:thepiratebay\.org(?:\:\d+)?|{escaped_url_netloc})/description\.php\?id=(\d+)$'
96             )
97             self.url_search = re.compile(
98                 fr'^(?:https?://thepiratebay\.org(?:\:\d+)?|{escaped_url_scheme}://{escaped_url_netloc})/search\.php\?q=.*$'
99             )
100 
101     # urlrewriter API
102     def url_rewritable(self, task, entry):
103         url = entry['url']
104         if url.endswith('.torrent'):
105             return False
106         return any((self.url_match.match(url), self.url_search.match(url)))
107 
108     # urlrewriter API
109     def url_rewrite(self, task, entry):
110         if 'url' not in entry:
111             logger.error("Didn't actually get a URL...")
112         else:
113             logger.debug('Got the URL: {}', entry['url'])
114         if self.url_search.match(entry['url']):
115             # use search
116             results = self.search(task, entry)
117             if not results:
118                 raise UrlRewritingError("No search results found")
119             # TODO: Close matching was taken out of search methods, this may need to be fixed to be more picky
120             entry['url'] = results[0]['url']
121         else:
122             torrent_id = self.url_match.match(entry['url']).group(1)
123             url = f"{self.url}/t.php?id={torrent_id}"
124             logger.debug('Getting info for torrent ID {}', torrent_id)
125             json_result = task.requests.get(url).json()
126             if json_result['id'] == '0':
127                 raise UrlRewritingError(f"Torrent with ID {torrent_id} does not exist.")
128             entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])
129 
130     @plugin.internet(logger)
131     def search(self, task, entry, config=None):
132         """
133         Search for name from piratebay.
134         """
135         if not isinstance(config, dict):
136             config = {}
137         self.set_urls(config.get('url', URL))
138         sort = SORT.get(config.get('sort_by', 'default'))
139         sort_reverse = bool(config.get('sort_reverse', 'True'))
140         if isinstance(config.get('category'), int):
141             category = config['category']
142         else:
143             category = CATEGORIES.get(config.get('category', 'all'))
144 
145         entries = set()
146         for search_string in entry.get('search_strings', [entry['title']]):
147             # query = normalize_unicode(search_string)
148             params = {'q': search_string, 'cat': category}
149             url = f"{self.url}/q.php"
150             json_results = task.requests.get(url, params=params).json()
151             if not json_results:
152                 raise plugin.PluginError("Error while searching piratebay for %s.", search_string)
153             for result in json_results:
154                 if result['id'] == '0':
155                     # JSON when no results found: [{ "id":"0", "name":"No results returned", ... }]
156                     break
157                 entry = self.json_to_entry(result)
158                 entries.add(entry)
159 
160         return sorted(entries, reverse=sort_reverse, key=lambda x: x.get(sort))
161 
162     # convert an info_hash string to a magnet uri
163     @staticmethod
164     def info_hash_to_magnet(info_hash: str, name: str) -> str:
165         magnet = {'xt': f"urn:btih:{info_hash}", 'dn': name, 'tr': TRACKERS}
166         magnet_qs = urlencode(magnet, doseq=True, safe=':')
167         magnet_uri = f"magnet:?{magnet_qs}"
168         return magnet_uri
169 
170     # convert a single json result to an Entry
171     def json_to_entry(self, json_result: dict) -> Entry:
172         entry = Entry()
173         entry['title'] = json_result['name']
174         entry['torrent_seeds'] = int(json_result['seeders'])
175         entry['torrent_leeches'] = int(json_result['leechers'])
176         entry['torrent_timestamp'] = int(json_result['added'])  # custom field for sorting by date
177         entry['torrent_availability'] = torrent_availability(
178             entry['torrent_seeds'], entry['torrent_leeches']
179         )
180         entry['content_size'] = int(
181             round(int(json_result['size']) / (1024 * 1024))
182         )  # content_size is in MiB
183         entry['torrent_info_hash'] = json_result['info_hash']
184         entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])
185         return entry
186 
187 
188 @event('plugin.register')
189 def register_plugin():
190     plugin.register(
191         UrlRewritePirateBay, 'piratebay', interfaces=['urlrewriter', 'search', 'task'], api_ver=2
192     )
193
```
--- 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/components/sites/sites/piratebay.py b/flexget/components/sites/sites/piratebay.py
--- a/flexget/components/sites/sites/piratebay.py
+++ b/flexget/components/sites/sites/piratebay.py
@@ -1,11 +1,12 @@
 import re
 from urllib.parse import urlencode, urlparse
+from json import JSONDecodeError
 
 from loguru import logger
 
 from flexget import plugin
 from flexget.components.sites.urlrewriting import UrlRewritingError
-from flexget.components.sites.utils import normalize_unicode, torrent_availability
+from flexget.components.sites.utils import torrent_availability
 from flexget.entry import Entry
 from flexget.event import event
 
@@ -108,23 +109,23 @@
     # urlrewriter API
     def url_rewrite(self, task, entry):
         if 'url' not in entry:
-            logger.error("Didn't actually get a URL...")
+            logger.error('Didn\'t actually get a URL...')
         else:
             logger.debug('Got the URL: {}', entry['url'])
         if self.url_search.match(entry['url']):
             # use search
             results = self.search(task, entry)
             if not results:
-                raise UrlRewritingError("No search results found")
+                raise UrlRewritingError('No search results found')
             # TODO: Close matching was taken out of search methods, this may need to be fixed to be more picky
             entry['url'] = results[0]['url']
         else:
             torrent_id = self.url_match.match(entry['url']).group(1)
-            url = f"{self.url}/t.php?id={torrent_id}"
+            url = f'{self.url}/t.php?id={torrent_id}'
             logger.debug('Getting info for torrent ID {}', torrent_id)
             json_result = task.requests.get(url).json()
             if json_result['id'] == '0':
-                raise UrlRewritingError(f"Torrent with ID {torrent_id} does not exist.")
+                raise UrlRewritingError(f'Torrent with ID {torrent_id} does not exist.')
             entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])
 
     @plugin.internet(logger)
@@ -146,10 +147,16 @@
         for search_string in entry.get('search_strings', [entry['title']]):
             # query = normalize_unicode(search_string)
             params = {'q': search_string, 'cat': category}
-            url = f"{self.url}/q.php"
-            json_results = task.requests.get(url, params=params).json()
+            url = f'{self.url}/q.php'
+            try:
+                json_results = task.requests.get(url, params=params).json()
+            except JSONDecodeError as e:
+                raise plugin.PluginError(
+                    f'Error while searching piratebay for {search_string}, invalid json response',
+                )
+
             if not json_results:
-                raise plugin.PluginError("Error while searching piratebay for %s.", search_string)
+                raise plugin.PluginError(f'Error while searching piratebay for {search_string}.')
             for result in json_results:
                 if result['id'] == '0':
                     # JSON when no results found: [{ "id":"0", "name":"No results returned", ... }]
@@ -162,9 +169,9 @@
     # convert an info_hash string to a magnet uri
     @staticmethod
     def info_hash_to_magnet(info_hash: str, name: str) -> str:
-        magnet = {'xt': f"urn:btih:{info_hash}", 'dn': name, 'tr': TRACKERS}
+        magnet = {'xt': f'urn:btih:{info_hash}', 'dn': name, 'tr': TRACKERS}
         magnet_qs = urlencode(magnet, doseq=True, safe=':')
-        magnet_uri = f"magnet:?{magnet_qs}"
+        magnet_uri = f'magnet:?{magnet_qs}'
         return magnet_uri
 
     # convert a single json result to an Entry

{"golden_diff": "diff --git a/flexget/components/sites/sites/piratebay.py b/flexget/components/sites/sites/piratebay.py\n--- a/flexget/components/sites/sites/piratebay.py\n+++ b/flexget/components/sites/sites/piratebay.py\n@@ -1,11 +1,12 @@\n import re\n from urllib.parse import urlencode, urlparse\n+from json import JSONDecodeError\n \n from loguru import logger\n \n from flexget import plugin\n from flexget.components.sites.urlrewriting import UrlRewritingError\n-from flexget.components.sites.utils import normalize_unicode, torrent_availability\n+from flexget.components.sites.utils import torrent_availability\n from flexget.entry import Entry\n from flexget.event import event\n \n@@ -108,23 +109,23 @@\n     # urlrewriter API\n     def url_rewrite(self, task, entry):\n         if 'url' not in entry:\n-            logger.error(\"Didn't actually get a URL...\")\n+            logger.error('Didn\\'t actually get a URL...')\n         else:\n             logger.debug('Got the URL: {}', entry['url'])\n         if self.url_search.match(entry['url']):\n             # use search\n             results = self.search(task, entry)\n             if not results:\n-                raise UrlRewritingError(\"No search results found\")\n+                raise UrlRewritingError('No search results found')\n             # TODO: Close matching was taken out of search methods, this may need to be fixed to be more picky\n             entry['url'] = results[0]['url']\n         else:\n             torrent_id = self.url_match.match(entry['url']).group(1)\n-            url = f\"{self.url}/t.php?id={torrent_id}\"\n+            url = f'{self.url}/t.php?id={torrent_id}'\n             logger.debug('Getting info for torrent ID {}', torrent_id)\n             json_result = task.requests.get(url).json()\n             if json_result['id'] == '0':\n-                raise UrlRewritingError(f\"Torrent with ID {torrent_id} does not exist.\")\n+                raise UrlRewritingError(f'Torrent with ID {torrent_id} does not exist.')\n             entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])\n \n     @plugin.internet(logger)\n@@ -146,10 +147,16 @@\n         for search_string in entry.get('search_strings', [entry['title']]):\n             # query = normalize_unicode(search_string)\n             params = {'q': search_string, 'cat': category}\n-            url = f\"{self.url}/q.php\"\n-            json_results = task.requests.get(url, params=params).json()\n+            url = f'{self.url}/q.php'\n+            try:\n+                json_results = task.requests.get(url, params=params).json()\n+            except JSONDecodeError as e:\n+                raise plugin.PluginError(\n+                    f'Error while searching piratebay for {search_string}, invalid json response',\n+                )\n+\n             if not json_results:\n-                raise plugin.PluginError(\"Error while searching piratebay for %s.\", search_string)\n+                raise plugin.PluginError(f'Error while searching piratebay for {search_string}.')\n             for result in json_results:\n                 if result['id'] == '0':\n                     # JSON when no results found: [{ \"id\":\"0\", \"name\":\"No results returned\", ... }]\n@@ -162,9 +169,9 @@\n     # convert an info_hash string to a magnet uri\n     @staticmethod\n     def info_hash_to_magnet(info_hash: str, name: str) -> str:\n-        magnet = {'xt': f\"urn:btih:{info_hash}\", 'dn': name, 'tr': TRACKERS}\n+        magnet = {'xt': f'urn:btih:{info_hash}', 'dn': name, 'tr': TRACKERS}\n         magnet_qs = urlencode(magnet, doseq=True, safe=':')\n-        magnet_uri = f\"magnet:?{magnet_qs}\"\n+        magnet_uri = f'magnet:?{magnet_qs}'\n         return magnet_uri\n \n     # convert a single json result to an Entry\n", "issue": "Pirate Bay Plugin: Error searching with piratebay: Expecting value: line 1 column 1 (char 0)\nWhen searching with the Pirate Bay plugin for Movies I get an error every time. I didn't change anything in my Config. It used to search just fine. Been getting this error since Version 3.1.75 or .76. \r\n\r\n\r\n#### Config:\r\n```yaml\r\ndownload-movies: \r\n    priority: 4   \r\n    imdb_lookup: yes  # can also use imdb_lookup or tmdb_lookup\r\n    discover:\r\n      what:\r\n        - movie_list: watchlist\r\n      from:\r\n        - piratebay:\r\n            sort_by: seeds\r\n            category: video\r\n            url: https://www1.thepiratebay3.to/\r\n        - rarbg:\r\n            category: [48, 44, 14, 45, 17]\r\n            sorted_by: seeders\r\n      interval: 30 minutes        \r\n```\r\n  \r\n#### Log:\r\n<details>\r\n <summary>(click to expand)</summary>\r\n\r\n```\r\n2020-10-18 13:42:42 VERBOSE  discover      download-movies Searching for `The Net (2016)` with plugin `piratebay` (1 of 3)\r\n2020-10-18 13:42:43 ERROR    discover      download-movies Error searching with piratebay: Expecting value: line 1 column 1 (char 0)\r\n2020-10-18 13:42:43 VERBOSE  discover      download-movies Searching for `The Net (2016)` with plugin `rarbg` (1 of 3)\r\n2020-10-18 13:42:46 VERBOSE  discover      download-movies No search results for `The Net (2016)`\r\n2020-10-18 13:42:46 VERBOSE  discover      download-movies Searching for `Angelo (2019)` with plugin `piratebay` (2 of 3)\r\n2020-10-18 13:42:46 ERROR    discover      download-movies Error searching with piratebay: Expecting value: line 1 column 1 (char 0)\r\n2020-10-18 13:42:46 VERBOSE  discover      download-movies Searching for `Angelo (2019)` with plugin `rarbg` (2 of 3)\r\n```\r\n</details>\r\n\r\n### Additional information:\r\n\r\n- FlexGet version: 3.1.77\r\n- Python version:\r\n- Installation method: \r\n- Using daemon (yes/no): yes\r\n- OS and version: DietPi rasperryPi Debian\n", "before_files": [{"content": "import re\nfrom urllib.parse import urlencode, urlparse\n\nfrom loguru import logger\n\nfrom flexget import plugin\nfrom flexget.components.sites.urlrewriting import UrlRewritingError\nfrom flexget.components.sites.utils import normalize_unicode, torrent_availability\nfrom flexget.entry import Entry\nfrom flexget.event import event\n\nlogger = logger.bind(name='piratebay')\n\nURL = 'https://apibay.org'  # for TOR: http://piratebayztemzmv.onion\n\nCATEGORIES = {\n    'all': 0,\n    'audio': 100,\n    'music': 101,\n    'video': 200,\n    'movies': 201,\n    'tv': 205,\n    'highres movies': 207,\n    'highres tv': 208,\n    'comics': 602,\n}\n\n# try to maintain compatibility with old config\nSORT = {\n    'default': 'torrent_availability',\n    'date': 'torrent_timestamp',\n    'size': 'content_size',\n    'seeds': 'torrent_seeds',\n    'leechers': 'torrent_leeches',\n}\n\n# default trackers for magnet links\nTRACKERS = [\n    'udp://tracker.coppersurfer.tk:6969/announce',\n    'udp://9.rarbg.to:2920/announce',\n    'udp://tracker.opentrackr.org:1337',\n    'udp://tracker.internetwarriors.net:1337/announce',\n    'udp://tracker.leechers-paradise.org:6969/announce',\n    'udp://tracker.coppersurfer.tk:6969/announce',\n    'udp://tracker.pirateparty.gr:6969/announce',\n    'udp://tracker.cyberia.is:6969/announce',\n]\n\n\nclass UrlRewritePirateBay:\n    \"\"\"PirateBay urlrewriter.\"\"\"\n\n    schema = {\n        'oneOf': [\n            {'type': 'boolean'},\n            {\n                'type': 'object',\n                'properties': {\n                    'url': {'type': 'string', 'default': URL, 'format': 'url'},\n                    'category': {\n                        'oneOf': [\n                            {'type': 'string', 'enum': list(CATEGORIES)},\n                            {'type': 'integer'},\n                        ]\n                    },\n                    'sort_by': {'type': 'string', 'enum': list(SORT)},\n                    'sort_reverse': {'type': 'boolean'},\n                },\n                'additionalProperties': False,\n            },\n        ]\n    }\n\n    url = None\n\n    def __init__(self):\n        self.set_urls(URL)\n\n    def on_task_start(self, task, config=None):\n        if not isinstance(config, dict):\n            config = {}\n        self.set_urls(config.get('url', URL))\n\n    def set_urls(self, url):\n        url = url.rstrip('/')\n        if self.url != url:\n            self.url = url\n            parsed_url = urlparse(url)\n            escaped_url_scheme = re.escape(parsed_url.scheme)\n            escaped_url_netloc = re.escape(parsed_url.netloc)\n            # most api mirrors share the same domain with frontend, except thepiratebay.org which uses apibay.org\n            # some api mirrors might contain path, for ex https://pirateproxy.surf/api?url=/q.php?q=ubuntu&cat=0\n            # valid URLs are https://piratebay.org/description.php?id=\\d+ and https://apibay.org/description.php?id=\\d+\n            self.url_match = re.compile(\n                fr'^{escaped_url_scheme}://(?:thepiratebay\\.org(?:\\:\\d+)?|{escaped_url_netloc})/description\\.php\\?id=(\\d+)$'\n            )\n            self.url_search = re.compile(\n                fr'^(?:https?://thepiratebay\\.org(?:\\:\\d+)?|{escaped_url_scheme}://{escaped_url_netloc})/search\\.php\\?q=.*$'\n            )\n\n    # urlrewriter API\n    def url_rewritable(self, task, entry):\n        url = entry['url']\n        if url.endswith('.torrent'):\n            return False\n        return any((self.url_match.match(url), self.url_search.match(url)))\n\n    # urlrewriter API\n    def url_rewrite(self, task, entry):\n        if 'url' not in entry:\n            logger.error(\"Didn't actually get a URL...\")\n        else:\n            logger.debug('Got the URL: {}', entry['url'])\n        if self.url_search.match(entry['url']):\n            # use search\n            results = self.search(task, entry)\n            if not results:\n                raise UrlRewritingError(\"No search results found\")\n            # TODO: Close matching was taken out of search methods, this may need to be fixed to be more picky\n            entry['url'] = results[0]['url']\n        else:\n            torrent_id = self.url_match.match(entry['url']).group(1)\n            url = f\"{self.url}/t.php?id={torrent_id}\"\n            logger.debug('Getting info for torrent ID {}', torrent_id)\n            json_result = task.requests.get(url).json()\n            if json_result['id'] == '0':\n                raise UrlRewritingError(f\"Torrent with ID {torrent_id} does not exist.\")\n            entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])\n\n    @plugin.internet(logger)\n    def search(self, task, entry, config=None):\n        \"\"\"\n        Search for name from piratebay.\n        \"\"\"\n        if not isinstance(config, dict):\n            config = {}\n        self.set_urls(config.get('url', URL))\n        sort = SORT.get(config.get('sort_by', 'default'))\n        sort_reverse = bool(config.get('sort_reverse', 'True'))\n        if isinstance(config.get('category'), int):\n            category = config['category']\n        else:\n            category = CATEGORIES.get(config.get('category', 'all'))\n\n        entries = set()\n        for search_string in entry.get('search_strings', [entry['title']]):\n            # query = normalize_unicode(search_string)\n            params = {'q': search_string, 'cat': category}\n            url = f\"{self.url}/q.php\"\n            json_results = task.requests.get(url, params=params).json()\n            if not json_results:\n                raise plugin.PluginError(\"Error while searching piratebay for %s.\", search_string)\n            for result in json_results:\n                if result['id'] == '0':\n                    # JSON when no results found: [{ \"id\":\"0\", \"name\":\"No results returned\", ... }]\n                    break\n                entry = self.json_to_entry(result)\n                entries.add(entry)\n\n        return sorted(entries, reverse=sort_reverse, key=lambda x: x.get(sort))\n\n    # convert an info_hash string to a magnet uri\n    @staticmethod\n    def info_hash_to_magnet(info_hash: str, name: str) -> str:\n        magnet = {'xt': f\"urn:btih:{info_hash}\", 'dn': name, 'tr': TRACKERS}\n        magnet_qs = urlencode(magnet, doseq=True, safe=':')\n        magnet_uri = f\"magnet:?{magnet_qs}\"\n        return magnet_uri\n\n    # convert a single json result to an Entry\n    def json_to_entry(self, json_result: dict) -> Entry:\n        entry = Entry()\n        entry['title'] = json_result['name']\n        entry['torrent_seeds'] = int(json_result['seeders'])\n        entry['torrent_leeches'] = int(json_result['leechers'])\n        entry['torrent_timestamp'] = int(json_result['added'])  # custom field for sorting by date\n        entry['torrent_availability'] = torrent_availability(\n            entry['torrent_seeds'], entry['torrent_leeches']\n        )\n        entry['content_size'] = int(\n            round(int(json_result['size']) / (1024 * 1024))\n        )  # content_size is in MiB\n        entry['torrent_info_hash'] = json_result['info_hash']\n        entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])\n        return entry\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(\n        UrlRewritePirateBay, 'piratebay', interfaces=['urlrewriter', 'search', 'task'], api_ver=2\n    )\n", "path": "flexget/components/sites/sites/piratebay.py"}], "after_files": [{"content": "import re\nfrom urllib.parse import urlencode, urlparse\nfrom json import JSONDecodeError\n\nfrom loguru import logger\n\nfrom flexget import plugin\nfrom flexget.components.sites.urlrewriting import UrlRewritingError\nfrom flexget.components.sites.utils import torrent_availability\nfrom flexget.entry import Entry\nfrom flexget.event import event\n\nlogger = logger.bind(name='piratebay')\n\nURL = 'https://apibay.org'  # for TOR: http://piratebayztemzmv.onion\n\nCATEGORIES = {\n    'all': 0,\n    'audio': 100,\n    'music': 101,\n    'video': 200,\n    'movies': 201,\n    'tv': 205,\n    'highres movies': 207,\n    'highres tv': 208,\n    'comics': 602,\n}\n\n# try to maintain compatibility with old config\nSORT = {\n    'default': 'torrent_availability',\n    'date': 'torrent_timestamp',\n    'size': 'content_size',\n    'seeds': 'torrent_seeds',\n    'leechers': 'torrent_leeches',\n}\n\n# default trackers for magnet links\nTRACKERS = [\n    'udp://tracker.coppersurfer.tk:6969/announce',\n    'udp://9.rarbg.to:2920/announce',\n    'udp://tracker.opentrackr.org:1337',\n    'udp://tracker.internetwarriors.net:1337/announce',\n    'udp://tracker.leechers-paradise.org:6969/announce',\n    'udp://tracker.coppersurfer.tk:6969/announce',\n    'udp://tracker.pirateparty.gr:6969/announce',\n    'udp://tracker.cyberia.is:6969/announce',\n]\n\n\nclass UrlRewritePirateBay:\n    \"\"\"PirateBay urlrewriter.\"\"\"\n\n    schema = {\n        'oneOf': [\n            {'type': 'boolean'},\n            {\n                'type': 'object',\n                'properties': {\n                    'url': {'type': 'string', 'default': URL, 'format': 'url'},\n                    'category': {\n                        'oneOf': [\n                            {'type': 'string', 'enum': list(CATEGORIES)},\n                            {'type': 'integer'},\n                        ]\n                    },\n                    'sort_by': {'type': 'string', 'enum': list(SORT)},\n                    'sort_reverse': {'type': 'boolean'},\n                },\n                'additionalProperties': False,\n            },\n        ]\n    }\n\n    url = None\n\n    def __init__(self):\n        self.set_urls(URL)\n\n    def on_task_start(self, task, config=None):\n        if not isinstance(config, dict):\n            config = {}\n        self.set_urls(config.get('url', URL))\n\n    def set_urls(self, url):\n        url = url.rstrip('/')\n        if self.url != url:\n            self.url = url\n            parsed_url = urlparse(url)\n            escaped_url_scheme = re.escape(parsed_url.scheme)\n            escaped_url_netloc = re.escape(parsed_url.netloc)\n            # most api mirrors share the same domain with frontend, except thepiratebay.org which uses apibay.org\n            # some api mirrors might contain path, for ex https://pirateproxy.surf/api?url=/q.php?q=ubuntu&cat=0\n            # valid URLs are https://piratebay.org/description.php?id=\\d+ and https://apibay.org/description.php?id=\\d+\n            self.url_match = re.compile(\n                fr'^{escaped_url_scheme}://(?:thepiratebay\\.org(?:\\:\\d+)?|{escaped_url_netloc})/description\\.php\\?id=(\\d+)$'\n            )\n            self.url_search = re.compile(\n                fr'^(?:https?://thepiratebay\\.org(?:\\:\\d+)?|{escaped_url_scheme}://{escaped_url_netloc})/search\\.php\\?q=.*$'\n            )\n\n    # urlrewriter API\n    def url_rewritable(self, task, entry):\n        url = entry['url']\n        if url.endswith('.torrent'):\n            return False\n        return any((self.url_match.match(url), self.url_search.match(url)))\n\n    # urlrewriter API\n    def url_rewrite(self, task, entry):\n        if 'url' not in entry:\n            logger.error('Didn\\'t actually get a URL...')\n        else:\n            logger.debug('Got the URL: {}', entry['url'])\n        if self.url_search.match(entry['url']):\n            # use search\n            results = self.search(task, entry)\n            if not results:\n                raise UrlRewritingError('No search results found')\n            # TODO: Close matching was taken out of search methods, this may need to be fixed to be more picky\n            entry['url'] = results[0]['url']\n        else:\n            torrent_id = self.url_match.match(entry['url']).group(1)\n            url = f'{self.url}/t.php?id={torrent_id}'\n            logger.debug('Getting info for torrent ID {}', torrent_id)\n            json_result = task.requests.get(url).json()\n            if json_result['id'] == '0':\n                raise UrlRewritingError(f'Torrent with ID {torrent_id} does not exist.')\n            entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])\n\n    @plugin.internet(logger)\n    def search(self, task, entry, config=None):\n        \"\"\"\n        Search for name from piratebay.\n        \"\"\"\n        if not isinstance(config, dict):\n            config = {}\n        self.set_urls(config.get('url', URL))\n        sort = SORT.get(config.get('sort_by', 'default'))\n        sort_reverse = bool(config.get('sort_reverse', 'True'))\n        if isinstance(config.get('category'), int):\n            category = config['category']\n        else:\n            category = CATEGORIES.get(config.get('category', 'all'))\n\n        entries = set()\n        for search_string in entry.get('search_strings', [entry['title']]):\n            # query = normalize_unicode(search_string)\n            params = {'q': search_string, 'cat': category}\n            url = f'{self.url}/q.php'\n            try:\n                json_results = task.requests.get(url, params=params).json()\n            except JSONDecodeError as e:\n                raise plugin.PluginError(\n                    f'Error while searching piratebay for {search_string}, invalid json response',\n                )\n\n            if not json_results:\n                raise plugin.PluginError(f'Error while searching piratebay for {search_string}.')\n            for result in json_results:\n                if result['id'] == '0':\n                    # JSON when no results found: [{ \"id\":\"0\", \"name\":\"No results returned\", ... }]\n                    break\n                entry = self.json_to_entry(result)\n                entries.add(entry)\n\n        return sorted(entries, reverse=sort_reverse, key=lambda x: x.get(sort))\n\n    # convert an info_hash string to a magnet uri\n    @staticmethod\n    def info_hash_to_magnet(info_hash: str, name: str) -> str:\n        magnet = {'xt': f'urn:btih:{info_hash}', 'dn': name, 'tr': TRACKERS}\n        magnet_qs = urlencode(magnet, doseq=True, safe=':')\n        magnet_uri = f'magnet:?{magnet_qs}'\n        return magnet_uri\n\n    # convert a single json result to an Entry\n    def json_to_entry(self, json_result: dict) -> Entry:\n        entry = Entry()\n        entry['title'] = json_result['name']\n        entry['torrent_seeds'] = int(json_result['seeders'])\n        entry['torrent_leeches'] = int(json_result['leechers'])\n        entry['torrent_timestamp'] = int(json_result['added'])  # custom field for sorting by date\n        entry['torrent_availability'] = torrent_availability(\n            entry['torrent_seeds'], entry['torrent_leeches']\n        )\n        entry['content_size'] = int(\n            round(int(json_result['size']) / (1024 * 1024))\n        )  # content_size is in MiB\n        entry['torrent_info_hash'] = json_result['info_hash']\n        entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])\n        return entry\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(\n        UrlRewritePirateBay, 'piratebay', interfaces=['urlrewriter', 'search', 'task'], api_ver=2\n    )\n", "path": "flexget/components/sites/sites/piratebay.py"}]}