Torrent Virtual FileSystem for Midnight Commander.
authorOleg Broytman <phd@phdru.name>
Thu, 11 Nov 2010 01:12:44 +0000 (01:12 +0000)
committerOleg Broytman <phd@phdru.name>
Thu, 11 Nov 2010 01:12:44 +0000 (01:12 +0000)
git-svn-id: file:///home/phd/archive/SVN/mc-extfs/trunk@41 1a6e6372-1aea-0310-bd00-dc960550e1df

torrent [new file with mode: 0755]
torrent-ANNOUNCE [new file with mode: 0644]

diff --git a/torrent b/torrent
new file mode 100755 (executable)
index 0000000..a845856
--- /dev/null
+++ b/torrent
@@ -0,0 +1,226 @@
+#! /usr/bin/env python
+
+"""Torrent Virtual FileSystem for Midnight Commander
+
+The script requires Midnight Commander 3.1+
+(http://www.midnight-commander.org/), Python 2.4+ (http://www.python.org/),
+module eff_bdecode.py (http://effbot.org/zone/bencode.htm).
+
+Put the script in the /usr/[local/][lib|share]/mc/extfs/, and add a line
+"torrent" to the /usr/[local/][lib|share]/mc/extfs/extfs.ini. Make the script
+executable.
+
+Run this "cd" command in the Midnight Commander (in the "bindings" file the
+command is "%cd"): cd file#torrent, where "file" is the name of your torrent
+metafile. The VFS lists all files and directories from the torrent metafile;
+all files appear empty, of course, but the sizes are shown.
+
+Along with the files/directories in the torrent metafile the VFS also presents
+meta information - in the form of files in .META directory. The size and
+contents of these files are taken from the corresponding fields in the torrent
+metafile. The VFS doesn't check if the torrent contains .META file or directory
+(quite unlikely).
+
+Date/time for all files is set at midnight of the 1st January of the current
+year.
+
+"""
+
+__version__ = "1.0.0"
+__revision__ = "$Id$"
+__date__ = "$Date$"
+__author__ = "Oleg Broytman <phd@phd.pp.ru>"
+__copyright__ = "Copyright (C) 2010 PhiloSoft Design"
+__license__ = "GPL"
+
+import locale, sys, os
+from tempfile import _candidate_tempdir_list
+from eff_bdecode import decode
+
+import logging
+logger = logging.getLogger('torrent-mcextfs')
+log_err_handler = logging.StreamHandler(sys.stderr)
+logger.addHandler(log_err_handler)
+logger.setLevel(logging.INFO)
+
+if len(sys.argv) < 3:
+    logger.critical("""\
+Torrent Virtual FileSystem for Midnight Commander version %s
+Author: %s
+%s
+
+This is not a program. Put the script in /usr/[local/][lib|share]/mc/extfs.
+For more information read the source!""",
+   __version__, __author__, __copyright__
+)
+    sys.exit(1)
+
+
+tempdirlist = _candidate_tempdir_list()
+tempdirlist.insert(0, os.path.abspath(os.path.dirname(sys.argv[2])))
+
+found = False
+for tempdir in tempdirlist:
+    try:
+        logfile_name = os.path.join(tempdir, 'torrent-mcextfs.log')
+        logfile = open(logfile_name, 'w')
+    except IOError:
+        pass
+    else:
+        found = True
+        logfile.close()
+        break
+
+if not found:
+    logger.critical("Cannot initialize error log file in directories %s" % str(tempdirlist))
+    sys.exit(1)
+
+logger.removeHandler(log_err_handler)
+logger.addHandler(logging.FileHandler(logfile_name))
+
+locale.setlocale(locale.LC_ALL, '')
+charset = locale.getpreferredencoding()
+
+
+def mctorrent_list():
+    """List the entire VFS"""
+
+    if 'info' not in torrent:
+        torrent_error('Info absent')
+
+    info = torrent['info']
+    if 'name' not in info:
+        torrent_error('Unknown name')
+
+    name = info['name']
+    if 'files' in info:
+        files = info['files']
+        paths = []
+        for file in files:
+            if 'path' not in file:
+                torrent_error('Unknown path')
+            if 'length' not in file:
+                torrent_error('Unknown length')
+            path = file['path']
+            length = file['length']
+            paths.append(('/'.join([name] + path), length))
+    else: # One-file torrent
+        if 'length' not in info:
+            torrent_error('Unknown length')
+        length = info['length']
+        paths = [(name, length)]
+
+    meta = []
+    for name in 'comment', 'encoding', 'creation date', 'announce-list', \
+            'created by', 'announce':
+        if name in torrent:
+            if name == 'creation date':
+                data = decode_datetime(torrent[name])
+            elif name == 'announce-list':
+                data = decode_list(torrent[name])
+            else:
+                data = torrent[name]
+            meta.append(('.META/' + name, len(data)))
+
+    if 'private' in info:
+        meta.append(('.META/private', 1))
+
+    for name, size in paths + meta:
+        print "-r--r--r-- 1 user group %d Jan 1 00:00 %s" % (size, name)
+
+
+def mctorrent_copyout():
+    """Extract a file from the VFS"""
+
+    torrent_filename = sys.argv[3]
+    real_filename = sys.argv[4]
+    data = None
+
+    for name in 'comment', 'encoding', 'creation date', 'announce-list', \
+            'created by', 'announce':
+        if torrent_filename == '.META/' + name:
+            if name in torrent:
+                if name == 'creation date':
+                    data = decode_datetime(torrent[name])
+                elif name == 'announce-list':
+                    data = decode_list(torrent[name])
+                else:
+                    data = str(torrent[name])
+            else:
+                torrent_error('Unknown ' + name)
+            break
+
+    if torrent_filename == '.META/private':
+        if 'info' not in torrent:
+            torrent_error('Info absent')
+        info = torrent['info']
+        if 'private' not in info:
+            torrent_error('Info absent')
+        data = str(info['private'])
+
+    if not torrent_filename.startswith('.META/'):
+        data = ''
+
+    if data is None:
+        torrent_error('Unknown file name')
+    else:
+        outfile = open(real_filename, 'w')
+        outfile.write(data)
+        outfile.close()
+
+
+def mctorrent_copyin():
+    """Put a file to the VFS"""
+    sys.exit("Torrent VFS doesn't support adding files")
+
+def mctorrent_rm():
+    """Remove a file from the VFS"""
+    sys.exit("Torrent VFS doesn't support removing files/directories")
+
+mctorrent_rmdir = mctorrent_rm
+
+def mctorrent_mkdir():
+    """Create a directory in the VFS"""
+    sys.exit("Torrent VFS doesn't support creating directories")
+
+
+def torrent_error(error_str):
+    logger.critical("Error parsing the torrent metafile: %s", error_str)
+    sys.exit(1)
+
+def decode_torrent():
+    try:
+        torrent_file = open(sys.argv[2], 'r')
+        data = torrent_file.read()
+        torrent_file.close()
+        return decode(data)
+    except IOError, error_str:
+        torrent_error(error_str)
+
+
+def decode_datetime(dt):
+    from time import localtime, asctime
+    the_time = float(dt)
+    l_now = localtime(the_time)
+    return asctime(l_now)
+
+def decode_list(announce):
+    return '\n'.join(l[0] for l in announce)
+
+
+command = sys.argv[1]
+procname = "mctorrent_" + command
+
+g = globals()
+if not g.has_key(procname):
+    logger.critical("Unknown command %s", command)
+    sys.exit(1)
+
+torrent = decode_torrent()
+
+try:
+    g[procname]()
+except SystemExit:
+    raise
+except:
+    logger.exception("Error during run")
diff --git a/torrent-ANNOUNCE b/torrent-ANNOUNCE
new file mode 100644 (file)
index 0000000..0182ec3
--- /dev/null
@@ -0,0 +1,27 @@
+Torrent Virtual FileSystem for Midnight Commander
+
+
+WHAT IS IT
+   View files, directories and meta information from a torrent metafile in
+Midnight Commander.
+
+
+WHAT'S NEW in version 1.0.0 (2010-11-11)
+   Initial release.
+
+
+WHERE TO GET
+   Master site: http://phd.pp.ru/Software/mc/
+
+   Mirrors:     http://phd.by.ru/Software/mc/
+           http://phd.webhost.ru/Software/mc/
+
+
+AUTHOR
+   Oleg Broytman <phd@phd.pp.ru>
+
+COPYRIGHT
+   Copyright (C) 2010 PhiloSoft Design
+
+LICENSE
+   GPL