We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Crash when using convert_magnet with aria2.
There is a crash when using convert_magnet with aria2.

```
2017-01-02 19:51 CRITICAL task          discover_movies_hd BUG: Unhandled error in plugin aria2: u'file'
2017-01-02 19:51 CRITICAL manager       discover_movies_hd An unexpected crash has occurred. Writing crash report to /home/wyrm/.flexget/crash_report.2017.01.02.195150778857.log. Please verify you are running the latest version of flexget by using "flexget -V" from CLI or by using version_checker plugin at http://flexget.com/wiki/Plugins/version_checker. You are currently using version 2.8.17.dev
2017-01-02 19:51 WARNING  task          discover_movies_hd Aborting task (plugin: aria2)

```
I don't have a crashlog, sorry.

--- 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/modify/convert_magnet.py`
Content:
```
1 from __future__ import unicode_literals, division, absolute_import
2 from builtins import *  # noqa pylint: disable=unused-import, redefined-builtin
3 import os
4 import time
5 import logging
6 
7 from flexget import plugin
8 from flexget.event import event
9 from flexget.utils.tools import parse_timedelta
10 from flexget.utils.pathscrub import pathscrub
11 
12 log = logging.getLogger('convert_magnet')
13 
14 
15 class ConvertMagnet(object):
16     """Convert magnet only entries to a torrent file"""
17 
18     schema = {
19         "oneOf": [
20             # Allow convert_magnet: no form to turn off plugin altogether
21             {"type": "boolean"},
22             {
23                 "type": "object",
24                 "properties": {
25                     "timeout": {"type": "string", "format": "interval", "default": "30 seconds"},
26                 },
27                 "additionalProperties": False
28             }
29         ]
30     }
31 
32     def magnet_to_torrent(self, magnet_uri, destination_folder, timeout):
33         import libtorrent
34         params = libtorrent.parse_magnet_uri(magnet_uri)
35         session = libtorrent.session()
36         # for some reason the info_hash needs to be bytes but it's a struct called sha1_hash
37         params['info_hash'] = bytes(params['info_hash'])
38         handle = libtorrent.add_magnet_uri(session, magnet_uri, params)
39         log.debug('Acquiring torrent metadata for magnet %s', magnet_uri)
40         timeout_value = timeout
41         while not handle.has_metadata():
42             time.sleep(0.1)
43             timeout_value -= 0.1
44             if timeout_value <= 0:
45                 raise plugin.PluginError('Timed out after {} seconds trying to magnetize'.format(timeout))
46         log.debug('Metadata acquired')
47         torrent_info = handle.get_torrent_info()
48         torrent_file = libtorrent.create_torrent(torrent_info)
49         torrent_path = pathscrub(os.path.join(destination_folder, torrent_info.name() + ".torrent"))
50         with open(torrent_path, "wb") as f:
51             f.write(libtorrent.bencode(torrent_file.generate()))
52         log.debug('Torrent file wrote to %s', torrent_path)
53         return torrent_path
54 
55     def prepare_config(self, config):
56         if not isinstance(config, dict):
57             config = {}
58         config.setdefault('timeout', '30 seconds')
59         return config
60 
61     @plugin.priority(255)
62     def on_task_start(self, task, config):
63         if config is False:
64             return
65         try:
66             import libtorrent  # noqa
67         except ImportError:
68             raise plugin.DependencyError('convert_magnet', 'libtorrent', 'libtorrent package required', log)
69 
70     @plugin.priority(130)
71     def on_task_download(self, task, config):
72         if config is False:
73             return
74         config = self.prepare_config(config)
75         # Create the conversion target directory
76         converted_path = os.path.join(task.manager.config_base, 'converted')
77 
78         timeout = parse_timedelta(config['timeout']).total_seconds()
79 
80         if not os.path.isdir(converted_path):
81             os.mkdir(converted_path)
82 
83         for entry in task.accepted:
84             if entry['url'].startswith('magnet:'):
85                 entry.setdefault('urls', [entry['url']])
86                 try:
87                     log.info('Converting entry {} magnet URI to a torrent file'.format(entry['title']))
88                     torrent_file = self.magnet_to_torrent(entry['url'], converted_path, timeout)
89                 except (plugin.PluginError, TypeError) as e:
90                     log.error('Unable to convert Magnet URI for entry %s: %s', entry['title'], e)
91                     continue
92                 # Windows paths need an extra / prepended to them for url
93                 if not torrent_file.startswith('/'):
94                     torrent_file = '/' + torrent_file
95                 entry['url'] = torrent_file
96                 entry['file'] = torrent_file
97                 # make sure it's first in the list because of how download plugin works
98                 entry['urls'].insert(0, 'file://{}'.format(torrent_file))
99 
100 
101 @event('plugin.register')
102 def register_plugin():
103     plugin.register(ConvertMagnet, 'convert_magnet', api_ver=2)
104
```

Path: `flexget/plugins/clients/aria2.py`
Content:
```
1 from __future__ import unicode_literals, division, absolute_import
2 from builtins import *  # noqa pylint: disable=unused-import, redefined-builtin
3 
4 import logging
5 import os
6 import xmlrpc.client
7 from socket import error as socket_error
8 
9 from flexget import plugin
10 from flexget.event import event
11 from flexget.utils.template import RenderError
12 
13 log = logging.getLogger('aria2')
14 
15 
16 class OutputAria2(object):
17     """
18     Simple Aria2 output
19 
20     Example::
21 
22         aria2:
23           path: ~/downloads/
24 
25     """
26 
27     schema = {
28         'type': 'object',
29         'properties': {
30             'server': {'type': 'string', 'default': 'localhost'},
31             'port': {'type': 'integer', 'default': 6800},
32             'secret': {'type': 'string', 'default': ''},
33             'username': {'type': 'string', 'default': ''}, # NOTE: To be deprecated by aria2
34             'password': {'type': 'string', 'default': ''},
35             'path': {'type': 'string'},
36             'options': {
37                 'type': 'object',
38                 'additionalProperties': {'oneOf': [{'type': 'string'}, {'type': 'integer'}]}
39             }
40 
41         },
42         'required': ['path'],
43         'additionalProperties': False
44     }
45 
46     def aria2_connection(self, server, port, username=None, password=None):
47         if username and password:
48             userpass = '%s:%s@' % (username, password)
49         else:
50             userpass = ''
51         url = 'http://%s%s:%s/rpc' % (userpass, server, port)
52         log.debug('aria2 url: %s' % url)
53         log.info('Connecting to daemon at %s', url)
54         try:
55             return xmlrpc.client.ServerProxy(url).aria2
56         except xmlrpc.client.ProtocolError as err:
57             raise plugin.PluginError('Could not connect to aria2 at %s. Protocol error %s: %s'
58                               % (url, err.errcode, err.errmsg), log)
59         except xmlrpc.client.Fault as err:
60             raise plugin.PluginError('XML-RPC fault: Unable to connect to aria2 daemon at %s: %s'
61                               % (url, err.faultString), log)
62         except socket_error as e:
63             raise plugin.PluginError('Socket connection issue with aria2 daemon at %s: %s' % (url, e), log)
64         except:
65             log.debug('Unexpected error during aria2 connection', exc_info=True)
66             raise plugin.PluginError('Unidentified error during connection to aria2 daemon', log)
67 
68     def prepare_config(self, config):
69         config.setdefault('server', 'localhost')
70         config.setdefault('port', 6800)
71         config.setdefault('username', '')
72         config.setdefault('password', '')
73         config.setdefault('secret', '')
74         config.setdefault('options', {})
75         return config
76 
77     def on_task_output(self, task, config):
78         # don't add when learning
79         if task.options.learn:
80             return
81         config = self.prepare_config(config)
82         aria2 = self.aria2_connection(config['server'], config['port'],
83                                       config['username'], config['password'])
84         for entry in task.accepted:
85             if task.options.test:
86                 log.verbose('Would add `%s` to aria2.', entry['title'])
87                 continue
88             try:
89                 self.add_entry(aria2, entry, config)
90             except socket_error as se:
91                 entry.fail('Unable to reach Aria2: %s', se)
92             except xmlrpc.client.Fault as err:
93                 log.critical('Fault code %s message %s', err.faultCode, err.faultString)
94                 entry.fail('Aria2 communication Fault')
95             except Exception as e:
96                 log.debug('Exception type %s', type(e), exc_info=True)
97                 raise
98 
99     def add_entry(self, aria2, entry, config):
100         """
101         Add entry to Aria2
102         """
103         options = config['options']
104         try:
105             options['dir'] = os.path.expanduser(entry.render(config['path']).rstrip('/'))
106         except RenderError as e:
107             entry.fail('failed to render \'path\': %s' % e)
108             return
109         secret = None
110         if config['secret']:
111             secret = 'token:%s' % config['secret']
112         # handle torrent files
113         if 'torrent' in entry:
114             if secret:
115                 return aria2.addTorrent(secret, xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))
116             return aria2.addTorrent(xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))
117         # handle everything else (except metalink -- which is unsupported)
118         # so magnets, https, http, ftp .. etc
119         if secret:
120             return aria2.addUri(secret, [entry['url']], options)
121         return aria2.addUri([entry['url']], options)
122 
123 
124 @event('plugin.register')
125 def register_plugin():
126     plugin.register(OutputAria2, 'aria2', api_ver=2)
127
```
--- 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/aria2.py b/flexget/plugins/clients/aria2.py
--- a/flexget/plugins/clients/aria2.py
+++ b/flexget/plugins/clients/aria2.py
@@ -111,9 +111,17 @@
             secret = 'token:%s' % config['secret']
         # handle torrent files
         if 'torrent' in entry:
+            if 'file' in entry:
+                torrent_file = entry['file']
+            elif 'location' in entry:
+                # in case download plugin moved the file elsewhere
+                torrent_file = entry['location']
+            else:
+                entry.fail('Cannot find torrent file')
+                return
             if secret:
-                return aria2.addTorrent(secret, xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))
-            return aria2.addTorrent(xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))
+                return aria2.addTorrent(secret, xmlrpc.client.Binary(open(torrent_file, mode='rb').read()), [], options)
+            return aria2.addTorrent(xmlrpc.client.Binary(open(torrent_file, mode='rb').read()), [], options)
         # handle everything else (except metalink -- which is unsupported)
         # so magnets, https, http, ftp .. etc
         if secret:
diff --git a/flexget/plugins/modify/convert_magnet.py b/flexget/plugins/modify/convert_magnet.py
--- a/flexget/plugins/modify/convert_magnet.py
+++ b/flexget/plugins/modify/convert_magnet.py
@@ -33,8 +33,10 @@
         import libtorrent
         params = libtorrent.parse_magnet_uri(magnet_uri)
         session = libtorrent.session()
-        # for some reason the info_hash needs to be bytes but it's a struct called sha1_hash
-        params['info_hash'] = bytes(params['info_hash'])
+        lt_version = [int(v) for v in libtorrent.version.split('.')]
+        if lt_version > [0,16,13,0]:
+            # for some reason the info_hash needs to be bytes but it's a struct called sha1_hash
+            params['info_hash'] = params['info_hash'].to_bytes()
         handle = libtorrent.add_magnet_uri(session, magnet_uri, params)
         log.debug('Acquiring torrent metadata for magnet %s', magnet_uri)
         timeout_value = timeout

{"golden_diff": "diff --git a/flexget/plugins/clients/aria2.py b/flexget/plugins/clients/aria2.py\n--- a/flexget/plugins/clients/aria2.py\n+++ b/flexget/plugins/clients/aria2.py\n@@ -111,9 +111,17 @@\n             secret = 'token:%s' % config['secret']\n         # handle torrent files\n         if 'torrent' in entry:\n+            if 'file' in entry:\n+                torrent_file = entry['file']\n+            elif 'location' in entry:\n+                # in case download plugin moved the file elsewhere\n+                torrent_file = entry['location']\n+            else:\n+                entry.fail('Cannot find torrent file')\n+                return\n             if secret:\n-                return aria2.addTorrent(secret, xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))\n-            return aria2.addTorrent(xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))\n+                return aria2.addTorrent(secret, xmlrpc.client.Binary(open(torrent_file, mode='rb').read()), [], options)\n+            return aria2.addTorrent(xmlrpc.client.Binary(open(torrent_file, mode='rb').read()), [], options)\n         # handle everything else (except metalink -- which is unsupported)\n         # so magnets, https, http, ftp .. etc\n         if secret:\ndiff --git a/flexget/plugins/modify/convert_magnet.py b/flexget/plugins/modify/convert_magnet.py\n--- a/flexget/plugins/modify/convert_magnet.py\n+++ b/flexget/plugins/modify/convert_magnet.py\n@@ -33,8 +33,10 @@\n         import libtorrent\n         params = libtorrent.parse_magnet_uri(magnet_uri)\n         session = libtorrent.session()\n-        # for some reason the info_hash needs to be bytes but it's a struct called sha1_hash\n-        params['info_hash'] = bytes(params['info_hash'])\n+        lt_version = [int(v) for v in libtorrent.version.split('.')]\n+        if lt_version > [0,16,13,0]:\n+            # for some reason the info_hash needs to be bytes but it's a struct called sha1_hash\n+            params['info_hash'] = params['info_hash'].to_bytes()\n         handle = libtorrent.add_magnet_uri(session, magnet_uri, params)\n         log.debug('Acquiring torrent metadata for magnet %s', magnet_uri)\n         timeout_value = timeout\n", "issue": "Crash when using convert_magnet with aria2.\nThere is a crash when using convert_magnet with aria2.\r\n\r\n```\r\n2017-01-02 19:51 CRITICAL task          discover_movies_hd BUG: Unhandled error in plugin aria2: u'file'\r\n2017-01-02 19:51 CRITICAL manager       discover_movies_hd An unexpected crash has occurred. Writing crash report to /home/wyrm/.flexget/crash_report.2017.01.02.195150778857.log. Please verify you are running the latest version of flexget by using \"flexget -V\" from CLI or by using version_checker plugin at http://flexget.com/wiki/Plugins/version_checker. You are currently using version 2.8.17.dev\r\n2017-01-02 19:51 WARNING  task          discover_movies_hd Aborting task (plugin: aria2)\r\n\r\n```\r\nI don't have a crashlog, sorry.\n", "before_files": [{"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\nimport os\nimport time\nimport logging\n\nfrom flexget import plugin\nfrom flexget.event import event\nfrom flexget.utils.tools import parse_timedelta\nfrom flexget.utils.pathscrub import pathscrub\n\nlog = logging.getLogger('convert_magnet')\n\n\nclass ConvertMagnet(object):\n    \"\"\"Convert magnet only entries to a torrent file\"\"\"\n\n    schema = {\n        \"oneOf\": [\n            # Allow convert_magnet: no form to turn off plugin altogether\n            {\"type\": \"boolean\"},\n            {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"timeout\": {\"type\": \"string\", \"format\": \"interval\", \"default\": \"30 seconds\"},\n                },\n                \"additionalProperties\": False\n            }\n        ]\n    }\n\n    def magnet_to_torrent(self, magnet_uri, destination_folder, timeout):\n        import libtorrent\n        params = libtorrent.parse_magnet_uri(magnet_uri)\n        session = libtorrent.session()\n        # for some reason the info_hash needs to be bytes but it's a struct called sha1_hash\n        params['info_hash'] = bytes(params['info_hash'])\n        handle = libtorrent.add_magnet_uri(session, magnet_uri, params)\n        log.debug('Acquiring torrent metadata for magnet %s', magnet_uri)\n        timeout_value = timeout\n        while not handle.has_metadata():\n            time.sleep(0.1)\n            timeout_value -= 0.1\n            if timeout_value <= 0:\n                raise plugin.PluginError('Timed out after {} seconds trying to magnetize'.format(timeout))\n        log.debug('Metadata acquired')\n        torrent_info = handle.get_torrent_info()\n        torrent_file = libtorrent.create_torrent(torrent_info)\n        torrent_path = pathscrub(os.path.join(destination_folder, torrent_info.name() + \".torrent\"))\n        with open(torrent_path, \"wb\") as f:\n            f.write(libtorrent.bencode(torrent_file.generate()))\n        log.debug('Torrent file wrote to %s', torrent_path)\n        return torrent_path\n\n    def prepare_config(self, config):\n        if not isinstance(config, dict):\n            config = {}\n        config.setdefault('timeout', '30 seconds')\n        return config\n\n    @plugin.priority(255)\n    def on_task_start(self, task, config):\n        if config is False:\n            return\n        try:\n            import libtorrent  # noqa\n        except ImportError:\n            raise plugin.DependencyError('convert_magnet', 'libtorrent', 'libtorrent package required', log)\n\n    @plugin.priority(130)\n    def on_task_download(self, task, config):\n        if config is False:\n            return\n        config = self.prepare_config(config)\n        # Create the conversion target directory\n        converted_path = os.path.join(task.manager.config_base, 'converted')\n\n        timeout = parse_timedelta(config['timeout']).total_seconds()\n\n        if not os.path.isdir(converted_path):\n            os.mkdir(converted_path)\n\n        for entry in task.accepted:\n            if entry['url'].startswith('magnet:'):\n                entry.setdefault('urls', [entry['url']])\n                try:\n                    log.info('Converting entry {} magnet URI to a torrent file'.format(entry['title']))\n                    torrent_file = self.magnet_to_torrent(entry['url'], converted_path, timeout)\n                except (plugin.PluginError, TypeError) as e:\n                    log.error('Unable to convert Magnet URI for entry %s: %s', entry['title'], e)\n                    continue\n                # Windows paths need an extra / prepended to them for url\n                if not torrent_file.startswith('/'):\n                    torrent_file = '/' + torrent_file\n                entry['url'] = torrent_file\n                entry['file'] = torrent_file\n                # make sure it's first in the list because of how download plugin works\n                entry['urls'].insert(0, 'file://{}'.format(torrent_file))\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(ConvertMagnet, 'convert_magnet', api_ver=2)\n", "path": "flexget/plugins/modify/convert_magnet.py"}, {"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\n\nimport logging\nimport os\nimport xmlrpc.client\nfrom socket import error as socket_error\n\nfrom flexget import plugin\nfrom flexget.event import event\nfrom flexget.utils.template import RenderError\n\nlog = logging.getLogger('aria2')\n\n\nclass OutputAria2(object):\n    \"\"\"\n    Simple Aria2 output\n\n    Example::\n\n        aria2:\n          path: ~/downloads/\n\n    \"\"\"\n\n    schema = {\n        'type': 'object',\n        'properties': {\n            'server': {'type': 'string', 'default': 'localhost'},\n            'port': {'type': 'integer', 'default': 6800},\n            'secret': {'type': 'string', 'default': ''},\n            'username': {'type': 'string', 'default': ''}, # NOTE: To be deprecated by aria2\n            'password': {'type': 'string', 'default': ''},\n            'path': {'type': 'string'},\n            'options': {\n                'type': 'object',\n                'additionalProperties': {'oneOf': [{'type': 'string'}, {'type': 'integer'}]}\n            }\n\n        },\n        'required': ['path'],\n        'additionalProperties': False\n    }\n\n    def aria2_connection(self, server, port, username=None, password=None):\n        if username and password:\n            userpass = '%s:%s@' % (username, password)\n        else:\n            userpass = ''\n        url = 'http://%s%s:%s/rpc' % (userpass, server, port)\n        log.debug('aria2 url: %s' % url)\n        log.info('Connecting to daemon at %s', url)\n        try:\n            return xmlrpc.client.ServerProxy(url).aria2\n        except xmlrpc.client.ProtocolError as err:\n            raise plugin.PluginError('Could not connect to aria2 at %s. Protocol error %s: %s'\n                              % (url, err.errcode, err.errmsg), log)\n        except xmlrpc.client.Fault as err:\n            raise plugin.PluginError('XML-RPC fault: Unable to connect to aria2 daemon at %s: %s'\n                              % (url, err.faultString), log)\n        except socket_error as e:\n            raise plugin.PluginError('Socket connection issue with aria2 daemon at %s: %s' % (url, e), log)\n        except:\n            log.debug('Unexpected error during aria2 connection', exc_info=True)\n            raise plugin.PluginError('Unidentified error during connection to aria2 daemon', log)\n\n    def prepare_config(self, config):\n        config.setdefault('server', 'localhost')\n        config.setdefault('port', 6800)\n        config.setdefault('username', '')\n        config.setdefault('password', '')\n        config.setdefault('secret', '')\n        config.setdefault('options', {})\n        return config\n\n    def on_task_output(self, task, config):\n        # don't add when learning\n        if task.options.learn:\n            return\n        config = self.prepare_config(config)\n        aria2 = self.aria2_connection(config['server'], config['port'],\n                                      config['username'], config['password'])\n        for entry in task.accepted:\n            if task.options.test:\n                log.verbose('Would add `%s` to aria2.', entry['title'])\n                continue\n            try:\n                self.add_entry(aria2, entry, config)\n            except socket_error as se:\n                entry.fail('Unable to reach Aria2: %s', se)\n            except xmlrpc.client.Fault as err:\n                log.critical('Fault code %s message %s', err.faultCode, err.faultString)\n                entry.fail('Aria2 communication Fault')\n            except Exception as e:\n                log.debug('Exception type %s', type(e), exc_info=True)\n                raise\n\n    def add_entry(self, aria2, entry, config):\n        \"\"\"\n        Add entry to Aria2\n        \"\"\"\n        options = config['options']\n        try:\n            options['dir'] = os.path.expanduser(entry.render(config['path']).rstrip('/'))\n        except RenderError as e:\n            entry.fail('failed to render \\'path\\': %s' % e)\n            return\n        secret = None\n        if config['secret']:\n            secret = 'token:%s' % config['secret']\n        # handle torrent files\n        if 'torrent' in entry:\n            if secret:\n                return aria2.addTorrent(secret, xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))\n            return aria2.addTorrent(xmlrpc.client.Binary(open(entry['file'], mode='rb').read()))\n        # handle everything else (except metalink -- which is unsupported)\n        # so magnets, https, http, ftp .. etc\n        if secret:\n            return aria2.addUri(secret, [entry['url']], options)\n        return aria2.addUri([entry['url']], options)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(OutputAria2, 'aria2', api_ver=2)\n", "path": "flexget/plugins/clients/aria2.py"}], "after_files": [{"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\nimport os\nimport time\nimport logging\n\nfrom flexget import plugin\nfrom flexget.event import event\nfrom flexget.utils.tools import parse_timedelta\nfrom flexget.utils.pathscrub import pathscrub\n\nlog = logging.getLogger('convert_magnet')\n\n\nclass ConvertMagnet(object):\n    \"\"\"Convert magnet only entries to a torrent file\"\"\"\n\n    schema = {\n        \"oneOf\": [\n            # Allow convert_magnet: no form to turn off plugin altogether\n            {\"type\": \"boolean\"},\n            {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"timeout\": {\"type\": \"string\", \"format\": \"interval\", \"default\": \"30 seconds\"},\n                },\n                \"additionalProperties\": False\n            }\n        ]\n    }\n\n    def magnet_to_torrent(self, magnet_uri, destination_folder, timeout):\n        import libtorrent\n        params = libtorrent.parse_magnet_uri(magnet_uri)\n        session = libtorrent.session()\n        lt_version = [int(v) for v in libtorrent.version.split('.')]\n        if lt_version > [0,16,13,0]:\n            # for some reason the info_hash needs to be bytes but it's a struct called sha1_hash\n            params['info_hash'] = params['info_hash'].to_bytes()\n        handle = libtorrent.add_magnet_uri(session, magnet_uri, params)\n        log.debug('Acquiring torrent metadata for magnet %s', magnet_uri)\n        timeout_value = timeout\n        while not handle.has_metadata():\n            time.sleep(0.1)\n            timeout_value -= 0.1\n            if timeout_value <= 0:\n                raise plugin.PluginError('Timed out after {} seconds trying to magnetize'.format(timeout))\n        log.debug('Metadata acquired')\n        torrent_info = handle.get_torrent_info()\n        torrent_file = libtorrent.create_torrent(torrent_info)\n        torrent_path = pathscrub(os.path.join(destination_folder, torrent_info.name() + \".torrent\"))\n        with open(torrent_path, \"wb\") as f:\n            f.write(libtorrent.bencode(torrent_file.generate()))\n        log.debug('Torrent file wrote to %s', torrent_path)\n        return torrent_path\n\n    def prepare_config(self, config):\n        if not isinstance(config, dict):\n            config = {}\n        config.setdefault('timeout', '30 seconds')\n        return config\n\n    @plugin.priority(255)\n    def on_task_start(self, task, config):\n        if config is False:\n            return\n        try:\n            import libtorrent  # noqa\n        except ImportError:\n            raise plugin.DependencyError('convert_magnet', 'libtorrent', 'libtorrent package required', log)\n\n    @plugin.priority(130)\n    def on_task_download(self, task, config):\n        if config is False:\n            return\n        config = self.prepare_config(config)\n        # Create the conversion target directory\n        converted_path = os.path.join(task.manager.config_base, 'converted')\n\n        timeout = parse_timedelta(config['timeout']).total_seconds()\n\n        if not os.path.isdir(converted_path):\n            os.mkdir(converted_path)\n\n        for entry in task.accepted:\n            if entry['url'].startswith('magnet:'):\n                entry.setdefault('urls', [entry['url']])\n                try:\n                    log.info('Converting entry {} magnet URI to a torrent file'.format(entry['title']))\n                    torrent_file = self.magnet_to_torrent(entry['url'], converted_path, timeout)\n                except (plugin.PluginError, TypeError) as e:\n                    log.error('Unable to convert Magnet URI for entry %s: %s', entry['title'], e)\n                    continue\n                # Windows paths need an extra / prepended to them for url\n                if not torrent_file.startswith('/'):\n                    torrent_file = '/' + torrent_file\n                entry['url'] = torrent_file\n                entry['file'] = torrent_file\n                # make sure it's first in the list because of how download plugin works\n                entry['urls'].insert(0, 'file://{}'.format(torrent_file))\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(ConvertMagnet, 'convert_magnet', api_ver=2)\n", "path": "flexget/plugins/modify/convert_magnet.py"}, {"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\n\nimport logging\nimport os\nimport xmlrpc.client\nfrom socket import error as socket_error\n\nfrom flexget import plugin\nfrom flexget.event import event\nfrom flexget.utils.template import RenderError\n\nlog = logging.getLogger('aria2')\n\n\nclass OutputAria2(object):\n    \"\"\"\n    Simple Aria2 output\n\n    Example::\n\n        aria2:\n          path: ~/downloads/\n\n    \"\"\"\n\n    schema = {\n        'type': 'object',\n        'properties': {\n            'server': {'type': 'string', 'default': 'localhost'},\n            'port': {'type': 'integer', 'default': 6800},\n            'secret': {'type': 'string', 'default': ''},\n            'username': {'type': 'string', 'default': ''}, # NOTE: To be deprecated by aria2\n            'password': {'type': 'string', 'default': ''},\n            'path': {'type': 'string'},\n            'options': {\n                'type': 'object',\n                'additionalProperties': {'oneOf': [{'type': 'string'}, {'type': 'integer'}]}\n            }\n\n        },\n        'required': ['path'],\n        'additionalProperties': False\n    }\n\n    def aria2_connection(self, server, port, username=None, password=None):\n        if username and password:\n            userpass = '%s:%s@' % (username, password)\n        else:\n            userpass = ''\n        url = 'http://%s%s:%s/rpc' % (userpass, server, port)\n        log.debug('aria2 url: %s' % url)\n        log.info('Connecting to daemon at %s', url)\n        try:\n            return xmlrpc.client.ServerProxy(url).aria2\n        except xmlrpc.client.ProtocolError as err:\n            raise plugin.PluginError('Could not connect to aria2 at %s. Protocol error %s: %s'\n                              % (url, err.errcode, err.errmsg), log)\n        except xmlrpc.client.Fault as err:\n            raise plugin.PluginError('XML-RPC fault: Unable to connect to aria2 daemon at %s: %s'\n                              % (url, err.faultString), log)\n        except socket_error as e:\n            raise plugin.PluginError('Socket connection issue with aria2 daemon at %s: %s' % (url, e), log)\n        except:\n            log.debug('Unexpected error during aria2 connection', exc_info=True)\n            raise plugin.PluginError('Unidentified error during connection to aria2 daemon', log)\n\n    def prepare_config(self, config):\n        config.setdefault('server', 'localhost')\n        config.setdefault('port', 6800)\n        config.setdefault('username', '')\n        config.setdefault('password', '')\n        config.setdefault('secret', '')\n        config.setdefault('options', {})\n        return config\n\n    def on_task_output(self, task, config):\n        # don't add when learning\n        if task.options.learn:\n            return\n        config = self.prepare_config(config)\n        aria2 = self.aria2_connection(config['server'], config['port'],\n                                      config['username'], config['password'])\n        for entry in task.accepted:\n            if task.options.test:\n                log.verbose('Would add `%s` to aria2.', entry['title'])\n                continue\n            try:\n                self.add_entry(aria2, entry, config)\n            except socket_error as se:\n                entry.fail('Unable to reach Aria2: %s', se)\n            except xmlrpc.client.Fault as err:\n                log.critical('Fault code %s message %s', err.faultCode, err.faultString)\n                entry.fail('Aria2 communication Fault')\n            except Exception as e:\n                log.debug('Exception type %s', type(e), exc_info=True)\n                raise\n\n    def add_entry(self, aria2, entry, config):\n        \"\"\"\n        Add entry to Aria2\n        \"\"\"\n        options = config['options']\n        try:\n            options['dir'] = os.path.expanduser(entry.render(config['path']).rstrip('/'))\n        except RenderError as e:\n            entry.fail('failed to render \\'path\\': %s' % e)\n            return\n        secret = None\n        if config['secret']:\n            secret = 'token:%s' % config['secret']\n        # handle torrent files\n        if 'torrent' in entry:\n            if 'file' in entry:\n                torrent_file = entry['file']\n            elif 'location' in entry:\n                # in case download plugin moved the file elsewhere\n                torrent_file = entry['location']\n            else:\n                entry.fail('Cannot find torrent file')\n                return\n            if secret:\n                return aria2.addTorrent(secret, xmlrpc.client.Binary(open(torrent_file, mode='rb').read()), [], options)\n            return aria2.addTorrent(xmlrpc.client.Binary(open(torrent_file, mode='rb').read()), [], options)\n        # handle everything else (except metalink -- which is unsupported)\n        # so magnets, https, http, ftp .. etc\n        if secret:\n            return aria2.addUri(secret, [entry['url']], options)\n        return aria2.addUri([entry['url']], options)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(OutputAria2, 'aria2', api_ver=2)\n", "path": "flexget/plugins/clients/aria2.py"}]}