3 """Torrent Virtual FileSystem for Midnight Commander
5 The script requires Midnight Commander 3.1+
6 (http://www.midnight-commander.org/), Python 2.4+ (http://www.python.org/),
7 module eff_bdecode.py (http://effbot.org/zone/bencode.htm).
9 Put the script in the /usr/[local/][lib|share]/mc/extfs/, and add a line
10 "torrent" to the /usr/[local/][lib|share]/mc/extfs/extfs.ini. Make the script
13 Run this "cd" command in the Midnight Commander (in the "bindings" file the
14 command is "%cd"): cd file#torrent, where "file" is the name of your torrent
15 metafile. The VFS lists all files and directories from the torrent metafile;
16 all files appear empty, of course, but the sizes are shown.
18 Along with the files/directories in the torrent metafile the VFS also presents
19 meta information - in the form of files in .META directory. The size and
20 contents of these files are taken from the corresponding fields in the torrent
21 metafile. The VFS doesn't check if the torrent contains .META file or directory
24 Date/time for all files is set at midnight of the 1st January of the current
25 year. The filesystem is read-only, of course.
32 __author__ = "Oleg Broytman <phd@phd.pp.ru>"
33 __copyright__ = "Copyright (C) 2010 PhiloSoft Design"
36 import locale, sys, os
37 from tempfile import _candidate_tempdir_list
38 from eff_bdecode import decode
41 logger = logging.getLogger('torrent-mcextfs')
42 log_err_handler = logging.StreamHandler(sys.stderr)
43 logger.addHandler(log_err_handler)
44 logger.setLevel(logging.INFO)
48 Torrent Virtual FileSystem for Midnight Commander version %s
52 This is not a program. Put the script in /usr/[local/][lib|share]/mc/extfs.
53 For more information read the source!""",
54 __version__, __author__, __copyright__
59 tempdirlist = _candidate_tempdir_list()
60 tempdirlist.insert(0, os.path.abspath(os.path.dirname(sys.argv[2])))
63 for tempdir in tempdirlist:
65 logfile_name = os.path.join(tempdir, 'torrent-mcextfs.log')
66 logfile = open(logfile_name, 'w')
75 logger.critical("Cannot initialize error log file in directories %s" % str(tempdirlist))
78 logger.removeHandler(log_err_handler)
79 logger.addHandler(logging.FileHandler(logfile_name))
81 locale.setlocale(locale.LC_ALL, '')
82 charset = locale.getpreferredencoding()
86 """List the entire VFS"""
88 if 'info' not in torrent:
89 torrent_error('Info absent')
91 info = torrent['info']
92 if 'name' not in info:
93 torrent_error('Unknown name')
100 if 'path' not in file:
101 torrent_error('Unknown path')
102 if 'length' not in file:
103 torrent_error('Unknown length')
105 length = file['length']
106 paths.append(('/'.join([name] + path), length))
107 else: # One-file torrent
108 if 'length' not in info:
109 torrent_error('Unknown length')
110 length = info['length']
111 paths = [(name, length)]
114 for name in 'comment', 'encoding', 'creation date', 'announce-list', \
115 'created by', 'announce':
117 if name == 'creation date':
118 data = decode_datetime(torrent[name])
119 elif name == 'announce-list':
120 data = decode_list(torrent[name])
123 meta.append(('.META/' + name, len(data)))
125 if 'private' in info:
126 meta.append(('.META/private', 1))
128 for name, size in paths + meta:
129 print "-r--r--r-- 1 user group %d Jan 1 00:00 %s" % (size, name)
132 def mctorrent_copyout():
133 """Extract a file from the VFS"""
135 torrent_filename = sys.argv[3]
136 real_filename = sys.argv[4]
139 for name in 'comment', 'encoding', 'creation date', 'announce-list', \
140 'created by', 'announce':
141 if torrent_filename == '.META/' + name:
143 if name == 'creation date':
144 data = decode_datetime(torrent[name])
145 elif name == 'announce-list':
146 data = decode_list(torrent[name])
148 data = str(torrent[name])
150 torrent_error('Unknown ' + name)
153 if torrent_filename == '.META/private':
154 if 'info' not in torrent:
155 torrent_error('Info absent')
156 info = torrent['info']
157 if 'private' not in info:
158 torrent_error('Info absent')
159 data = str(info['private'])
161 if not torrent_filename.startswith('.META/'):
165 torrent_error('Unknown file name')
167 outfile = open(real_filename, 'w')
172 def mctorrent_copyin():
173 """Put a file to the VFS"""
174 sys.exit("Torrent VFS doesn't support adding files")
177 """Remove a file from the VFS"""
178 sys.exit("Torrent VFS doesn't support removing files/directories")
180 mctorrent_rmdir = mctorrent_rm
182 def mctorrent_mkdir():
183 """Create a directory in the VFS"""
184 sys.exit("Torrent VFS doesn't support creating directories")
187 def torrent_error(error_str):
188 logger.critical("Error parsing the torrent metafile: %s", error_str)
191 def decode_torrent():
193 torrent_file = open(sys.argv[2], 'r')
194 data = torrent_file.read()
197 except IOError, error_str:
198 torrent_error(error_str)
201 def decode_datetime(dt):
202 from time import localtime, asctime
204 l_now = localtime(the_time)
205 return asctime(l_now)
207 def decode_list(announce):
208 return '\n'.join(l[0] for l in announce)
211 command = sys.argv[1]
212 procname = "mctorrent_" + command
215 if not g.has_key(procname):
216 logger.critical("Unknown command %s", command)
219 torrent = decode_torrent()
226 logger.exception("Error during run")