diff --git a/Magnet2Torrent.py b/Magnet2Torrent.py
new file mode 100755
index 0000000..501e458
--- /dev/null
+++ b/Magnet2Torrent.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python3
+"""convert magnet link to torrent file.
+
+Created on Apr 19, 2012 @author: dan, Faless
+ GNU GENERAL PUBLIC LICENSE - Version 3
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+ http://www.gnu.org/licenses/gpl-3.0.txt
+
+"""
+
+import logging
+import os.path as pt
+import shutil
+import sys
+import tempfile
+from argparse import ArgumentParser
+from time import sleep
+try:
+ from urllib.parse import unquote_plus
+except ImportError:
+ from urllib import unquote_plus
+import libtorrent as lt
+
+
+class Magnet2Torrent(object):
+ """class for converter from magnet link to torrent."""
+
+ def __init__(self, magnet, output_name=None):
+ """init function.
+
+ check for validity of the input.
+
+ Raises:
+ ValueError: if input is not valid this error will be raise
+ """
+ if (output_name and not pt.isdir(output_name) and
+ not pt.isdir(pt.dirname(pt.abspath(output_name)))):
+ raise ValueError("Invalid output folder: " + pt.dirname(pt.abspath(output_name)))
+ self.output_name = output_name
+
+ self.tempdir = tempfile.mkdtemp()
+ self.ses = lt.session()
+
+ params = {
+ 'url': magnet,
+ 'save_path': self.tempdir,
+ 'storage_mode': lt.storage_mode_t(2),
+ 'paused': False,
+ 'auto_managed': True,
+ 'duplicate_is_error': False
+ }
+ self.handle = self.ses.add_torrent(params)
+
+ def run(self):
+ """run the converter.
+
+ using the class attribute initiated at init function.
+
+ Returns:
+ Filename of created torrent.
+
+ Raises:
+ KeyboardInterrupt: This error caused by user to stop this.
+ When downloading metadata from magnet link,
+ it requires an additional step before the error reraised again.
+ """
+ print("Downloading Metadata (this may take a while)")
+
+ # used to control "Maybe..." and "or the" msgs after sleep(1)
+ wait_time = 1
+ soft_limit = 120
+ while not self.handle.has_metadata():
+ try:
+ sleep(1)
+ if wait_time > soft_limit:
+ print("Downloading is taking a while, maybe there is an "
+ "issue with the magnet link or your network connection")
+ soft_limit += 30
+ wait_time += 1
+ except KeyboardInterrupt:
+ print("\nAborting...")
+ self.ses.pause()
+ print("Cleanup dir " + self.tempdir)
+ shutil.rmtree(self.tempdir)
+ raise
+ self.ses.pause()
+ print("Done")
+
+ torinfo = self.handle.get_torrent_info()
+ torfile = lt.create_torrent(torinfo)
+
+ output = pt.abspath(torinfo.name() + ".torrent")
+
+ if self.output_name:
+ if pt.isdir(self.output_name):
+ output = pt.abspath(pt.join(self.output_name,
+ torinfo.name() + ".torrent"))
+ elif pt.isdir(pt.dirname(pt.abspath(self.output_name))):
+ output = pt.abspath(self.output_name)
+ else:
+ output = pt.abspath(torinfo.name() + ".torrent")
+
+ print("Saving torrent file here : " + output + " ...")
+ with open(output, "wb") as outfile:
+ torcontent = lt.bencode(torfile.generate())
+ outfile.write(torcontent)
+
+ print("Saved! Cleaning up dir: " + self.tempdir)
+ self.ses.remove_torrent(self.handle)
+ shutil.rmtree(self.tempdir)
+
+ return output
+
+
+def open_default_app(filepath):
+ """open filepath with default application for each operating system."""
+ import os
+ import subprocess
+
+ if sys.platform.startswith('darwin'):
+ subprocess.call(('open', filepath))
+ elif os.name == 'nt':
+ os.startfile(filepath)
+ elif os.name == 'posix':
+ subprocess.call(('xdg-open', filepath))
+
+
+def parse_args(args):
+ """parse some commandline arguments"""
+ description = ("A command line tool that converts "
+ "magnet links into .torrent files")
+ parser = ArgumentParser(description=description)
+ parser.add_argument('-m', '--magnet', help='The magnet url', required=True)
+ parser.add_argument('-o', '--output', help='The output torrent file name')
+ parser.add_argument('--rewrite-file',
+ help='Rewrite torrent file if it already exists(default)',
+ dest='rewrite_file', action='store_true')
+ parser.add_argument('--no-rewrite-file',
+ help='Create a new filename if torrent exists.',
+ dest='rewrite_file', action='store_false')
+ parser.set_defaults(rewrite_file=True)
+ parser.add_argument('--skip-file', help='Skip file if it already exists.',
+ dest='skip_file', action='store_true', default=False)
+ parser.add_argument('--open-file', help='Open file after converting.',
+ dest='open_file', action='store_true', default=False)
+ return parser.parse_args(args)
+
+
+def main():
+ """main function."""
+ args = parse_args(sys.argv[1:])
+ output_name = args.output
+ magnet = args.magnet
+
+ # guess the name if output name is not given.
+ # in a magnet link it is between '&dn' and '&tr'
+ try:
+ if output_name is None:
+ output_name = magnet.split('&dn=')[1].split('&tr')[0]
+ output_name = unquote_plus(output_name)
+ output_name += '.torrent'
+ except IndexError:
+ logging.error('magnet: {}'.format(magnet))
+
+ # return if user wants to skip existing file.
+ if output_name is not None and pt.isfile(output_name) and args.skip_file:
+ print('File [{}] already exists.'.format(output_name))
+ # still open file if file already exists.
+ if args.open_file:
+ open_default_app(output_name)
+ return
+
+ # create fullname if file exists.
+ if output_name is not None and pt.isfile(output_name) and not args.rewrite_file:
+ new_output_name = output_name
+ counter = 1
+ while pt.isfile(new_output_name):
+ non_basename, non_ext = pt.splitext(new_output_name)
+ if counter - 1 != 0:
+ non_basename = non_basename.rsplit('_{}'.format(counter - 1), 1)[0]
+ non_basename += '_{}'.format(counter)
+ new_output_name = '{}{}'.format(non_basename, non_ext)
+ counter += 1
+ output_name = new_output_name
+
+ # encode magnet link if it's url decoded.
+ if magnet != unquote_plus(magnet):
+ magnet = unquote_plus(magnet)
+
+ conv = Magnet2Torrent(magnet, output_name)
+ conv.run()
+
+ if args.open_file:
+ open_default_app(output_name)
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/Magnet_To_Torrent2.py b/Magnet_To_Torrent2.py
deleted file mode 100755
index 67b04bf..0000000
--- a/Magnet_To_Torrent2.py
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/usr/bin/env python
-'''
-Created on Apr 19, 2012
-@author: dan, Faless
-
- GNU GENERAL PUBLIC LICENSE - Version 3
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
- http://www.gnu.org/licenses/gpl-3.0.txt
-
-'''
-
-import shutil
-import tempfile
-import os.path as pt
-import sys
-import libtorrent as lt
-from time import sleep
-from argparse import ArgumentParser
-
-
-def magnet2torrent(magnet, output_name=None):
- if output_name and \
- not pt.isdir(output_name) and \
- not pt.isdir(pt.dirname(pt.abspath(output_name))):
- print("Invalid output folder: " + pt.dirname(pt.abspath(output_name)))
- print("")
- sys.exit(0)
-
- tempdir = tempfile.mkdtemp()
- ses = lt.session()
- params = {
- 'save_path': tempdir,
- 'storage_mode': lt.storage_mode_t(2),
- 'paused': False,
- 'auto_managed': True,
- 'duplicate_is_error': True
- }
- handle = lt.add_magnet_uri(ses, magnet, params)
-
- print("Downloading Metadata (this may take a while)")
- while (not handle.has_metadata()):
- try:
- sleep(1)
- except KeyboardInterrupt:
- print("Aborting...")
- ses.pause()
- print("Cleanup dir " + tempdir)
- shutil.rmtree(tempdir)
- sys.exit(0)
- ses.pause()
- print("Done")
-
- torinfo = handle.get_torrent_info()
- torfile = lt.create_torrent(torinfo)
-
- output = pt.abspath(torinfo.name() + ".torrent")
-
- if output_name:
- if pt.isdir(output_name):
- output = pt.abspath(pt.join(
- output_name, torinfo.name() + ".torrent"))
- elif pt.isdir(pt.dirname(pt.abspath(output_name))):
- output = pt.abspath(output_name)
-
- print("Saving torrent file here : " + output + " ...")
- torcontent = lt.bencode(torfile.generate())
- f = open(output, "wb")
- f.write(lt.bencode(torfile.generate()))
- f.close()
- print("Saved! Cleaning up dir: " + tempdir)
- ses.remove_torrent(handle)
- shutil.rmtree(tempdir)
-
- return output
-
-def main():
- parser = ArgumentParser(description="A command line tool that converts magnet links in to .torrent files")
- parser.add_argument('-m','--magnet', help='The magnet url')
- parser.add_argument('-o','--output', help='The output torrent file name')
-
- #
- # This second parser is created to force the user to provide
- # the 'output' arg if they provide the 'magnet' arg.
- #
- # The current version of argparse does not have support
- # for conditionally required arguments. That is the reason
- # for creating the second parser
- #
- # Side note: one should look into forking argparse and adding this
- # feature.
- #
- conditionally_required_arg_parser = ArgumentParser(description="A command line tool that converts magnet links in to .torrent files")
- conditionally_required_arg_parser.add_argument('-m','--magnet', help='The magnet url')
- conditionally_required_arg_parser.add_argument('-o','--output', help='The output torrent file name', required=True)
-
- magnet = None
- output_name = None
-
- #
- # Attempting to retrieve args using the new method
- #
- args = vars(parser.parse_known_args()[0])
- if args['magnet'] is not None:
- magnet = args['magnet']
- argsHack = vars(conditionally_required_arg_parser.parse_known_args()[0])
- output_name = argsHack['output']
- if args['output'] is not None and output_name is None:
- output_name = args['output']
- if magnet is None:
- #
- # This is a special case.
- # This is when the user provides only the "output" args.
- # We're forcing him to provide the 'magnet' args in the new method
- #
- print ('usage: {0} [-h] [-m MAGNET] -o OUTPUT'.format(sys.argv[0]))
- print ('{0}: error: argument -m/--magnet is required'.format(sys.argv[0]))
- sys.exit()
- #
- # Defaulting to the old of doing things
- #
- if output_name is None and magnet is None:
- if len(sys.argv) >= 2:
- magnet = sys.argv[1]
- if len(sys.argv) >= 3:
- output_name = sys.argv[2]
-
- magnet2torrent(magnet, output_name)
-
-
-if __name__ == "__main__":
- main()
diff --git a/README.md b/README.md
index 41f1aa8..19439ed 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,43 @@
# Magnet2Torrent
-A command line tool that converts magnet links in to .torrent files.
-
-### This project is mostly abandoned. I will still merge most pull requests.
+A command line tool that converts magnet links into .torrent files.
## Requirements
-* python
-* python-libtorrent (libtorrent-rasterbar version 0.16 or later)
+* python2.7/3.5
+* python-libtorrent (libtorrent-rasterbar version 0.16 or later) for python 2.7 or
+ python3-libtorrent for python 3.5
+
+### Install libtorrent-python on Mac
+
+ brew install libtorrent-rasterbar --with-python
+
+### Install python-libtorrent on Ubuntu
+ sudo apt-get install python-libtorrent -y
+
+## Usage
+
+ usage: Magnet2Torrent.py [-h] -m MAGNET [-o OUTPUT] [--rewrite-file]
+ [--no-rewrite-file] [--skip-file] [--open-file]
+
+A command line tool that converts magnet links into .torrent files
+
+Optional arguments:
-## Install python-libtorrent on Ubuntu
-`sudo apt-get install python-libtorrent -y`
+ -h, --help Show this help message and exit.
+ -m MAGNET, --magnet MAGNET
+ The magnet url.
+ -o OUTPUT, --output OUTPUT
+ The output torrent file name.
+ --rewrite-file Rewrite torrent file if it already exists (default).
+ --no-rewrite-file Create a new filename if torrent exists.
+ --skip-file Skip file if it already exists.
+ --open-file Open file after converting.
-## Install python-libtorrent on macOS
-`brew install libtorrent-rasterbar --with-python`
+## Example usage
-## How to Use
-`python Magnet_To_Torrent2.py [torrent file]`
+ python MagnetToTorrent.py -m [torrent file]
-### Example
-`python Magnet_To_Torrent2.py -m "magnet:?xt=urn:btih:49fbd26322960d982da855c54e36df19ad3113b8&dn=ubuntu-12.04-desktop-i386.iso&tr=udp%3A%2F%2Ftracker.openbittorrent.com" -o ubunut12-04.iso`
+ python Magnet2Torrent.py -m "magnet:?xt=urn:btih:49fbd26322960d982da855c54e36df19ad3113b8&dn=ubuntu-12.04-desktop-i386.iso&tr=udp%3A%2F%2Ftracker.openbittorrent.com" -o ubunut12-04.iso
## Licenses
All code is licensed under the [GPL version 3](http://www.gnu.org/licenses/gpl.html)