def _verify_download(self, file_name): try: bencodepy.decode_from_file(file_name) except bencodepy.DecodingError as e: logger.debug('Failed to validate torrent file: {0}'.format(str(e))) logger.debug('Result is not a valid torrent file') return False return True
def __init__(self, torrent_file, file_extract = None): ''' Initialise various variables for a torrent. torrent_file must be path to .torrent file Currently this handles only single file case. ''' if file_extract == None: self.file_extract = decode_from_file(torrent_file) else: self.file_extract = file_extract self.tracker = [] if b'announce-list' in self.file_extract: for i in self.file_extract[b'announce-list']: self.tracker.append(i[0].decode()) else: self.tracker = [self.file_extract[b'announce'].decode()] if b'encoding' in self.file_extract: self.encoding = self.file_extract[b'encoding'].decode() else: self.encoding = 'UTF-8' self.piece_len = self.file_extract[b'info'][b'piece length'] self.piece = self.file_extract[b'info'][b'pieces'] self.name = self.file_extract[b'info'][b'name'].decode() self.length = self.file_extract[b'info'][b'length'] self.print_file_info()
def make_magnet_from_file(file): metadata = bencodepy.decode_from_file(file) subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() return 'magnet:?' + 'xt=urn:btih:' + b32hash
def magnetCheck(stringPassed): if "magnet:?xt=" in stringPassed[:11]: addTorrent(stringPassed) elif os.path.isfile(stringPassed) and stringPassed.endswith('.torrent'): metadata = bencodepy.decode_from_file(stringPassed) subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() convertedMagnet = 'magnet:?'\ + 'xt=urn:btih:' + b32hash\ + '&dn=' + metadata[b'info'][b'name'].decode()\ + '&tr=' + metadata[b'announce'].decode()\ + '&xl=' + str(metadata[b'info'][b'piece length']) addTorrent(convertedMagnet) elif stringPassed.startswith('http') and stringPassed.endswith('.torrent'): addTorrent(stringPassed) elif stringPassed.startswith('http') and not stringPassed.endswith('.torrent'): fd, path = tempfile.mkstemp(suffix=".torrent") try: with os.fdopen(fd, 'wb') as tmp: tmp.write(s.get(stringPassed, allow_redirects=True).content) magnetCheck(path) finally: os.remove(path) else: console.print("Invalid input. Exiting...", style="red")
def total_size_files_torrent(file_name): try: parsed = bencodepy.decode_from_file(file_name) except bencodepy.exceptions.DecodingError as e: print("Error parsing {}: {}".format(file_name, e)) return 0 else: file_list = parsed.get(b'info').get(b'files') return sum(item[b'length'] for item in file_list)
def search_by_hash(self, torr_hash, *dst): """ Compare a torrent hash with a list of torrents and returns those who match """ if not isinstance(torr_hash, bytes): torr_hash = torr_hash.encode() for d in dst: d_hash = bencodepy.decode_from_file(d)[b"info"][b"pieces"] if torr_hash == d_hash: yield d
def from_file(cls, filename: str, **kwargs): dictionary = cast(OrderedDict, bencodepy.decode_from_file(filename)) download_info = DownloadInfo.from_dict(dictionary[b'info']) if b'announce-list' in dictionary: announce_list = [[url.decode() for url in tier] for tier in dictionary[b'announce-list']] else: announce_list = [[dictionary[b'announce'].decode()]] return cls(download_info, announce_list, **kwargs)
def from_file(cls, filename: str, **kwargs): dictionary = cast(OrderedDict, bencodepy.decode_from_file(filename)) download_info = DownloadInfo.from_dict(dictionary[b'info']) if b'announce-list' in dictionary: announce_list = [[url.decode() for url in tier] for tier in dictionary[b'announce-list']] else: announce_list = [[dictionary[b'announce'].decode()]] return cls(download_info, announce_list, **kwargs)
def make_magnet_from_file(file): metadata = bencodepy.decode_from_file(file) subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() return 'magnet:?'\ + 'xt=urn:btih:' + b32hash\ + '&dn=' + metadata[b'info'][b'name'].decode()\ + '&tr=' + metadata[b'announce'].decode()\ + '&xl=' + str(metadata[b'info'][b'length'])
def parse(path): """Parse the given torrent file and return `Torrent` object. """ logger.info('Started parsing .torrent file') res = bencodepy.decode_from_file(path) return Torrent(announce=res[b'announce'], announce_list=res.get(b'announce-list', []), comment=res.get(b'comment', ''), created_by=res.get(b'created by', ''), created_at=res.get(b'creation date'), url_list=res.get(b'url-list'), info=res.get(b'info'))
def make_magnet_from_torrent_file(file): metadata = bencodepy.decode_from_file(file) subj = metadata.get(b"info", {}) hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b16hash = base64.b16encode(digest).decode().lower() return ("magnet:?" + "xt=urn:btih:" + b16hash + "&dn=" + metadata.get(b"info", {}).get(b"name", b"").decode() + "&tr=" + metadata.get(b"announce", b"").decode() + "".join([ "&tr=" + tr.decode() for trlist in metadata.get(b"announce-list", []) for tr in trlist if tr.decode().strip() ]) + "&xl=" + str(metadata.get(b"info", {}).get(b"length")))
def main(): arg = ArgumentParser.ArgumentParser() arg.do_parsing() torrent_dict = decode_from_file(os.getcwd() + "\\" + arg.torrent_file_url) info_dict = torrent_dict[b"info"] piece_length = info_dict[b"piece length"] piece_count = int(len(info_dict[b"pieces"])/20) file_name = info_dict[b"name"] file_name = file_name.decode("utf-8") if b"files" in info_dict: print(info_dict[b"files"]) global chunk_number chunk_number = int(piece_length/chunk_size) if piece_length % chunk_size != 0: chunk_number += 1 global pieces_bitfield pieces_bitfield = [None] * piece_count global currently_used currently_used = [False] * piece_count dictionary_sha1 = helper.get_sha1(encode(info_dict)) bencoded_info_dict = encode(info_dict) info_hash = helper.get_sha1(bencoded_info_dict) peer_id = os.urandom(20) listen_port = 2710 file_length = info_dict[b"length"] payload = {"info_hash": info_hash, "peer_id": peer_id, "port": listen_port, "uploaded": 0, "downloaded": 0, "left": file_length} r = requests.get(torrent_dict[b"announce"], params=payload) response = decode(r.content) if b"failure reason" in response: return interval = response[b"interval"] peers = response[b"peers"] peers_list = [] peer_num = len(peers)/6 for elem in range(int(peer_num)): start_ind = 6 * elem peer_ip = socket.inet_ntoa(peers[start_ind:start_ind+4]) peer_port = struct.unpack("!H", peers[start_ind+4:start_ind+6])[0] peers_list.append((peer_ip, peer_port)) print(peers_list) for elem in peers_list: test_ip = elem[0] test_port = elem[1] cur_thread = Thread(target=do_for_each_peer, args=(dictionary_sha1, test_ip, test_port, piece_length, info_dict, peer_id, file_length, file_name)) # do_for_each_peer(dictionary_sha1, test_ip, test_port, piece_length, info_dict,peer_id) # print(cur_thread.name) cur_thread.start()
def generate_magnet_from_file(file) : meta_data = bencodepy.decode_from_file(file) meta_info = meta_data[b'info'] meta_announce = meta_data[b'announce'] hash_contents = bencodepy.encode(meta_info) digest = hashlib.sha1(hash_contents).digest() b32hash = base64.b32encode(digest).decode() return "magnet:?xt=urn:btih:{0}&dn={1}&tr={2}".format( b32hash, meta_info[b'name'].decode(), meta_announce.decode() )
def make_magnet_from_file(file): # Создание magnet ссылок из torrent файла try: metadata = bencodepy.decode_from_file(file) except: # print('Вы использовали доступное Вам количество торрент-файлов в сутки') return 'Вы использовали доступное Вам количество торрент-файлов в сутки' subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() return 'magnet:?'\ + 'xt=urn:btih:' + b32hash\ + '&dn=' + metadata[b'info'][b'name'].decode()\ + '&tr=' + metadata[b'announce'].decode()\
def have(self, *src_lst): """ Check if the torrent is already in a watch directory. param src_lst: torrents to scan """ hash_lst = { src: bencodepy.decode_from_file(src)[b"info"][b"pieces"] for src in src_lst if len(src) } if not hash_lst: return logger.debug("Searching if having the list %s…" % hash_lst.keys()) for src, t in self._search_multiple_hash(hash_lst, self.targets): yield (src, t)
def add_new_torrent_by_file(message): file_info = bot.get_file(message.document.file_id) downloaded_file = bot.download_file(file_info.file_path) torrent_file_name = "{}.torrent".format(time.strftime("%d%m%Y%H%M%S")) with open(torrent_file_name, "wb") as new_file: new_file.write(downloaded_file) metadata = bencodepy.decode_from_file(torrent_file_name) subj = metadata[b"info"] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() transmission = Transmission() add_result = transmission.add_torrent("magnet:?xt=urn:btih:" + b32hash) os.remove(torrent_file_name) return "Torrent was successfully added with ID #{0}".format(add_result)
def bt2magnet(f): metadata = bencodepy.decode_from_file(f) # print(metadata) subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() print('magnet:?' + 'xt=urn:btih:' + b32hash + '&dn=' + metadata[b'info'][b'name'].decode() + '&tr=' + metadata[b'announce'].decode() + '&xl=' + str(metadata[b'info'][b'piece length'])) return 'magnet:?'\ + 'xt=urn:btih:' + b32hash\ + '&dn=' + metadata[b'info'][b'name'].decode()\ + '&tr=' + metadata[b'announce'].decode()\ + '&xl=' + str(metadata[b'info'][b'piece length'])
def __init__(self, parameters): self.parameter_parser = ParameterParser(parameters) # self.torrent_file_dict = getcwd() + "/" + self.parameter_parser.get_torrent_file_path() self.torrent_file_dict = decode_from_file(self.parameter_parser.get_torrent_file_path()) self.tracker = "" self.backup_trackers = [] if b'announce-list' in self.torrent_file_dict: self.backup_trackers = self.torrent_file_dict[b'announce-list'] self.tracker = self.torrent_file_dict[b'announce'] # print(self.torrent_file_dict[b'info']) self.info_parser = InfoDictParser(self.torrent_file_dict[b'info']) if self.info_parser.is_single_file_info(): self.total_size = self.info_parser.get_file_size() print(self.info_parser.get_single_file_info()[b'name']) print(self.tracker.decode()) self.register_with_tracker()
def make_magnet_from_torrent_file(file): metadata = bencodepy.decode_from_file(file) subj = metadata.get(b'info', {}) hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() return 'magnet:?'\ + 'xt=urn:btih:' + b32hash\ + '&dn=' + metadata.get(b'info', {}).get(b'name', b'').decode()\ + '&tr=' + metadata.get(b'announce', b'').decode()\ + "".join([ "&tr=" + tr.decode() for trlist in metadata.get(b'announce-list', []) for tr in trlist if tr.decode().strip() ])\ + '&xl=' + str(metadata.get(b'info', {}).get(b'length'))
def __init__(self, path_to_torrent: str = "debian.torrent", path_to_save_dir: str = os.getcwd()): self.log_update_time = 6 self.path_to_torrent = path_to_torrent self.torrent_dict = bencodepy.decode_from_file(self.path_to_torrent) self.info_hash = calculate_hash(bencodepy.encode(self.torrent_dict[b'info'])) temp = self.torrent_dict[b'info'][b'pieces'] self.pieces_hashes = [temp[i:i + 20] for i in range(0, len(temp), 20)] self.pieces_cnt = len(self.pieces_hashes) self.piece_length = self.torrent_dict[b'info'][b'piece length'] self.peer_id = calculate_peer_id() self.file_name = self.torrent_dict[b'info'][b'name'].decode() self.full_result_filepath = path_to_save_dir + "/" + self.file_name self.received_pieces_mask = [0] * self.pieces_cnt self.full_length = self.calculate_full_length() self.downloaded_bytes = None self.connected_peers = [] self.log_lock = threading.Lock() self.pieces_lock = threading.Lock()
def magnetCheck(stringPassed): if "magnet:?xt=" in stringPassed[:11]: #print("YAY its a magnet link") addTorrent(stringPassed) else: if os.path.isfile(stringPassed) and stringPassed.endswith('.torrent'): metadata = bencodepy.decode_from_file(stringPassed) subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() convertedMagnet = 'magnet:?'\ + 'xt=urn:btih:' + b32hash\ + '&dn=' + metadata[b'info'][b'name'].decode()\ + '&tr=' + metadata[b'announce'].decode()\ + '&xl=' + str(metadata[b'info'][b'piece length']) # print(convertedMagnet) addTorrent(convertedMagnet)
def parse_torrent_file(filename): """ Decode Torrent file and sig out data that matters: trackers, and infohash """ try: logger.info('Parsing torrent file {0}'.format(filename)) data = b.decode_from_file(filename) except (b.DecodingError, IOError) as e: logger.critical('Unable to parse torrent file {0}: {1}'.format( filename, e)) raise trackers = [data[b'announce'].decode()] + flatten(data[b'announce-list']) trackers = set(trackers) infohash = sha1(b.encode(data[b'info'])).hexdigest() return trackers, infohash
def magnetCheck(stringPassed): if "magnet:?xt=" in stringPassed[:11]: addTorrent(stringPassed) elif os.path.isfile(stringPassed) and stringPassed.endswith('.torrent'): metadata = bencodepy.decode_from_file(stringPassed) subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() convertedMagnet = 'magnet:?'\ + 'xt=urn:btih:' + b32hash\ + '&dn=' + metadata[b'info'][b'name'].decode()\ + '&tr=' + metadata[b'announce'].decode()\ + '&xl=' + str(metadata[b'info'][b'piece length']) addTorrent(convertedMagnet) elif stringPassed.startswith('http') and stringPassed.endswith('.torrent'): addTorrent(stringPassed) else: print(f"{Fore.RED}Invalid input. Exiting...")
def __init__(self, filename): self.metainfo_file_path = (filename + ".torrent").encode('utf-8') self.decoded_metainfo = decode_from_file(self.metainfo_file_path) self.info_dict = self.decoded_metainfo[b'info'] self.info_hash = hashlib.sha1() for key in self.info_dict.keys(): self.info_hash.update(key) for value in self.info_dict.values(): self.info_hash.update(bytearray(value)) self.announce = self.decoded_metainfo[b'announce'].decode('utf-8') self.filename = filename self.piece_length = self.info_dict[b'piece length'] self.file_length = self.info_dict[b'length'] self.pieces = self.info_dict[b'pieces'] self.num_pieces = math.ceil(self.info_dict[b'length']/self.info_dict[b"piece length"])
def collect_torrents(torrent_dirs): print("Getting file/folder names from torrents...") torrent_files = set() target_names = set() for d in torrent_dirs: for x in os.scandir(d): if not x.is_file() or not x.name.endswith(".torrent"): continue try: path = os.path.abspath(os.path.join(os.getcwd(), x.path)) data = decode_from_file(path) name = data[b"info"][b"name"].decode("utf-8", errors="replace") except (OSError, DecodingError, KeyError) as e: print("Couldn't check '{}': {}".format(path, e)) else: torrent_files.add(path) target_names.add(name) return torrent_files, target_names
def filter(self, torrent): """ Apply filter and return the match as a boolean :param torrent: path of torrent file to apply the filters on """ def tracker_matches(f_tracker, tracker): regex = r"^.*://%s(:\d*|)(/.*|)$" exclude = f_tracker.startswith("!") if exclude: f_tracker = f_tracker[1:] return not re.match(regex % f_tracker, tracker) else: return re.match(regex % f_tracker, tracker) match = True if (self.filters.get("trackers", False) and len(self.filters["trackers"])): try: decoded_torrent = bencodepy.decode_from_file(torrent) tracker = decoded_torrent[b"announce"].decode() logger.debug("Tracker of %s: %s" % (torrent, tracker)) if isinstance(self.filters["trackers"], str): f_tracker = self.filters["trackers"] match = match and tracker_matches(f_tracker, tracker) else: matches = [] for f_tracker in self.filters["trackers"]: matches.append(tracker_matches(f_tracker, tracker)) match = match and any(matches) except Exception as e: logger.info("%s doesn't contain a announce field, pass" % torrent) logger.debug(e) pass logger.debug("%s matches %s" % (torrent, match or "no filter")) return match
async def get_magnet(self, location: str) -> str: """ Will take a file location or an internet location for a torrent file. The magnet URL for that torrent is then resolved and returned. If the location parameter is already detected to be a magnet URL, it will instantly return it. Parameters ---------- location: str A file location or web address. Returns ------- str The magnet URL for the torrent at the given location. """ if location.startswith("magnet:?"): return location elif location.endswith(".torrent"): async with self.session.get(location) as resp: torrent_bytes = await resp.read() metadata = bencodepy.decode(torrent_bytes) else: metadata = bencodepy.decode_from_file(location) subject = metadata[b'info'] hash_data = bencodepy.encode(subject) digest = hashlib.sha1(hash_data).digest() base32_hash = base64.b32encode(digest).decode() return "magnet:?"\ + f"xt=urn:btih:{base32_hash}"\ + f"&dn={metadata[b'info'][b'name'].decode()}"\ + f"&tr={metadata[b'announce'].decode()}"
def _search_multiple_hash(self, torrent_lst, dst_lst): """ Search in a list of hash which ones match with the destination list """ if len(torrent_lst) == 0: return for dst in dst_lst: dst = os.path.expanduser(dst) if os.path.isdir(dst): logger.debug("Scanning all torrents into %s" % dst) for t, h in self._search_multiple_hash( torrent_lst, glob.glob(os.path.join(dst, "*.torrent"))): yield t, h continue try: dst_hash = bencodepy.decode_from_file(dst)[b"info"][b"pieces"] for t, h in torrent_lst.items(): if dst_hash == h: logger.debug("Hash matches for %s", dst) yield t, dst except Exception as e: logger.error("Error when opening the torrent %s" % dst) logger.error(e)
def main(): client = Client('127.0.0.1', 9999, 'UR.mp3') #parse metainfo file metainfo_file_path = "UR.mp3.torrent".encode('utf-8') decoded_metainfo = decode_from_file(metainfo_file_path) info_dict = decoded_metainfo[b'info'] info_hash = hashlib.sha1() for key in info_dict.keys(): info_hash.update(key) print("Key: " + str(key) + '\n') for value in info_dict.values(): info_hash.update(bytearray(value)) print("val: " + str(value) + '\n') print(info_hash) #Contact tracker and get list of peers #initiate handshaking with peers #download/upload chunks according to peer wire protocol #maintain state information for each connection with remote peer #should include bidirectional status #use status info to determine whether a chunk should be downloaded or uploaded #rarest first with randomization #message flow #choke, unchoke, interested, not interested #have #bitfield #sent after handshaking before any other messages #client should drop connection if bitfield is wrong length #request #piece #cancel (can be ignored) #implement commands def print_metainfo(): print("IP/port : " + str(client.ip_addr) + "/" + str(client.port)) print("ID : " + "someplaceholderstuff") print("metainfo file: " + "UR.mp3.torrent") print("info hash : " + str(info_hash.hexdigest())) print("filename : " + "UR.mp3") print("piece length: " + str(info_dict[b"piece length"])) print("file size: " + str(info_dict[b"length"])) print("announce URL: " + str(decoded_metainfo[b"announce"])) print("pieces' hashes: ") num_pieces = math.ceil(info_dict[b"length"] / info_dict[b"piece length"]) print(num_pieces) print("other") # for i in range(0, num_pieces): # print(info_dict[b"pieces"][i:i+20+1].hexdigest()) while True: command = input() #metainfo if (command == "metainfo"): print_metainfo()
path_torrent_file = args.torrent_file verbose = args.verbose save_directory = args.directory logging_time = int(args.t) if args.t else 30 signal.signal(signal.SIGINT, signal_handler) if not os.path.exists(save_directory) or (not os.path.isdir(save_directory)): print("No such directory") exit() if save_directory == "/": save_directory = os.getcwd() my_ordred_dict = bencodepy.decode_from_file(path_torrent_file) dict_hash = utils.compute_hash(bencodepy.encode(my_ordred_dict[b'info'])) my_peer_id = utils.random_peer_id() hashes = my_ordred_dict[b'info'][b'pieces'] root_directory = "" files = [] file = () if b'files' in my_ordred_dict[b'info'].keys(): root_directory = str(my_ordred_dict[b'info'][b'name'], 'utf-8') if root_directory.endswith("/"): root_directory = root_directory[:-1] # if save_directory.endswith("/"): save_directory = save_directory[:-1] if not os.path.exists(save_directory + "/" + root_directory): os.mkdir(save_directory + "/" + root_directory)
def parse_from_file(self, file, base='16', size=0, seed=1, leech=1, surrogated_id=''): ''' This function, will parse the content of a *.torrent file, retrieving the fundamental values :param file: this value, represents the path to the *.torrent file :param base: this value, represents the base of hash you're gonna use to encode, by default 16 :return: this function, returns a magnet instace with the fundamental values from the *.torrent file :rtype: MagnetInstance ''' _hash = '' announce = '' display_name = '' announce_list = '' try: metadata0 = self.raw_parse_from_file(file) metadata = bencodepy.decode_from_file(file) # Read from the file subj = metadata[b'info'] # # Calculating hash try: hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest( ) # Calculating the magnet hash 16, based on the metadata[b'info] if base == '16': _hash = base64.b16encode(digest).decode().lower() else: _hash = base64.b32encode(digest).decode().lower() except Exception as err: self.logger.error(err) try: display_name = self._eval_display_name( metadata0) # Gather display_name from the file except MagnetBuilderTorrentKeyDisplayNameError as err: self.logger.warning(err.message) try: announce = self._eval_announce( metadata0) # Gather announce from the file except MagnetBuilderTorrentAnnounceKeyError as err: self.logger.warning(err.message) try: announce_list = self._eval_announce_list( metadata0) # Gather announce_list from the file except MagnetBuilderTorrentAnnounceListKeyError as err: self.logger.warning(err.message) try: size = self._eval_size( metadata0) # Gather announce_list from the file except MagnetBuilderTorrentSizeKeyError as err: self.logger.warning(err.message) if announce_list is '': announce_list = announce ch_filter = chinese_filter() display_name = ch_filter.sub('', str(display_name)) self.logger.debug0( '{0} Generated Uri from Torrent File: {1} with Hash [ {2} ]'. format(self.name, display_name, _hash)) self.logger.debug('* Announce List {0}'.format(announce_list)) print(_hash, str(display_name), announce_list, size, seed, leech, surrogated_id) return MagnetInstance(_hash, str(display_name), announce_list, size, seed, leech, surrogated_id) except Exception as err: return MagnetInstance
def get_data_from_torrent(arg): # https://github.com/eweast/BencodePy global torrent_data # try to parse and decode the torrent file... try: # assign file_path based on the command line arg/param file_path = arg # call the decode_from_file() function that's a member of the bencodepy class` btdata = bencodepy.decode_from_file(file_path) # store the fresh, bencodepy decoded data in the global scope global btdata_backup btdata_backup = btdata # XXX test print XXX # print("\n\n::::::btdata backup : \n\n", btdata_backup, "\n\n") # next, build the decoded dictionary through a series of iterative statements within the btdata OrderedDict object # the "builder" variable used for this we'll call decoded_dict decoded_dict = {} # for each of the key:value pairs in the OrderedDict, try to decode both the key and the value # finally, append the results to the builder dictionary : decoded_dict for x, y in btdata.items(): # decode the key x = x.decode('UTF-8') # try to decode the value associated with the key... try: y = y.decode('UTF-8') except AttributeError: # if we can't decode the value, just pass it for now pass decoded_dict[x] = y # decode the array elements that exist as the value for the 'url-list' key in the decoded_dict for x, member in enumerate(decoded_dict['url-list']): decoded_dict['url-list'][x] = decoded_dict['url-list'][x].decode( 'UTF-8') # decode the array elements that exist as the value for the 'announce-list' key in the decoded_dict # this has another layer of complexity compared to decoding the elements in the 'url-list', this is # because some of the elements of the decoded_dict['announce-list'] are arrays themselves, need a nested loop : for x, member in enumerate(decoded_dict['announce-list']): for y, member in enumerate(decoded_dict['announce-list'][x]): decoded_dict['announce-list'][x][y] = decoded_dict[ 'announce-list'][x][y].decode('UTF-8') # store freshly bencodepy decoded info-ordered-dictionary global btdata_info_backup btdata_info_backup = decoded_dict['info'] # decode the (sub)ordered-dictionary that exists as a value corresponding to the 'info' key inside the decoded_dict dictionary # access this (sub)ordered-dictionary with : decoded_dict['info'] # use the appendage_dict={} in order to temporarily store the sub-ordered-dictionary, this will be appended to the decoded_dict at the correct 'info' key after traversal appendage_dict = {} for x, y in decoded_dict['info'].items(): # decode the key x = x.decode('UTF-8') # try to decode the value associated with the key... try: # we don't want to decode the value at the pieces key... this is a byte string if x != 'pieces': y = y.decode('UTF-8') except AttributeError: # if we can't decode the value, just pass it for now pass # append the key:value pair to the dictionary appendage_dict[x] = y # append the appendage_dict to the 'info' key of the decoded_dict dictionary, the same place where it came encoded from decoded_dict['info'] = appendage_dict # XXX test print XXX # print(decoded_dict) # XXX test print XXX # Do what you need to do with the torrent data. # You'll probably want to set some globals, such as # total_length, piece_length, number of pieces (you'll) # need to calculate that) etc. You might want to give # file_array its initial value here as an array of # empty binary sequences (b'') that can later be appended # to. There may be other values you want to initialize here. # instantiate an object to have the TorrentData class type # assign all of the key:value pairs to correspond to the relevant bit_torrent data # note : the number of pieces is thus determined by 'ceil( total length / piece size )' torrent_data = TorrentData(\ decoded_dict['info']['name'],\ decoded_dict['info']['length'],\ decoded_dict['info']['length']/8,\ decoded_dict['info']['piece length'],\ decoded_dict['info']['piece length']/8,\ math.ceil(decoded_dict['info']['length']/decoded_dict['info']['piece length']),\ decoded_dict['announce']) # XXX test print XXX # print('total length : ', total_length) # print('piece length : ', piece_length) # print('piece length bytes : ', piece_length_bytes) # print('number of pieces :', no_of_pieces) # print('announce url :', announce_url) # print('output file name : ', output_filename) # print(decoded_dict['info']['pieces']) # print('type :', type(decoded_dict['info']['pieces'])) # type of # XXX test print XXX # reporting torrent : report_torrent(torrent_data) except: print( 'Failed to parse input. Usage: python btClient.py torrent_file"\ntorrent_file must be a .torrent file' ) sys.exit(2) return decoded_dict
def open_torrent_url(url): """Mount the specified torrent and open it in the file browser Keyword arguments: url -- url to download the torrent file, path of torrent in filesystem, or magnet url """ url_parsed = urlparse(url) # Magnet if url_parsed.scheme == 'magnet': print('MAGNET', url) query_params = parse_qs(url_parsed.query) magnet_params = {} if 'tr' in query_params: magnet_params['tr'] = query_params['tr'] if magnet_params: encoded_params = '&' + urlencode(magnet_params, doseq=True) else: encoded_params = '' # For each torrent in the magnet for param_name, param_data in query_params.items(): if param_name[:2] != 'xt': continue xt_data = param_data[0] btih = re.search(r'^urn:btih:([0-9a-fA-F]{40}|[2-7A-Z]{32})$', xt_data) if btih is not None: btih = btih.group(1) # Hex encoded if (len(btih) == 40): btih = btih.lower() # Base32 encoded else: btih = base64.b32decode(btih).hex() open_torrent_btih(btih, 'magnet:?xt=' + xt_data + encoded_params) return # Download torrent from URL if len(url_parsed.scheme): print('URL', url) torrent_file = os.path.join(config.torrent_dir, hashlib.md5(url.encode('utf-8')).hexdigest()+'.torrent') urllib.request.urlretrieve(url, torrent_file) url = torrent_file # Open torrent in file system if os.path.isfile(url): print('FILE', url) # Calculate bittorrent info hash metadata = bencodepy.decode_from_file(url) hashcontents = bencodepy.encode(metadata[b'info']) digest = hashlib.sha1(hashcontents).digest() btih = digest.hex() open_torrent_btih(btih, url) return print('Torrent URL is not supported')