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, naturally, read-only.
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 if 'piece length' in info:
129 meta.append(('.META/piece length', len(str(info['piece length']))))
131 for name, size in paths + meta:
132 print "-r--r--r-- 1 user group %d Jan 1 00:00 %s" % (size, name)
135 def mctorrent_copyout():
136 """Extract a file from the VFS"""
138 torrent_filename = sys.argv[3]
139 real_filename = sys.argv[4]
142 for name in 'comment', 'encoding', 'creation date', 'announce-list', \
143 'created by', 'announce':
144 if torrent_filename == '.META/' + name:
146 if name == 'creation date':
147 data = decode_datetime(torrent[name])
148 elif name == 'announce-list':
149 data = decode_list(torrent[name])
151 data = str(torrent[name])
153 torrent_error('Unknown ' + name)
156 if torrent_filename in ('.META/private', '.META/piece length'):
157 if 'info' not in torrent:
158 torrent_error('Info absent')
159 info = torrent['info']
160 if torrent_filename == '.META/private':
161 if 'private' not in info:
162 torrent_error('Info absent')
163 if torrent_filename == '.META/piece length':
164 if 'piece length' not in info:
165 torrent_error('Info absent')
166 data = str(info[torrent_filename[len('.META/'):]])
168 if not torrent_filename.startswith('.META/'):
172 torrent_error('Unknown file name')
174 outfile = open(real_filename, 'w')
179 def mctorrent_copyin():
180 """Put a file to the VFS"""
181 sys.exit("Torrent VFS doesn't support adding files")
184 """Remove a file from the VFS"""
185 sys.exit("Torrent VFS doesn't support removing files/directories")
187 mctorrent_rmdir = mctorrent_rm
189 def mctorrent_mkdir():
190 """Create a directory in the VFS"""
191 sys.exit("Torrent VFS doesn't support creating directories")
194 def torrent_error(error_str):
195 logger.critical("Error parsing the torrent metafile: %s", error_str)
198 def decode_torrent():
200 torrent_file = open(sys.argv[2], 'r')
201 data = torrent_file.read()
204 except IOError, error_str:
205 torrent_error(error_str)
208 def decode_datetime(dt):
209 from time import localtime, asctime
211 l_now = localtime(the_time)
212 return asctime(l_now)
214 def decode_list(announce):
215 return '\n'.join(l[0] for l in announce)
218 command = sys.argv[1]
219 procname = "mctorrent_" + command
222 if not g.has_key(procname):
223 logger.critical("Unknown command %s", command)
226 torrent = decode_torrent()
233 logger.exception("Error during run")