def __init__(self, storage, config, hashes, piece_size, finished, statusfunc, flag, data_flunked, infohash, errorfunc, resumefile): self.numpieces = len(hashes) self.storage = storage self.config = config check_hashes = config['check_hashes'] self.hashes = hashes self.piece_size = piece_size self.data_flunked = data_flunked self.errorfunc = errorfunc self.total_length = storage.get_total_length() self.amount_left = self.total_length self.partial_mark = "BitTorrent - this part has not been "+\ "downloaded yet."+infohash+\ tobinary(config['download_slice_size']) if self.total_length <= piece_size * (self.numpieces - 1): raise BTFailure, _("bad data in responsefile - total too small") if self.total_length > piece_size * self.numpieces: raise BTFailure, _("bad data in responsefile - total too big") self.finished = finished self.numactive = array('H', [0] * self.numpieces) self.inactive_requests = [1] * self.numpieces self.amount_inactive = self.total_length self.endgame = False self.have = Bitfield(self.numpieces) self.waschecked = Bitfield(self.numpieces) if self.numpieces < 32768: typecode = 'h' else: typecode = 'l' self.places = array(typecode, [NO_PLACE] * self.numpieces) if not check_hashes: self.rplaces = array(typecode, range(self.numpieces)) fastresume = True else: self.rplaces = self._load_fastresume(resumefile, typecode) if self.rplaces is not None: fastresume = True else: self.rplaces = array(typecode, [UNALLOCATED] * self.numpieces) fastresume = False self.holepos = 0 self.stat_numfound = 0 self.stat_numflunked = 0 self.stat_numdownloaded = 0 self.stat_active = {} self.stat_new = {} self.stat_dirty = {} self.download_history = {} self.failed_pieces = {} if self.numpieces == 0: return targets = {} total = 0 if not fastresume: for i in xrange(self.numpieces): if self._waspre(i): self.rplaces[i] = ALLOCATED total += 1 else: targets[hashes[i]] = i if total and check_hashes: statusfunc(_("checking existing file"), 0) def markgot(piece, pos): if self.have[piece]: if piece != pos: return self.rplaces[self.places[pos]] = ALLOCATED self.places[pos] = self.rplaces[pos] = pos return self.places[piece] = pos self.rplaces[pos] = piece self.have[piece] = True self.amount_left -= self._piecelen(piece) self.amount_inactive -= self._piecelen(piece) self.inactive_requests[piece] = None if not fastresume: self.waschecked[piece] = True self.stat_numfound += 1 lastlen = self._piecelen(self.numpieces - 1) partials = {} for i in xrange(self.numpieces): if not self._waspre(i): if self.rplaces[i] != UNALLOCATED: raise BTFailure(_("--check_hashes 0 or fastresume info " "doesn't match file state (missing data)")) continue elif fastresume: t = self.rplaces[i] if t >= 0: markgot(t, i) continue if t == UNALLOCATED: raise BTFailure(_("Bad fastresume info (files contain more " "data)")) if t == ALLOCATED: continue if t!= FASTRESUME_PARTIAL: raise BTFailure(_("Bad fastresume info (illegal value)")) data = self.storage.read(self.piece_size * i, self._piecelen(i)) self._check_partial(i, partials, data) self.rplaces[i] = ALLOCATED else: data = self.storage.read(piece_size * i, self._piecelen(i)) sh = sha(buffer(data, 0, lastlen)) sp = sh.digest() sh.update(buffer(data, lastlen)) s = sh.digest() if s == hashes[i]: markgot(i, i) elif s in targets and self._piecelen(i) == self._piecelen(targets[s]): markgot(targets[s], i) elif not self.have[self.numpieces - 1] and sp == hashes[-1] and (i == self.numpieces - 1 or not self._waspre(self.numpieces - 1)): markgot(self.numpieces - 1, i) else: self._check_partial(i, partials, data) statusfunc(fractionDone = 1 - self.amount_left / self.total_length) if flag.isSet(): return self.amount_left_with_partials = self.amount_left for piece in partials: if self.places[piece] < 0: pos = partials[piece][0] self.places[piece] = pos self.rplaces[pos] = piece self._make_partial(piece, partials[piece][1]) for i in xrange(self.numpieces): if self.rplaces[i] != UNALLOCATED: self.storage.allocated(piece_size * i, self._piecelen(i)) if self.have[i]: self.storage.downloaded(piece_size * i, self._piecelen(i))
def make_meta_files(url, files, flag=Event(), progressfunc=dummy, filefunc=dummy, piece_len_pow2=None, target=None, comment=None, filesystem_encoding=None, use_tracker=True, data_dir=None): if len(files) > 1 and target: raise BTFailure( _("You can't specify the name of the .torrent file " "when generating multiple torrents at once")) if not filesystem_encoding: try: getattr(sys, 'getfilesystemencoding') except AttributeError: pass else: filesystem_encoding = sys.getfilesystemencoding() if not filesystem_encoding: filesystem_encoding = 'ascii' try: 'a1'.decode(filesystem_encoding) except: raise BTFailure( _('Filesystem encoding "%s" is not supported in this version') % filesystem_encoding) files.sort() ext = '.torrent' togen = [] for f in files: if not f.endswith(ext): togen.append(f) total = 0 for f in togen: total += calcsize(f) subtotal = [0] def callback(x): subtotal[0] += x progressfunc(subtotal[0] / total) for f in togen: if flag.isSet(): break t = os.path.split(f) if t[1] == '': f = t[0] filefunc(f) if use_tracker: make_meta_file(f, url, flag=flag, progress=callback, piece_len_exp=piece_len_pow2, target=target, comment=comment, encoding=filesystem_encoding) else: make_meta_file_dht(f, url, flag=flag, progress=callback, piece_len_exp=piece_len_pow2, target=target, comment=comment, encoding=filesystem_encoding, data_dir=data_dir)
# defaultargs.py is even more annoying. --Dave ddir = os.path.join( platform.get_dot_dir(), "launchmany-console" ) ddir = decode_from_filesystem(ddir) modify_default(defaults, 'data_dir', ddir) config, args = configfile.parse_configuration_and_args(defaults, uiname, sys.argv[1:], 0, 1) # returned from here config['save_in'] is /home/dave/Desktop/... if args: torrent_dir = args[0] config['torrent_dir'] = torrent_dir else: torrent_dir = config['torrent_dir'] torrent_dir,bad = encode_for_filesystem(torrent_dir) if bad: raise BTFailure(_("Warning: ")+config['torrent_dir']+ _(" is not a directory")) if not os.path.isdir(torrent_dir): raise BTFailure(_("Warning: ")+torrent_dir+ _(" is not a directory")) # the default behavior is to save_in files to the platform # get_save_dir. For launchmany, if no command-line argument # changed the save directory then use the torrent directory. #if config['save_in'] == platform.get_save_dir(): # config['save_in'] = config['torrent_dir'] if '--save_in' in sys.argv: print "Don't use --save_in for launchmany-console. Saving files from " \ "many torrents in the same directory can result in filename collisions." sys.exit(1) # The default 'save_in' is likely to be something like /home/myname/BitTorrent Downloads
t.working_path = encode_for_filesystem(t.working_path)[0] t.destination_path = t.working_path elif version == 3: up, down, working_path = line[41:-1].split(' ', 2) t.uptotal = t.uptotal_old = int(up) t.downtotal = t.downtotal_old = int(down) t.working_path = working_path.decode('string_escape') t.working_path = t.working_path.decode('utf-8') t.working_path = encode_for_filesystem(t.working_path)[0] t.destination_path = t.working_path elif version >= 4: up, down = line[41:-1].split(' ', 1) t.uptotal = t.uptotal_old = int(up) t.downtotal = t.downtotal_old = int(down) except ValueError: # unpack, int(), decode() raise BTFailure(_("Invalid state file (bad entry)")) torrent_config = self.config try: if version < 5: torrent_config = configfile.read_torrent_config( self.config, self.data_dir, infohash, lambda s : self.global_error(logging.ERROR, s)) else: torrent_config = self._read_torrent_config(infohash) t.update_config(torrent_config) except BTFailure, e: self.logger.error("Read torrent config failed", exc_info=sys.exc_info())
def __init__(self, *args): IPCSocketBase.__init__(self, *args) data_dir, bad = encode_for_filesystem(self.config['data_dir']) if bad: raise BTFailure(_("Invalid path encoding.")) self.socket_filename = os.path.join(data_dir, self.name)
def message(self, s): print "### "+s def exception(self, s): exceptions.append(s) self.message(_("SYSTEM ERROR - EXCEPTION GENERATED")) if __name__ == '__main__': uiname = 'launchmany-console' defaults = get_defaults(uiname) try: if len(sys.argv) < 2: printHelp(uiname, defaults) sys.exit(1) config, args = configfile.parse_configuration_and_args(defaults, uiname, sys.argv[1:], 0, 1) if args: config['torrent_dir'] = args[0] if not os.path.isdir(config['torrent_dir']): raise BTFailure(_("Warning: ")+args[0]+_(" is not a directory")) except BTFailure, e: print _("error: %s\nrun with no args for parameter explanations") % str(e) sys.exit(1) LaunchMany(config, HeadlessDisplayer(), 'launchmany-console') if exceptions: print _("\nEXCEPTION:") print exceptions[0]
if args: if config['responsefile']: raise BTFailure, 'must have responsefile as arg or ' \ 'parameter, not both' config['responsefile'] = args[0] try: if config['responsefile']: h = file(config['responsefile'], 'rb') metainfo = h.read() h.close() elif config['url']: h = urlopen(config['url']) metainfo = h.read() h.close() else: raise BTFailure('you need to specify a .torrent file') except IOError, e: raise BTFailure('Error reading .torrent file: ', str(e)) except BTFailure, e: print str(e) sys.exit(1) errlist = [] dl = DL(metainfo, config, errlist) curses_wrapper(dl.run) if errlist: print "These errors occurred during execution:" for error in errlist: print error