def read(self): with open(self.path, 'rb') as f: self.raw_file = bencoder.decode(f.read()) try: self.announce = self.raw_file[b'announce'] except Exception as e: logging.warning( f'In {self.__class__.__name__}: Announce URL not found', exc_info=e) try: self.announce_list = self.raw_file[b'announce-list'] except Exception as e: logging.warning( f'In {self.__class__.__name__}: Announce List not found', exc_info=e) try: self.info = self.raw_file[b'info'] except Exception as e: logging.warning(f'In {self.__class__.__name__}: Info not found', exc_info=e) self.piece_length = self.info[b'piece length'] self.length = self.info[b'length']
def save_torrent(hex): torrent = codecs.decode(hex, 'hex') metadata = bencoder.decode(torrent) infohash = calculated_infohash = _infohash(metadata) if b'infohash' in metadata: infohash = metadata[b'infohash'].decode(encoding='ascii', errors='ignore').lower() if infohash != calculated_infohash: logger.warn("Infohash mismatch (%s != %s)", infohash, calculated_infohash) return name = metadata[b'info'][b'name'] try: name = name.decode(encoding='utf8', errors='ignore') except AttributeError: pass path = _torrent_path(infohash) if not os.path.isdir(os.path.dirname(path)): os.mkdir(os.path.dirname(path)) if os.path.isfile(path): logger.warn("Have already: %s", infohash) return with open(path, 'wb') as file: file.write(torrent) logger.info('%s.torrent <= [%s]', infohash, name)
def get_peers(self): self.url_params = { 'info_hash': self.info_sha1, 'peer_id': self.my_id, 'port': 6881, 'uploaded': 0, 'downloaded': 0, 'left': self.total_file_size, 'event': 'started', 'compact': 1 } response = requests.get(self.announce.decode('ascii'), params=self.url_params) self.response = bencoder.decode(response.content) peers = self.response[b'peers'] peer_list = [] port_list = [] for itr in range(0, len(peers), 6): out_tup = struct.unpack('>BBBBH', peers[itr:itr + 6]) peer_ip = str(out_tup[0]) + '.' + str(out_tup[1]) + '.' + str( out_tup[2]) + '.' + str(out_tup[3]) peer_list.append(peer_ip) port_list.append(out_tup[4]) self.peer_list = peer_list self.port_list = port_list
def summarize_torrent(torrent_obj, infohash): torrent = bencoder.decode(torrent_obj.read()) output = {} info = torrent[b'info'] output["infohash"] = infohash if b'name.utf-8' in info: output["name"] = info[b'name.utf-8'].decode() else: output["name"] = info[b'name'].decode() num_files = 1 size = 0 if b'length' in info: output["num_files"] = 1 output["size"] = info[b'length'] else: num_files = 0 files = [] for f in info[b'files']: num_files += 1 size += f[b'length'] files.append({"size": f[b'length'], "path": [f.decode(errors='ignore') for f in f[b'path']]}) output["size"] = size output["num_files"] = num_files output["files"] = files return output
def add_trcackers(filename): f = open('torrent/' + filename, "rb") # 读入文件 d = bencoder.decode(f.read()) #print(d[b'announce-list']) trackers = 'track.txt' # 保存trackers的文本文档,可编辑,可自行添加trackers track_list = [] with open(trackers) as f: for line in f: if len(line) > 1: l = line.rstrip() n = [] n.append(l) track_list.append(n) #print(000, len(track_list)) #print(len(track_list)) a = track_list + d[b'announce-list'] l2 = [] for i in a: if i not in l2: l2.append(i) print(len(l2)) d[b'announce-list'] = l2 with open('torrent/' + filename, "wb") as n: n.write(bencoder.encode(d)) # 写入文件 print('共', len(d[b'announce-list']), '个trackers.')
def announce_tracker(self): """ Gets the list of peers from the tracker :return: list of peers """ payload = self._create_payload() print(self.torrent.file_name) for url_tracker in self.torrent.announce_list: if url_tracker.startswith(b'udp'): url_tracker = b'http' + url_tracker print(url_tracker) try: raw_response = t.urlopen(url_tracker.decode() + "?" + payload).read() response = bencoder.decode(raw_response) if b'failure reason' in response.keys(): print('Torrent failed because of ' + response[b'failure reason'].decode()) else: # print(response) print(Torrent.bin_to_dec(response[b'peers'])) except urllib.error.URLError as e: print(e) print()
async def announce(self, server_port, event): request_parameters = { 'info_hash': self.download_info.info_hash, 'peer_id': self.peer_id, 'port': server_port, 'uploaded': self.statistics.total_uploaded, 'downloaded': self.statistics.total_downloaded, 'left': self.download_info.bytes_left, 'event': event, 'compact': 1, } if event != EventType.none: request_parameters['event'] = event.name if self._tracker_id is not None: request_parameters['trackerid'] = self._tracker_id url = self.announce_url + '?' + urlencode(request_parameters) with aiohttp.Timeout(HTTPTracker.REQUEST_TIMEOUT): with contextlib.closing(urlopen(url)) as connection: response = connection.read() response = bencoder.decode(response) if not response: if event == EventType.started: raise ValueError('Empty answer on start announcement') return response = cast(OrderedDict, response) self.handle_tracker_response(response)
def decode_file(file): ''' Reads and decodes binary torrent file. ''' full_path = os.path.abspath(file) with open(full_path, 'rb') as read_obj: decoded_file = bencoder.decode(read_obj.read()) return decoded_file
def get_info(self, file, **kwargs): dictionary = cast(OrderedDict, bencoder.decode(file)) download_info = DownloadInfo.get_download_info(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 self(download_info, announce_list, **kwargs)
def test_class(self): file = 'tests/test_torrent.torrent' torrent_info = TorrentInfo.get_info(file, download_dir='downloads') print(torrent_info.download_info) announce = list(['http://t.bitlove.org/announce']) announce_list = list() announce_list.append(announce) dictionary = bencoder.decode(file) download_info = DownloadInfo.get_download_info(dictionary[b'info']) self.assertEqual(torrent_info.announce_list, announce_list) self.assertEqual(torrent_info.download_info.info_hash, download_info.info_hash)
def feed_datagram(self, data, addr): """called when received a UDP datagram""" ip, port = addr try: msg = bencoder.decode(data) except: raise BadDHTMessageError('not properly bencoded') try: transaction_id = msg[b't'] message_type = msg[b'y'] except KeyError: raise BadDHTMessageError('bad dict') if message_type == b'q': # received a query query_type = msg.get(b'q') arg = msg.get(b'a') if not query_type or not arg: raise BadDHTMessageError('bad query') method = self._query_handler_method_map.get(query_type) if not method: raise BadDHTMessageError('unknown query type') response = method(arg, ip, port) if not response: return payload = { b't': transaction_id, b'y': b'r', b'r': response, } self.transport.sendto(bencoder.encode(payload), addr) remote_id = arg.get(b'id') if remote_id is not None: self._update_kbucket(decode_id(remote_id), ip, port) elif message_type == b'r': # received a response arg = msg.get(b'r') if not arg: raise BadDHTMessageError('bad response') future_key = (ip, port, transaction_id) future = self._query_future_map.get(future_key) if not future: raise BadDHTMessageError('response without query') del self._query_future_map[future_key] future.set_result(arg) remote_id = arg.get(b'id') if remote_id is not None: self._update_kbucket(decode_id(remote_id), ip, port) else: raise BadDHTMessageError('unknown message type')
async def _add_torrent_url(self, url, options): async with self.core.session.get(url) as response: body = await response.read() parsed_body = bencoder.decode(body) info_hash = hashlib.sha1(bencoder.encode( parsed_body[b'info'])).hexdigest() await self._client.call_remote( 'core.add_torrent_file', parsed_body[b'info'][b'name'] + b'.torrent', base64.b64encode(body), options, ) return info_hash
def read_file(file_path) -> MetaInfoFile: with io.open(file_path, 'rb') as torrent_file: decoded = bencoder.decode(torrent_file.read()) # announce and info must be present thus we don't check for their existence announce = decoded[b'announce'] info = decoded[b'info'] announce_list = None comment = None created_by = None creation_date = None if b'announce-list' in decoded: announce_list = decoded[b'announce-list'] if b'comment' in decoded: comment = decoded[b'comment'] if b'created by' in decoded: created_by = decoded[b'created by'] if b'creation date' in decoded: creation_date = decoded[b'creation date'] if b'files' in info: print("multi_file torrent") # todo move to debug mode only return MetaInfoFile( announce=announce, info_hash=TorrentFileReader.create_info_hash(info), torrent_file=TorrentFileReader. _create_multi_file_torrent_from_info(info), announce_list=announce_list, comment=comment, created_by=created_by, creation_date=creation_date, ) else: print("single_file torrent") # todo move to debug mode only return MetaInfoFile( announce=announce, info_hash=TorrentFileReader.create_info_hash(info), torrent_file=TorrentFileReader. _create_single_file_torrent_from_info(info), announce_list=announce_list, comment=comment, created_by=created_by, creation_date=creation_date, )
def parse_torrent_input(torrent, walk=True, recursive=False): # torrent is literal infohash if re.match(r'^[\da-fA-F]{40}$', torrent): return {'hash': torrent} # torrent is literal id if re.match(r'^\d+$', torrent): return {'id': torrent} # torrent is valid path if os.path.exists(torrent): if walk and os.path.isdir(torrent): for path in map(lambda x: os.path.join(torrent, x), os.listdir(torrent)): handle_input_torrent(path, recursive, recursive) return 'walked' # If file/dir name is info hash use that filename = os.path.split(torrent)[-1].split('.')[0] if re.match(r'^[\da-fA-F]{40}$', filename): return {'hash': filename} # If torrent file compute the info hash if not args.no_hash and os.path.isfile(torrent) and os.path.split( torrent)[-1].endswith('.torrent'): global encode, decode if 'encode' not in globals() or 'decode' not in globals(): try: from bencoder import encode, decode except: print( 'Found torrent file ' + torrent + ' but unable to load bencoder module to compute hash') print( 'Install bencoder (pip install bencoder) then try again or pass --no-hash to not compute the hash' ) if args.ignore_invalid: return None else: sys.exit(EXIT_CODES['input-error']) with open(torrent, 'rb') as torrent: try: decoded = decode(torrent.read()) info_hash = sha1(encode(decoded[b'info'])).hexdigest() except: return None return {'hash': info_hash} # torrent is a URL url_match = re.match(r'.*torrentid=(\d+).*', torrent) if not url_match or url_match.lastindex < 1: return None return {'id': url_match[1]}
async def request_peers(self): async with aiohttp.ClientSession() as session: resp = await session.get(self.tracker_url, params=self._get_request_params()) resp_data = await resp.read() LOG.info('Tracker response: {}'.format(resp)) peers = None try: peers = bencoder.decode(resp_data) except AssertionError: LOG.error( 'Failed to decode Tracker response: {}'.format(resp_data)) LOG.error('Tracker request URL: {}'.format( str(resp.url).split('&'))) raise RuntimeError('Failed to get Peers from Tracker') return peers
def __init__(self, file_name): self.file_name = file_name self.peerID = self.construct_peer_id() self.downloaded = 0 self.uploaded = 0 self.compact = 1 # TODO: proper handling of port. From 6881-6889 check every port if it is open and pick the first one self.port = 6882 # self.event = 'started' if file_name.endswith('torrent'): file = open(file_name, 'rb') self.torrent_data = bencoder.decode(file.read()) self.info = self.torrent_data[b'info'] self.hash_info = hashlib.sha1(bencoder.encode(self.info)).digest() self.creation_date = self.torrent_data[b'creation date'] self.announce_list = list() if b'announce_list' in self.torrent_data.keys(): self.announce_list = self.torrent_data[b'announce-list'] elif b'httpseeds' in self.torrent_data.keys(): self.announce_list = self.torrent_data[b'httpseeds'] self.announce_list.append(self.torrent_data[b'announce']) if b'files' in self.info.keys(): self.files = self.info[b'files'] else: # In case we have only one file we change it to a similar format as multi file torrent self.files = list() file_data = dict() file_data[b'length'] = self.info[b'length'] file_data[b'path'] = list() file_data[b'path'].append(self.info[b'name']) self.files.append(file_data) self.total_length = self.get_total_length() elif file_name.startswith('magnet'): self.torrent_data = self.magnet_to_torrent(file_name) self.hash_info = self.torrent_data[b'info'][b'hash_info'] self.announce_list = self.torrent_data[b'announce-list'] self.announce_list.append(self.torrent_data[b'announce'])
def __init__(self, path_to_torrent, peer_id): # Set id self.peer_id = peer_id # Read torrent file with open(path_to_torrent, 'rb') as torrent_file: torrent_contents = torrent_file.read() # Decode torrent file self.metainfo = decode(torrent_contents) # Get info dictionary self.info_dict = self.metainfo[b'info'] # Create SHA1 hash of info dictionary hash_sha1 = hashlib.sha1() hash_sha1.update(encode(self.info_dict)) self.info_hash = hash_sha1.digest() # Get announce url self.announce_url = self.metainfo[b'announce'] # Get pieces and pieces length self.piece_length = self.info_dict[b'piece length'] self.pieces = self.info_dict[b'pieces'] # Get name of the torrent self.torrent_name = self.info_dict[b'name'] # Get the length of the torrent and determine if it's a multi file torrent if b"files" in self.info_dict.keys(): total_length = 0 for i in self.info_dict[b'files']: total_length += i[b'length'] self.torrent_length = total_length self.is_multi_files = True else: self.torrent_length = self.info_dict[b'length'] self.is_multi_files = False # get paths for each file if its a multi file torrent if self.is_multi_files: self.file_paths = [] for i in self.info_dict[b'files']: self.file_paths.append([i[b'path'], i[b'length']])
def __init__(self, file_name): # Text self._bencoded_text = read_binary_file(file_name) self._parsed_text = bencoder.decode(self._bencoded_text)[0] self._parsed_info_hash = self._parsed_text['info'] self.bencoded_info_hash = bencoder.encode(self._parsed_info_hash) # turn into readonly property # File information self.file_info_dict = self._get_file_info_dict() self.base_file_name = self._parsed_info_hash['name'] self.type = "single" if len(self.file_info_dict.keys()) == 1 else "multiple" # Length and piece information self.total_length = self._get_total_length() self.piece_length = self._parsed_info_hash['piece length'] self.num_pieces = int(len(self._parsed_info_hash['pieces']) / 20) self.request_blocks_per_piece = int(math.ceil( float(self.piece_length) / 2**14)) self.pieces_hash = self._parsed_info_hash['pieces']
def getinfo(self, filename): fp = open(filename, "rb") data = fp.read() #it is string #print data decode_data = bencoder.decode(data) #get a dictionary #print(decode_data) if 'announce' in decode_data and 'info' in decode_data: self.tracker = decode_data.get('announce') self.tracker_list = decode_data.get('announce-list') self.create = decode_data.get('created by') self.date = decode_data.get('creation date') self.source = decode_data.get('comment') info = decode_data.get('info') self.piece_size = info.get('piece length') self.pieces = info.get('pieces') else: #print("Invalid torrent file") pass if 'length' in info: self.directory = '' self.files = [(info.get('name'), info.get('length'))] self.size = info.get('length') self.name = info.get('name') else: files = [] self.directory = info.get('name') for d in decode_data['info']['files']: files.append((d['path'], d['length'])) self.size += d['length'] if self.size % self.piece_size != 0: extra = 1 # print 'extra 1' else: extra = 0 # print 'extra 2' self.no_of_pieces = self.size / self.piece_size + extra # print self.no_of_pieces sha1 = hashlib.sha1() sha1.update(bencoder.encode(info)) self.hash_info = sha1.digest()
def connect_httptracker(mytorrent, tracker): parameters = { 'info_hash': mytorrent.hash_info, 'peer_id': mytorrent.peer_id, 'uploaded': 0, 'downloaded': 0, 'event': "started", 'left': mytorrent.size, 'port': 6881, 'compact': 1 } try: response = requests.get(tracker, params=parameters, timeout=5) responses = bencoder.decode(response.content) peer_list = get_http_peer(responses['peers']) return peer_list except Exception as e: # print(e) return
def receive_response_forever(self): """ 循环接受 udp 数据 """ self.logger.info( "receive response forever {}:{}".format(self.bind_ip, self.bind_port) ) # 首先加入到 DHT 网络 self.bootstrap() while True: try: # 接受返回报文 data, address = self.udp.recvfrom(UDP_RECV_BUFFSIZE) # 使用 bdecode 解码返回数据 msg = bencoder.decode(data) # 处理返回信息 self.on_message(msg, address) time.sleep(SLEEP_TIME) except Exception as e: self.logger.warning(e)
def __init__(self, file_name): # Text self._bencoded_text = message.read_binary_file(file_name) self._parsed_text = bencoder.decode(self._bencoded_text)[0] self._parsed_info_hash = self._parsed_text['info'] self.bencoded_info_hash = bencoder.encode( self._parsed_info_hash) # turn into readonly property # File information self.file_info_dict = self._get_file_info_dict() self.base_file_name = self._parsed_info_hash['name'] self.type = "single" if len( self.file_info_dict.keys()) == 1 else "multiple" # Length and piece information self.total_length = self._get_total_length() self.piece_length = self._parsed_info_hash['piece length'] self.num_pieces = int(len(self._parsed_info_hash['pieces']) / 20) self.request_blocks_per_piece = int( math.ceil(float(self.piece_length) / POLITE_REQUEST_SIZE)) self.pieces_hash = self._parsed_info_hash['pieces']
def parse_resume(self): path = r"%s\resume.dat" % self.var_dir.get() # Reading of the file for decoding if not os.path.exists(path): tk.messagebox.showerror('Error', 'Resume.dat文件不存在') return f = open(path, "rb") d = bencoder.decode(f.read()) for key in d: if key == b'.fileguard': pass elif key == b'rec': pass else: filename = key.decode() path = d[key][b'path'].decode() # if os.path.exists(path): # yes_or_no = '否' # else: # yes_or_no = '是' code = self.get_statu_code(filename, path) save_dir = '\\'.join(path.split('\\')[0:-1]) values = [filename, save_dir, code] self.tree.insert('', 0, values=values)
def test_decoding_string(self): expected = b'ifyoureadthisyoureadthis' result = decode(b'24:ifyoureadthisyoureadthis') self.assertEquals(expected, result)
def parse_file(self): data = None with open(self.torrent_file_path, 'rb') as f: data = f.read() return decode(data)
def test_decoding(self): expected = -42 result = decode(b'i-42e') self.assertEquals(expected, result)
def test_it_decodes_dicts_w_some_numbers(self): decoded_dict = bencoder.decode(self.dict_w_nums)[0] self.assertEqual(decoded_dict.keys(), ['bar', 'foo']) self.assertEqual(decoded_dict.values(), ['spam', 42])
def test_it_decodes_a_dict_with_list_values(self): decoded_dict = bencoder.decode(self.dict_w_lists)[0] self.assertEqual(decoded_dict.keys(), ['spam', 'eggs']) self.assertEqual(decoded_dict.values(), [['a', 'b'], ['a', 'b']])
def test_it_decodes_dicts_w_nums_and_lists(self): decoded_dict = bencoder.decode(self.dict_w_nums_and_lists)[0] self.assertEqual(decoded_dict.keys(), ['length', 'path']) self.assertEqual(decoded_dict.values(), [291, ['Distributed by Mininova.txt']])
import bencoder,json from pprint import pprint f = open("Gemini Man (2019) [WEBRip] [720p] [YTS.LT].torrent", "rb") d = bencoder.decode(f.read()) pprint(d)
def test_it_encodes_actual_bittorrent_files(self): decoded_dict = bencoder.decode(self.metainfo_file)[0] encoded_file = bencoder.encode(decoded_dict) self.assertEqual(self.metainfo_file, encoded_file)
def test_decoding_list(self): expected = [1, [2, [3]]] result = decode(b'li1eli2eli3eeee') self.assertEquals(expected, result)
def test_it_decodes_single_item_lists(self): decoded_list = bencoder.decode(self.b_single_word_list)[0] self.assertEqual(decoded_list, ['Distributed by Mininova.txt'])
def test_it_decodes_a_bigger_dict(self): decoded_dict = bencoder.decode(self.bigger_b_dict)[0] self.assertEqual(decoded_dict.keys(), ['publisher', 'publisher-webpage', 'publisher.location']) self.assertEqual(decoded_dict.values(), ['bob', 'www.example.com', 'home'])
def test_it_decodes_a_dict_of_strings(self): decoded_dict = bencoder.decode(self.little_b_dict)[0] self.assertEqual(decoded_dict.keys(), ['cow', 'spam']) self.assertEqual(decoded_dict.values(), ['moo', 'eggs'])
def test_it_decodes_nested_lists(self): decoded_list = bencoder.decode(self.b_nested_list)[0] self.assertEqual(decoded_list, [['spam', 'eggs'], ['spam', 'eggs']])
def test_decoding_dict(self): expected = {b'bar': b'spam', b'foo': 42, b'mess': [1, b'c']} result = decode(b'd3:bar4:spam3:fooi42e4:messli1e1:cee') self.assertEquals(expected, result)
def test_it_decodes_actual_bittorrent_files(self): decoded_dict = bencoder.decode(self.metainfo_file)[0] self.assertTrue(decoded_dict.keys())