We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Flexget crashes due to "No module named 'packaging'"
### Expected behaviour:

daemon starts 

### Actual behaviour:
flexget crashes

### Steps to reproduce:
flexget daemon start -d

  
#### Log:
```
    self.initialize()
    |    -> <function Manager.initialize at 0x7fceb0a4d950>
    -> <flexget.manager.Manager object at 0x7fceb204add8>
  File "/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/manager.py", line 215, in initialize
    extra_components=[os.path.join(self.config_base, 'components')],
                      |  |    |    |    -> '/home/loke/.flexget'
                      |  |    |    -> <flexget.manager.Manager object at 0x7fceb204add8>
                      |  |    -> <function join at 0x7fceb2c67ea0>
                      |  -> <module 'posixpath' from '/home/loke/.psources/flexget/lib/python3.7/posixpath.py'>
                      -> <module 'os' from '/home/loke/.psources/flexget/lib/python3.7/os.py'>
  File "/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugin.py", line 555, in load_plugins
    _load_plugins_from_dirs(extra_plugins)
    |                       -> ['/home/loke/.flexget/plugins', '/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugins']
    -> <function _load_plugins_from_dirs at 0x7fceb0f59d90>
  File "/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugin.py", line 473, in _load_plugins_from_dirs
    _import_plugin(module_name, plugin_path)
    |              |            -> PosixPath('/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugins/clients/pyload.py')
    |              -> 'flexget.plugins.clients.pyload'
    -> <function _import_plugin at 0x7fceb0f59d08>
> File "/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugin.py", line 424, in _import_plugin
    import_module(module_name)
    |             -> 'flexget.plugins.clients.pyload'
    -> <function import_module at 0x7fceb2ba36a8>
  File "/home/loke/.psources/flexget/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           |          |           |    |        |        -> 0
           |          |           |    |        -> None
           |          |           |    -> 0
           |          |           -> 'flexget.plugins.clients.pyload'
           |          -> <function _gcd_import at 0x7fceb2ce5e18>
           -> <module 'importlib._bootstrap' (frozen)>
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugins/clients/pyload.py", line 11, in <module>
    from packaging import version

ModuleNotFoundError: No module named 'packaging'
```

### Additional information:

- FlexGet version: 3.1.45 (3.1.44 works fine)
- Python version: 3.7
- Installation method: virtualenv
- Using daemon (yes/no): yes 
- OS and version: debian 10



--- 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/pyload.py`
Content:
```
1 from urllib.parse import quote
2 
3 from loguru import logger
4 from requests.exceptions import RequestException
5 
6 from flexget import plugin
7 from flexget.config_schema import one_or_more
8 from flexget.event import event
9 from flexget.utils import json
10 from flexget.utils.template import RenderError
11 from packaging import version
12 logger = logger.bind(name='pyload')
13 
14 
15 class PyloadApi:
16     def __init__(self, requests, url):
17         self.requests = requests
18         self.url = url
19 
20     def get_session(self, config):
21         # Login
22         data = {'username': config['username'], 'password': config['password']}
23         result = self.post('login', data=data)
24         response = result.json()
25         if not response:
26             raise plugin.PluginError('Login failed', logger)
27 
28         if isinstance(response, str):
29             return response.replace('"', '')
30         else:
31             return response
32 
33     def get(self, method):
34         try:
35             return self.requests.get(self.url.rstrip("/") + "/" + method.strip("/"))
36         except RequestException as e:
37             if e.response and e.response.status_code == 500:
38                 raise plugin.PluginError(
39                     'Internal API Error: <%s> <%s>' % (method, self.url), logger
40                 )
41             raise
42 
43     def post(self, method, data):
44         try:
45             return self.requests.post(self.url.rstrip("/") + "/" + method.strip("/"), data=data)
46         except RequestException as e:
47             if e.response and e.response.status_code == 500:
48                 raise plugin.PluginError(
49                     'Internal API Error: <%s> <%s> <%s>' % (method, self.url, data), logger
50                 )
51             raise
52 
53 
54 class PluginPyLoad:
55     """
56     Parse task content or url for hoster links and adds them to pyLoad.
57 
58     Example::
59 
60       pyload:
61         api: http://localhost:8000/api
62         queue: yes
63         username: my_username
64         password: my_password
65         folder: desired_folder
66         package: desired_package_name (jinja2 supported)
67         package_password: desired_package_password
68         hoster:
69           - YoutubeCom
70         parse_url: no
71         multiple_hoster: yes
72         enabled: yes
73 
74     Default values for the config elements::
75 
76       pyload:
77           api: http://localhost:8000/api
78           queue: no
79           hoster: ALL
80           parse_url: no
81           multiple_hoster: yes
82           enabled: yes
83     """
84 
85     __author__ = 'http://pyload.org'
86     __version__ = '0.5'
87 
88     DEFAULT_API = 'http://localhost:8000/api'
89     DEFAULT_QUEUE = False
90     DEFAULT_FOLDER = ''
91     DEFAULT_HOSTER = []
92     DEFAULT_PARSE_URL = False
93     DEFAULT_MULTIPLE_HOSTER = True
94     DEFAULT_PREFERRED_HOSTER_ONLY = False
95     DEFAULT_HANDLE_NO_URL_AS_FAILURE = False
96 
97     schema = {
98         'type': 'object',
99         'properties': {
100             'api': {'type': 'string'},
101             'username': {'type': 'string'},
102             'password': {'type': 'string'},
103             'folder': {'type': 'string'},
104             'package': {'type': 'string'},
105             'package_password': {'type': 'string'},
106             'queue': {'type': 'boolean'},
107             'parse_url': {'type': 'boolean'},
108             'multiple_hoster': {'type': 'boolean'},
109             'hoster': one_or_more({'type': 'string'}),
110             'preferred_hoster_only': {'type': 'boolean'},
111             'handle_no_url_as_failure': {'type': 'boolean'},
112             'enabled': {'type': 'boolean'},
113         },
114         'required': ['username', 'password'],
115         'additionalProperties': False,
116     }
117 
118     def on_task_output(self, task, config):
119         if not config.get('enabled', True):
120             return
121         if not task.accepted:
122             return
123 
124         self.add_entries(task, config)
125 
126     def add_entries(self, task, config):
127         """Adds accepted entries"""
128 
129         apiurl = config.get('api', self.DEFAULT_API)
130         api = PyloadApi(task.requests, apiurl)
131 
132         try:
133             session = api.get_session(config)
134         except IOError:
135             raise plugin.PluginError('pyLoad not reachable', logger)
136         except plugin.PluginError:
137             raise
138         except Exception as e:
139             raise plugin.PluginError('Unknown error: %s' % str(e), logger)
140 
141         remote_version = None
142         try:
143             remote_version = api.get('getServerVersion')
144         except RequestException as e:
145             if e.response is not None and e.response.status_code == 404:
146                 remote_version = json.loads(api.get('get_server_version').content)
147             else:
148                 raise e
149 
150         parse_urls_command = 'parseURLs'
151         add_package_command = 'addPackage'
152         set_package_data_command = 'setPackageData'
153 
154         is_pyload_ng = False
155         if version.parse(remote_version) >= version.parse('0.5'):
156             parse_urls_command = 'parse_urls'
157             add_package_command = 'add_package'
158             set_package_data_command = 'set_package_date'
159             is_pyload_ng = True
160 
161         hoster = config.get('hoster', self.DEFAULT_HOSTER)
162 
163         for entry in task.accepted:
164             # bunch of urls now going to check
165             content = entry.get('description', '') + ' ' + quote(entry['url'])
166             content = json.dumps(content)
167 
168             if is_pyload_ng:
169                 url = (
170                     entry['url']
171                     if config.get('parse_url', self.DEFAULT_PARSE_URL)
172                     else ''
173                 )
174             else:
175                 url = (
176                     json.dumps(entry['url'])
177                     if config.get('parse_url', self.DEFAULT_PARSE_URL)
178                     else "''"
179                 )
180 
181             logger.debug('Parsing url {}', url)
182 
183             data = {'html': content, 'url': url}
184             if not is_pyload_ng:
185                 data['session'] = session
186             result = api.post(parse_urls_command, data=data)
187 
188             parsed = result.json()
189 
190             urls = []
191 
192             # check for preferred hoster
193             for name in hoster:
194                 if name in parsed:
195                     urls.extend(parsed[name])
196                     if not config.get('multiple_hoster', self.DEFAULT_MULTIPLE_HOSTER):
197                         break
198 
199             # no preferred hoster and not preferred hoster only - add all recognized plugins
200             if not urls and not config.get(
201                 'preferred_hoster_only', self.DEFAULT_PREFERRED_HOSTER_ONLY
202             ):
203                 for name, purls in parsed.items():
204                     if name != 'BasePlugin':
205                         urls.extend(purls)
206 
207             if task.options.test:
208                 logger.info('Would add `{}` to pyload', urls)
209                 continue
210 
211             # no urls found
212             if not urls:
213                 if config.get('handle_no_url_as_failure', self.DEFAULT_HANDLE_NO_URL_AS_FAILURE):
214                     entry.fail('No suited urls in entry %s' % entry['title'])
215                 else:
216                     logger.info('No suited urls in entry {}', entry['title'])
217                 continue
218 
219             logger.debug('Add {} urls to pyLoad', len(urls))
220 
221             try:
222                 dest = 1 if config.get('queue', self.DEFAULT_QUEUE) else 0  # Destination.Queue = 1
223 
224                 # Use the title of the entry, if no naming schema for the package is defined.
225                 name = config.get('package', entry['title'])
226 
227                 # If name has jinja template, render it
228                 try:
229                     name = entry.render(name)
230                 except RenderError as e:
231                     name = entry['title']
232                     logger.error('Error rendering jinja event: {}', e)
233 
234                 if is_pyload_ng:
235                     data = {
236                         'name': name.encode('ascii', 'ignore').decode(),
237                         'links': urls,
238                         'dest': dest,
239                     }
240                 else:
241                     data = {
242                         'name': json.dumps(name.encode('ascii', 'ignore').decode()),
243                         'links': json.dumps(urls),
244                         'dest': json.dumps(dest),
245                         'session': session
246                     }
247 
248                 pid = api.post(add_package_command, data=data).text
249                 logger.debug('added package pid: {}', pid)
250 
251                 # Set Folder
252                 folder = config.get('folder', self.DEFAULT_FOLDER)
253                 folder = entry.get('path', folder)
254                 if folder:
255                     # If folder has jinja template, render it
256                     try:
257                         folder = entry.render(folder)
258                     except RenderError as e:
259                         folder = self.DEFAULT_FOLDER
260                         logger.error('Error rendering jinja event: {}', e)
261                     # set folder with api
262                     data = json.dumps({'folder': folder})
263                     post_data = {'pid': pid, 'data': data}
264                     if not is_pyload_ng:
265                         post_data['session'] = session
266                     api.post(set_package_data_command, data=post_data)
267 
268                 # Set Package Password
269                 package_password = config.get('package_password')
270                 if package_password:
271                     data = json.dumps({'password': package_password})
272                     post_data = {'pid': pid, 'data': data}
273                     if not is_pyload_ng:
274                         post_data['session'] = session
275                     api.post(set_package_data_command, data=post_data)
276 
277             except Exception as e:
278                 entry.fail(str(e))
279 
280 
281 @event('plugin.register')
282 def register_plugin():
283     plugin.register(PluginPyLoad, 'pyload', api_ver=2)
284
```
--- 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/pyload.py b/flexget/plugins/clients/pyload.py
--- a/flexget/plugins/clients/pyload.py
+++ b/flexget/plugins/clients/pyload.py
@@ -8,7 +8,6 @@
 from flexget.event import event
 from flexget.utils import json
 from flexget.utils.template import RenderError
-from packaging import version
 logger = logger.bind(name='pyload')
 
 
@@ -123,6 +122,15 @@
 
         self.add_entries(task, config)
 
+    @staticmethod
+    def get_version_from_packaging():
+        version = None
+        try:
+            from packaging import version
+        except ModuleNotFoundError:
+            logger.warning('packaging is not installed')
+        return version
+
     def add_entries(self, task, config):
         """Adds accepted entries"""
 
@@ -152,7 +160,8 @@
         set_package_data_command = 'setPackageData'
 
         is_pyload_ng = False
-        if version.parse(remote_version) >= version.parse('0.5'):
+        version = self.get_version_from_packaging()
+        if version and version.parse(remote_version) >= version.parse('0.5'):
             parse_urls_command = 'parse_urls'
             add_package_command = 'add_package'
             set_package_data_command = 'set_package_date'

{"golden_diff": "diff --git a/flexget/plugins/clients/pyload.py b/flexget/plugins/clients/pyload.py\n--- a/flexget/plugins/clients/pyload.py\n+++ b/flexget/plugins/clients/pyload.py\n@@ -8,7 +8,6 @@\n from flexget.event import event\n from flexget.utils import json\n from flexget.utils.template import RenderError\n-from packaging import version\n logger = logger.bind(name='pyload')\n \n \n@@ -123,6 +122,15 @@\n \n         self.add_entries(task, config)\n \n+    @staticmethod\n+    def get_version_from_packaging():\n+        version = None\n+        try:\n+            from packaging import version\n+        except ModuleNotFoundError:\n+            logger.warning('packaging is not installed')\n+        return version\n+\n     def add_entries(self, task, config):\n         \"\"\"Adds accepted entries\"\"\"\n \n@@ -152,7 +160,8 @@\n         set_package_data_command = 'setPackageData'\n \n         is_pyload_ng = False\n-        if version.parse(remote_version) >= version.parse('0.5'):\n+        version = self.get_version_from_packaging()\n+        if version and version.parse(remote_version) >= version.parse('0.5'):\n             parse_urls_command = 'parse_urls'\n             add_package_command = 'add_package'\n             set_package_data_command = 'set_package_date'\n", "issue": "Flexget crashes due to \"No module named 'packaging'\"\n### Expected behaviour:\r\n\r\ndaemon starts \r\n\r\n### Actual behaviour:\r\nflexget crashes\r\n\r\n### Steps to reproduce:\r\nflexget daemon start -d\r\n\r\n  \r\n#### Log:\r\n```\r\n    self.initialize()\r\n    |    -> <function Manager.initialize at 0x7fceb0a4d950>\r\n    -> <flexget.manager.Manager object at 0x7fceb204add8>\r\n  File \"/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/manager.py\", line 215, in initialize\r\n    extra_components=[os.path.join(self.config_base, 'components')],\r\n                      |  |    |    |    -> '/home/loke/.flexget'\r\n                      |  |    |    -> <flexget.manager.Manager object at 0x7fceb204add8>\r\n                      |  |    -> <function join at 0x7fceb2c67ea0>\r\n                      |  -> <module 'posixpath' from '/home/loke/.psources/flexget/lib/python3.7/posixpath.py'>\r\n                      -> <module 'os' from '/home/loke/.psources/flexget/lib/python3.7/os.py'>\r\n  File \"/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugin.py\", line 555, in load_plugins\r\n    _load_plugins_from_dirs(extra_plugins)\r\n    |                       -> ['/home/loke/.flexget/plugins', '/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugins']\r\n    -> <function _load_plugins_from_dirs at 0x7fceb0f59d90>\r\n  File \"/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugin.py\", line 473, in _load_plugins_from_dirs\r\n    _import_plugin(module_name, plugin_path)\r\n    |              |            -> PosixPath('/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugins/clients/pyload.py')\r\n    |              -> 'flexget.plugins.clients.pyload'\r\n    -> <function _import_plugin at 0x7fceb0f59d08>\r\n> File \"/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugin.py\", line 424, in _import_plugin\r\n    import_module(module_name)\r\n    |             -> 'flexget.plugins.clients.pyload'\r\n    -> <function import_module at 0x7fceb2ba36a8>\r\n  File \"/home/loke/.psources/flexget/lib/python3.7/importlib/__init__.py\", line 127, in import_module\r\n    return _bootstrap._gcd_import(name[level:], package, level)\r\n           |          |           |    |        |        -> 0\r\n           |          |           |    |        -> None\r\n           |          |           |    -> 0\r\n           |          |           -> 'flexget.plugins.clients.pyload'\r\n           |          -> <function _gcd_import at 0x7fceb2ce5e18>\r\n           -> <module 'importlib._bootstrap' (frozen)>\r\n  File \"<frozen importlib._bootstrap>\", line 1006, in _gcd_import\r\n  File \"<frozen importlib._bootstrap>\", line 983, in _find_and_load\r\n  File \"<frozen importlib._bootstrap>\", line 967, in _find_and_load_unlocked\r\n  File \"<frozen importlib._bootstrap>\", line 677, in _load_unlocked\r\n  File \"<frozen importlib._bootstrap_external>\", line 728, in exec_module\r\n  File \"<frozen importlib._bootstrap>\", line 219, in _call_with_frames_removed\r\n  File \"/home/loke/.psources/flexget/lib/python3.7/site-packages/flexget/plugins/clients/pyload.py\", line 11, in <module>\r\n    from packaging import version\r\n\r\nModuleNotFoundError: No module named 'packaging'\r\n```\r\n\r\n### Additional information:\r\n\r\n- FlexGet version: 3.1.45 (3.1.44 works fine)\r\n- Python version: 3.7\r\n- Installation method: virtualenv\r\n- Using daemon (yes/no): yes \r\n- OS and version: debian 10\r\n\r\n\n", "before_files": [{"content": "from urllib.parse import quote\n\nfrom loguru import logger\nfrom requests.exceptions import RequestException\n\nfrom flexget import plugin\nfrom flexget.config_schema import one_or_more\nfrom flexget.event import event\nfrom flexget.utils import json\nfrom flexget.utils.template import RenderError\nfrom packaging import version\nlogger = logger.bind(name='pyload')\n\n\nclass PyloadApi:\n    def __init__(self, requests, url):\n        self.requests = requests\n        self.url = url\n\n    def get_session(self, config):\n        # Login\n        data = {'username': config['username'], 'password': config['password']}\n        result = self.post('login', data=data)\n        response = result.json()\n        if not response:\n            raise plugin.PluginError('Login failed', logger)\n\n        if isinstance(response, str):\n            return response.replace('\"', '')\n        else:\n            return response\n\n    def get(self, method):\n        try:\n            return self.requests.get(self.url.rstrip(\"/\") + \"/\" + method.strip(\"/\"))\n        except RequestException as e:\n            if e.response and e.response.status_code == 500:\n                raise plugin.PluginError(\n                    'Internal API Error: <%s> <%s>' % (method, self.url), logger\n                )\n            raise\n\n    def post(self, method, data):\n        try:\n            return self.requests.post(self.url.rstrip(\"/\") + \"/\" + method.strip(\"/\"), data=data)\n        except RequestException as e:\n            if e.response and e.response.status_code == 500:\n                raise plugin.PluginError(\n                    'Internal API Error: <%s> <%s> <%s>' % (method, self.url, data), logger\n                )\n            raise\n\n\nclass PluginPyLoad:\n    \"\"\"\n    Parse task content or url for hoster links and adds them to pyLoad.\n\n    Example::\n\n      pyload:\n        api: http://localhost:8000/api\n        queue: yes\n        username: my_username\n        password: my_password\n        folder: desired_folder\n        package: desired_package_name (jinja2 supported)\n        package_password: desired_package_password\n        hoster:\n          - YoutubeCom\n        parse_url: no\n        multiple_hoster: yes\n        enabled: yes\n\n    Default values for the config elements::\n\n      pyload:\n          api: http://localhost:8000/api\n          queue: no\n          hoster: ALL\n          parse_url: no\n          multiple_hoster: yes\n          enabled: yes\n    \"\"\"\n\n    __author__ = 'http://pyload.org'\n    __version__ = '0.5'\n\n    DEFAULT_API = 'http://localhost:8000/api'\n    DEFAULT_QUEUE = False\n    DEFAULT_FOLDER = ''\n    DEFAULT_HOSTER = []\n    DEFAULT_PARSE_URL = False\n    DEFAULT_MULTIPLE_HOSTER = True\n    DEFAULT_PREFERRED_HOSTER_ONLY = False\n    DEFAULT_HANDLE_NO_URL_AS_FAILURE = False\n\n    schema = {\n        'type': 'object',\n        'properties': {\n            'api': {'type': 'string'},\n            'username': {'type': 'string'},\n            'password': {'type': 'string'},\n            'folder': {'type': 'string'},\n            'package': {'type': 'string'},\n            'package_password': {'type': 'string'},\n            'queue': {'type': 'boolean'},\n            'parse_url': {'type': 'boolean'},\n            'multiple_hoster': {'type': 'boolean'},\n            'hoster': one_or_more({'type': 'string'}),\n            'preferred_hoster_only': {'type': 'boolean'},\n            'handle_no_url_as_failure': {'type': 'boolean'},\n            'enabled': {'type': 'boolean'},\n        },\n        'required': ['username', 'password'],\n        'additionalProperties': False,\n    }\n\n    def on_task_output(self, task, config):\n        if not config.get('enabled', True):\n            return\n        if not task.accepted:\n            return\n\n        self.add_entries(task, config)\n\n    def add_entries(self, task, config):\n        \"\"\"Adds accepted entries\"\"\"\n\n        apiurl = config.get('api', self.DEFAULT_API)\n        api = PyloadApi(task.requests, apiurl)\n\n        try:\n            session = api.get_session(config)\n        except IOError:\n            raise plugin.PluginError('pyLoad not reachable', logger)\n        except plugin.PluginError:\n            raise\n        except Exception as e:\n            raise plugin.PluginError('Unknown error: %s' % str(e), logger)\n\n        remote_version = None\n        try:\n            remote_version = api.get('getServerVersion')\n        except RequestException as e:\n            if e.response is not None and e.response.status_code == 404:\n                remote_version = json.loads(api.get('get_server_version').content)\n            else:\n                raise e\n\n        parse_urls_command = 'parseURLs'\n        add_package_command = 'addPackage'\n        set_package_data_command = 'setPackageData'\n\n        is_pyload_ng = False\n        if version.parse(remote_version) >= version.parse('0.5'):\n            parse_urls_command = 'parse_urls'\n            add_package_command = 'add_package'\n            set_package_data_command = 'set_package_date'\n            is_pyload_ng = True\n\n        hoster = config.get('hoster', self.DEFAULT_HOSTER)\n\n        for entry in task.accepted:\n            # bunch of urls now going to check\n            content = entry.get('description', '') + ' ' + quote(entry['url'])\n            content = json.dumps(content)\n\n            if is_pyload_ng:\n                url = (\n                    entry['url']\n                    if config.get('parse_url', self.DEFAULT_PARSE_URL)\n                    else ''\n                )\n            else:\n                url = (\n                    json.dumps(entry['url'])\n                    if config.get('parse_url', self.DEFAULT_PARSE_URL)\n                    else \"''\"\n                )\n\n            logger.debug('Parsing url {}', url)\n\n            data = {'html': content, 'url': url}\n            if not is_pyload_ng:\n                data['session'] = session\n            result = api.post(parse_urls_command, data=data)\n\n            parsed = result.json()\n\n            urls = []\n\n            # check for preferred hoster\n            for name in hoster:\n                if name in parsed:\n                    urls.extend(parsed[name])\n                    if not config.get('multiple_hoster', self.DEFAULT_MULTIPLE_HOSTER):\n                        break\n\n            # no preferred hoster and not preferred hoster only - add all recognized plugins\n            if not urls and not config.get(\n                'preferred_hoster_only', self.DEFAULT_PREFERRED_HOSTER_ONLY\n            ):\n                for name, purls in parsed.items():\n                    if name != 'BasePlugin':\n                        urls.extend(purls)\n\n            if task.options.test:\n                logger.info('Would add `{}` to pyload', urls)\n                continue\n\n            # no urls found\n            if not urls:\n                if config.get('handle_no_url_as_failure', self.DEFAULT_HANDLE_NO_URL_AS_FAILURE):\n                    entry.fail('No suited urls in entry %s' % entry['title'])\n                else:\n                    logger.info('No suited urls in entry {}', entry['title'])\n                continue\n\n            logger.debug('Add {} urls to pyLoad', len(urls))\n\n            try:\n                dest = 1 if config.get('queue', self.DEFAULT_QUEUE) else 0  # Destination.Queue = 1\n\n                # Use the title of the entry, if no naming schema for the package is defined.\n                name = config.get('package', entry['title'])\n\n                # If name has jinja template, render it\n                try:\n                    name = entry.render(name)\n                except RenderError as e:\n                    name = entry['title']\n                    logger.error('Error rendering jinja event: {}', e)\n\n                if is_pyload_ng:\n                    data = {\n                        'name': name.encode('ascii', 'ignore').decode(),\n                        'links': urls,\n                        'dest': dest,\n                    }\n                else:\n                    data = {\n                        'name': json.dumps(name.encode('ascii', 'ignore').decode()),\n                        'links': json.dumps(urls),\n                        'dest': json.dumps(dest),\n                        'session': session\n                    }\n\n                pid = api.post(add_package_command, data=data).text\n                logger.debug('added package pid: {}', pid)\n\n                # Set Folder\n                folder = config.get('folder', self.DEFAULT_FOLDER)\n                folder = entry.get('path', folder)\n                if folder:\n                    # If folder has jinja template, render it\n                    try:\n                        folder = entry.render(folder)\n                    except RenderError as e:\n                        folder = self.DEFAULT_FOLDER\n                        logger.error('Error rendering jinja event: {}', e)\n                    # set folder with api\n                    data = json.dumps({'folder': folder})\n                    post_data = {'pid': pid, 'data': data}\n                    if not is_pyload_ng:\n                        post_data['session'] = session\n                    api.post(set_package_data_command, data=post_data)\n\n                # Set Package Password\n                package_password = config.get('package_password')\n                if package_password:\n                    data = json.dumps({'password': package_password})\n                    post_data = {'pid': pid, 'data': data}\n                    if not is_pyload_ng:\n                        post_data['session'] = session\n                    api.post(set_package_data_command, data=post_data)\n\n            except Exception as e:\n                entry.fail(str(e))\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(PluginPyLoad, 'pyload', api_ver=2)\n", "path": "flexget/plugins/clients/pyload.py"}], "after_files": [{"content": "from urllib.parse import quote\n\nfrom loguru import logger\nfrom requests.exceptions import RequestException\n\nfrom flexget import plugin\nfrom flexget.config_schema import one_or_more\nfrom flexget.event import event\nfrom flexget.utils import json\nfrom flexget.utils.template import RenderError\nlogger = logger.bind(name='pyload')\n\n\nclass PyloadApi:\n    def __init__(self, requests, url):\n        self.requests = requests\n        self.url = url\n\n    def get_session(self, config):\n        # Login\n        data = {'username': config['username'], 'password': config['password']}\n        result = self.post('login', data=data)\n        response = result.json()\n        if not response:\n            raise plugin.PluginError('Login failed', logger)\n\n        if isinstance(response, str):\n            return response.replace('\"', '')\n        else:\n            return response\n\n    def get(self, method):\n        try:\n            return self.requests.get(self.url.rstrip(\"/\") + \"/\" + method.strip(\"/\"))\n        except RequestException as e:\n            if e.response and e.response.status_code == 500:\n                raise plugin.PluginError(\n                    'Internal API Error: <%s> <%s>' % (method, self.url), logger\n                )\n            raise\n\n    def post(self, method, data):\n        try:\n            return self.requests.post(self.url.rstrip(\"/\") + \"/\" + method.strip(\"/\"), data=data)\n        except RequestException as e:\n            if e.response and e.response.status_code == 500:\n                raise plugin.PluginError(\n                    'Internal API Error: <%s> <%s> <%s>' % (method, self.url, data), logger\n                )\n            raise\n\n\nclass PluginPyLoad:\n    \"\"\"\n    Parse task content or url for hoster links and adds them to pyLoad.\n\n    Example::\n\n      pyload:\n        api: http://localhost:8000/api\n        queue: yes\n        username: my_username\n        password: my_password\n        folder: desired_folder\n        package: desired_package_name (jinja2 supported)\n        package_password: desired_package_password\n        hoster:\n          - YoutubeCom\n        parse_url: no\n        multiple_hoster: yes\n        enabled: yes\n\n    Default values for the config elements::\n\n      pyload:\n          api: http://localhost:8000/api\n          queue: no\n          hoster: ALL\n          parse_url: no\n          multiple_hoster: yes\n          enabled: yes\n    \"\"\"\n\n    __author__ = 'http://pyload.org'\n    __version__ = '0.5'\n\n    DEFAULT_API = 'http://localhost:8000/api'\n    DEFAULT_QUEUE = False\n    DEFAULT_FOLDER = ''\n    DEFAULT_HOSTER = []\n    DEFAULT_PARSE_URL = False\n    DEFAULT_MULTIPLE_HOSTER = True\n    DEFAULT_PREFERRED_HOSTER_ONLY = False\n    DEFAULT_HANDLE_NO_URL_AS_FAILURE = False\n\n    schema = {\n        'type': 'object',\n        'properties': {\n            'api': {'type': 'string'},\n            'username': {'type': 'string'},\n            'password': {'type': 'string'},\n            'folder': {'type': 'string'},\n            'package': {'type': 'string'},\n            'package_password': {'type': 'string'},\n            'queue': {'type': 'boolean'},\n            'parse_url': {'type': 'boolean'},\n            'multiple_hoster': {'type': 'boolean'},\n            'hoster': one_or_more({'type': 'string'}),\n            'preferred_hoster_only': {'type': 'boolean'},\n            'handle_no_url_as_failure': {'type': 'boolean'},\n            'enabled': {'type': 'boolean'},\n        },\n        'required': ['username', 'password'],\n        'additionalProperties': False,\n    }\n\n    def on_task_output(self, task, config):\n        if not config.get('enabled', True):\n            return\n        if not task.accepted:\n            return\n\n        self.add_entries(task, config)\n\n    @staticmethod\n    def get_version_from_packaging():\n        version = None\n        try:\n            from packaging import version\n        except ModuleNotFoundError:\n            logger.warning('packaging is not installed')\n        return version\n\n    def add_entries(self, task, config):\n        \"\"\"Adds accepted entries\"\"\"\n\n        apiurl = config.get('api', self.DEFAULT_API)\n        api = PyloadApi(task.requests, apiurl)\n\n        try:\n            session = api.get_session(config)\n        except IOError:\n            raise plugin.PluginError('pyLoad not reachable', logger)\n        except plugin.PluginError:\n            raise\n        except Exception as e:\n            raise plugin.PluginError('Unknown error: %s' % str(e), logger)\n\n        remote_version = None\n        try:\n            remote_version = api.get('getServerVersion')\n        except RequestException as e:\n            if e.response is not None and e.response.status_code == 404:\n                remote_version = json.loads(api.get('get_server_version').content)\n            else:\n                raise e\n\n        parse_urls_command = 'parseURLs'\n        add_package_command = 'addPackage'\n        set_package_data_command = 'setPackageData'\n\n        is_pyload_ng = False\n        version = self.get_version_from_packaging()\n        if version and version.parse(remote_version) >= version.parse('0.5'):\n            parse_urls_command = 'parse_urls'\n            add_package_command = 'add_package'\n            set_package_data_command = 'set_package_date'\n            is_pyload_ng = True\n\n        hoster = config.get('hoster', self.DEFAULT_HOSTER)\n\n        for entry in task.accepted:\n            # bunch of urls now going to check\n            content = entry.get('description', '') + ' ' + quote(entry['url'])\n            content = json.dumps(content)\n\n            if is_pyload_ng:\n                url = (\n                    entry['url']\n                    if config.get('parse_url', self.DEFAULT_PARSE_URL)\n                    else ''\n                )\n            else:\n                url = (\n                    json.dumps(entry['url'])\n                    if config.get('parse_url', self.DEFAULT_PARSE_URL)\n                    else \"''\"\n                )\n\n            logger.debug('Parsing url {}', url)\n\n            data = {'html': content, 'url': url}\n            if not is_pyload_ng:\n                data['session'] = session\n            result = api.post(parse_urls_command, data=data)\n\n            parsed = result.json()\n\n            urls = []\n\n            # check for preferred hoster\n            for name in hoster:\n                if name in parsed:\n                    urls.extend(parsed[name])\n                    if not config.get('multiple_hoster', self.DEFAULT_MULTIPLE_HOSTER):\n                        break\n\n            # no preferred hoster and not preferred hoster only - add all recognized plugins\n            if not urls and not config.get(\n                'preferred_hoster_only', self.DEFAULT_PREFERRED_HOSTER_ONLY\n            ):\n                for name, purls in parsed.items():\n                    if name != 'BasePlugin':\n                        urls.extend(purls)\n\n            if task.options.test:\n                logger.info('Would add `{}` to pyload', urls)\n                continue\n\n            # no urls found\n            if not urls:\n                if config.get('handle_no_url_as_failure', self.DEFAULT_HANDLE_NO_URL_AS_FAILURE):\n                    entry.fail('No suited urls in entry %s' % entry['title'])\n                else:\n                    logger.info('No suited urls in entry {}', entry['title'])\n                continue\n\n            logger.debug('Add {} urls to pyLoad', len(urls))\n\n            try:\n                dest = 1 if config.get('queue', self.DEFAULT_QUEUE) else 0  # Destination.Queue = 1\n\n                # Use the title of the entry, if no naming schema for the package is defined.\n                name = config.get('package', entry['title'])\n\n                # If name has jinja template, render it\n                try:\n                    name = entry.render(name)\n                except RenderError as e:\n                    name = entry['title']\n                    logger.error('Error rendering jinja event: {}', e)\n\n                if is_pyload_ng:\n                    data = {\n                        'name': name.encode('ascii', 'ignore').decode(),\n                        'links': urls,\n                        'dest': dest,\n                    }\n                else:\n                    data = {\n                        'name': json.dumps(name.encode('ascii', 'ignore').decode()),\n                        'links': json.dumps(urls),\n                        'dest': json.dumps(dest),\n                        'session': session\n                    }\n\n                pid = api.post(add_package_command, data=data).text\n                logger.debug('added package pid: {}', pid)\n\n                # Set Folder\n                folder = config.get('folder', self.DEFAULT_FOLDER)\n                folder = entry.get('path', folder)\n                if folder:\n                    # If folder has jinja template, render it\n                    try:\n                        folder = entry.render(folder)\n                    except RenderError as e:\n                        folder = self.DEFAULT_FOLDER\n                        logger.error('Error rendering jinja event: {}', e)\n                    # set folder with api\n                    data = json.dumps({'folder': folder})\n                    post_data = {'pid': pid, 'data': data}\n                    if not is_pyload_ng:\n                        post_data['session'] = session\n                    api.post(set_package_data_command, data=post_data)\n\n                # Set Package Password\n                package_password = config.get('package_password')\n                if package_password:\n                    data = json.dumps({'password': package_password})\n                    post_data = {'pid': pid, 'data': data}\n                    if not is_pyload_ng:\n                        post_data['session'] = session\n                    api.post(set_package_data_command, data=post_data)\n\n            except Exception as e:\n                entry.fail(str(e))\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(PluginPyLoad, 'pyload', api_ver=2)\n", "path": "flexget/plugins/clients/pyload.py"}]}