def get_torrent_file(torrent_id, return_file=False): rows = db2.query(Torrent_File).filter_by(torrent_id=torrent_id).all() if len(rows) != 0: if return_file is False: return else: return {"file": rows[0].file, "source": "Cached"} login() r = gazelle.get("{0}/torrents.php?action=download&id={1}".format( gazelle_url, torrent_id)) try: data = bencodepy.decode(r.content) except: print("Error decoding torrent %d" % torrent_id) exit() # data[b"announce"] = "" db2.merge(Torrent_File(torrent_id=torrent_id, file=bencodepy.encode(data))) db2.commit() #return {"file": None, "source": ""} if return_file is True: return {"file": bencodepy.encode(data), "source": "Fetched"}
def get_torrent_file(torrent_id, return_file=False): rows = db2.query(Torrent_File).filter_by(torrent_id=torrent_id).all() if len(rows) != 0: if return_file is False: return else: return {"file": rows[0].file, "source": "Cached"} login() r = gazelle.get("{0}/torrents.php?action=download&id={1}".format(gazelle_url, torrent_id)) try: data = bencodepy.decode(r.content) except: print("Error decoding torrent %d" % torrent_id) exit() # data[b"announce"] = "" db2.merge(Torrent_File(torrent_id=torrent_id, file=bencodepy.encode(data))) db2.commit() #return {"file": None, "source": ""} if return_file is True: return {"file": bencodepy.encode(data), "source": "Fetched"}
def test_torrent_decode_exceptions(): assert_raises(TorrentDecodeError, TorrentMetainfo, b'') assert_raises(TorrentDecodeError, TorrentMetainfo, b' ') sample = { 'announce': 'http://aaa.com', 'encoding': 'UTF-8', 'info': { 'name': 'bbb', 'length': 1, 'piece length': 1, 'pieces': b'.....................' } } TorrentMetainfo(bencodepy.encode(sample)) t = copy.deepcopy(sample) t['announce'] = '' assert_raises(TorrentDecodeError, TorrentMetainfo, bencodepy.encode(t)) t = copy.deepcopy(sample) del t['encoding'] TorrentMetainfo(bencodepy.encode(t)) t = copy.deepcopy(sample) t['encoding'] = 'zzz' assert_raises(TorrentDecodeError, TorrentMetainfo, bencodepy.encode(t))
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 spawn(url): torrent_url_components = urlparse(url) torrent_url_query = torrent_url_components.query match = re.search('ref=(.*)', torrent_url_query) if match is None: pass else: torrent_file = str(match.groups(0)[0]) + '.torrent' blob = download_torrent(url) dbx = dropbox.Dropbox( 'JUEnSrL_pnAAAAAAAAAADGNPxjjbk3nYLnatbTN8vvJ01JM8yQIhn-MI5DqW41nR') path = '/torrents/%s' % torrent_file dbx.files_upload(blob, path) link = dbx.sharing_create_shared_link_with_settings(path).url link = re.sub('dl=0', 'dl=1', link) try: metainfo = decode(blob) info = metainfo[b'info'] btih = hashlib.sha1(encode(info)).hexdigest() dn = metainfo[b'info'][b'name'] magnet = 'magnet:?xt=urn:btih:{btih}&dn={dn}'.format(btih=btih, dn=dn) torrent = {'status': 'OK', 'magnet': magnet, 'torrent': link} r.hmset(url, torrent) record_event({'type': 'aisex.newtorrent'}) except: torrent = {'status': 'ERROR', 'error': 'not a valid torrent file'} return torrent
def __init__(self, bencontent): """ Args: bencontent (bytes): bencoded torrent file contents """ if not bencontent: raise TorrentDecodeError('Empty torrent file') try: content = bencodepy.decode(bencontent) except bencodepy.DecodingError as e: # TODO: better msg raise TorrentDecodeError from e # TODO: validate shape using voluptuous or schema libraries # 'encoding' field defines character encoding for 'pieces' field. encoding = content.get(b'encoding') if encoding and encoding.decode('utf-8').lower() != 'utf-8': raise(TorrentDecodeError('Unsupported encoding: %s' % encoding)) self.announce = content[b'announce'].decode('utf-8') try: vol.Url()(self.announce) except vol.UrlInvalid as e: msg = 'Invalid announce URL: %s' % self.announce raise TorrentDecodeError(msg) from e # Ignore 'creation date', 'comment', 'created by', 'announce-list' info_dict = content[b'info'] self.info_hash = hashlib.sha1(bencodepy.encode(info_dict)).digest() self.info = self._decode_info_dict(info_dict)
def handle(request): logging.warning('Tracker connection received!') def create_sock(_peer, ip): server = yield from loop.create_server(lambda: TorrentProxy(_peer), ip, 0) port = server.sockets[0].getsockname()[1] return port ip = request.GET['ip'] if ip in request.GET else '127.0.0.1' port = yield from create_sock({ 'ip': ip, 'port': request.GET['port'] }, '0.0.0.0') path = request.path_qs.replace('port={}'.format(request.GET['port']), 'port={}'.format(port)) r = yield from aiohttp.get(sys.argv[1] + path) data = yield from r.read() yield from r.release() torrent = bencodepy.decode(data) proxied_peers = [] base_ip = ip2int('127.13.37.0') for index, peer in enumerate(decode_peers(torrent[b'peers'])): ip = int2ip(base_ip + index) port = yield from create_sock(peer, ip) proxied_peers.append({ 'ip': ip, 'port': port }) logging.info('Opened listener on {}'.format(port)) torrent[b'peers'] = encode_peers(proxied_peers) return web.Response(body=bencodepy.encode(torrent))
def _send(self, tid, data, addr, type): bytes_sent = self.sock.sendto(bencodepy.encode(data), addr) with self.lock: self.requests[tid] = Request(tid, time.time(), addr, type) return bytes_sent
def encode(self, message): """ bencodes a message :param message: a dictionary representing the message :return: the bencoded message """ return bencodepy.encode(message)
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 ext_handshake(s): """ Format: <length prefix><message ID><payload> """ msg_body = {"m": {"ut_metadata": 1}} msg = b"\x14\x00" + bencodepy.encode(msg_body) send_msg(s, msg)
def get_info_hash(torrent): info = bencodepy.encode(torrent[b'info']) hexdigest = hashlib.sha1(info).hexdigest() info_hash = bytes.fromhex(hexdigest) return info_hash
def generate_info_hash(self): sha1_hash = hashlib.sha1() # get the raw info value raw_info = self.torrent_file_raw_extract[b'info'] # update the sha1 hash value sha1_hash.update(bencodepy.encode(raw_info)) return sha1_hash.digest()
def send(data, port): if config['protocol'] == 'udp': local_sock = create_udp_socket(config['local_address'], port) else: local_sock = create_tcp_socket(config["local_address"], port) cookie = ''.join(random.choice(string.ascii_lowercase) for i in range(5)) data = bencodepy.encode(data).decode() message = str(cookie) + " " + str(data) logging.debug('message: ' + message) local_sock.sendto(message.encode('utf-8'), (config['rtpe_address'], int(config['rtpe_port']))) logging.debug('Command sent to rtpengine.') try: response = local_sock.recv(10240) logging.debug(f'Received from rtpengine: {str(response)}') except Exception: logging.error('After 10 seconds not received any response.') local_sock.close() return None try: data = response.decode() data = data.split(" ", 1) local_sock.close() return bc.decode(data[1]) except Exception as e: logging.info(e) logging.error(f'Received response is not a string. {str(response)}.') local_sock.close() return None
def do_GET(self): parsed_url = urllib.parse.urlparse(self.path) print(parsed_url) parsed_query = urllib.parse.parse_qs(parsed_url.query) error, client_id, info_hash = self.query_errors(parsed_query) if error: self.wfile.write(error) else: curr_peer = { "peer_id": client_id, "ip": self.client_address[0], "port": parsed_query["port"][0], } print(curr_peer) if do_handshake(curr_peer, info_hash): peers_list = [ peer for peer in retrv_peers() if peer != curr_peer ] res = bencodepy.encode({ "interval": INTERV_REQ, "peers": peers_list, "tracker_id": TRACKER_ID, }) self.wfile.write(res)
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 get_info_hash(btdata): # https://docs.python.org/3/library/hashlib.html # get the info directory, re-encode it into bencode, then encrypt it with # SHA1 using the hashlib library and generate a digest. # XXX test print XXX # print("\n\n::::::btdata backup : \n\n", btdata_backup, "\n\n") # print("\n\n::::::INFO btdata backup : \n\n", btdata_info_backup, "\n\n") # XXX test print XXX # print('re-encoded : ', btdata['info']) # first, encode info_dictionary in bencode before encrypting using sha1 encoded_info_dictionary = bencodepy.encode(btdata_info_backup) # XXX test print XXX # print('encoded info dictionary : ', encoded_info_dictionary) # encrypt the encoded_info_dictionary using sha1 & generate sha1 hash digest digest_builder = hashlib.sha1() digest_builder.update(encoded_info_dictionary) digest_builder = digest_builder.digest() # XXX test print XXX # print('digest builder : ', digest_builder,'\n\n') return digest_builder
def _download_torrent(self): res = self.session.get(self.dl_link) torrent = bytes() for chunk in res.iter_content(100000): torrent += chunk ggn_dir = os.path.join(TORRENT_DIR, 'ggn/') if not os.path.exists(ggn_dir): os.makedirs(ggn_dir) with open( os.path.join( ggn_dir, os.path.basename('[GGn]{}.torrent'.format( self.release_title))), 'wb') as t: t.write(torrent) torrent = bencodepy.decode(torrent) torrent[ b'announce'] = b'https://tracker.pterclub.com/announce?passkey=' + bytes( PTER_KEY, encoding='utf-8') torrent[b'info'][b'source'] = bytes('[pterclub.com] PT之友俱乐部', encoding='utf-8') del torrent[b'comment'] torrent = bencodepy.encode(torrent) with open( os.path.join( 'torrents', os.path.basename('[PTer]{}.torrent'.format( self.release_title))), 'wb') as t: t.write(torrent)
def test_encode_bytes(self): pass b = b"TheseAreSomeBytes" coded = bencodepy.encode(b) l = bytes(str(len(b)), 'utf-8') self.assertEqual(coded, l + b':' + b, msg='Failed to encode string from bytes.')
def __init__(self, torrent_path): self.torrent_path = torrent_path self.files = [] if self._validate_torrent_file(): self.meta_info = bencodepy.bread(self.torrent_path) info = bencodepy.encode(self.meta_info[b"info"]) self.info_hash = sha1(info).digest() self._get_torrent_files()
def test_encode_dict(self): od = collections.OrderedDict() od['ka'] = 'va' od['kb'] = 2 coded = bencodepy.encode(od) self.assertEqual(coded, b'd2:ka2:va2:kbi2ee', msg='Failed to encode dictionary from dict.')
def dumpb(self, obj, options: dict) -> bytes: kwargs = {} kwargs.update(Options.pop_origin_kwargs(options)) self.check_options(options) try: return bencodepy.encode(obj, **kwargs) except TypeError as e: raise SerializeError(e)
def _calc_info_hash(self): self.info_hash = None if "info" in self._torrent_decoded: info_encoded = bencodepy.encode(self._torrent_decoded["info"]) if info_encoded: self.info_hash = hashlib.sha1(info_encoded).hexdigest().upper() return self.info_hash
def __init__(self, filepath): self.file = filepath with open(self.file, 'rb') as f: self.meta_info = f.read() self.meta_info = bencodepy.decode(self.meta_info) info = bencodepy.encode(self.meta_info[b'info']) self.info_hash = sha1(info).digest() self.count_files()
def create_info_hash(self): """ Bencode the info dict and hash it with SHA1 :param meta_data: decoded meta data from .torrent file :return: hashlib digest """ self.info_hash = hashlib.sha1() self.info_hash.update(bencodepy.encode(self.metadata['info'])) self.info_hash = self.info_hash.digest() return self.info_hash
def test_encode_complex(self): od = collections.OrderedDict() od['KeyA'] = ['listitemA', {'k': 'v'}, 3] od['KeyB'] = {'k': 'v'} od['KeyC'] = 3 od['KeyD'] = 'AString' expected_result = b'd4:KeyAl9:listitemAd1:k1:vei3ee4:KeyBd1:k1:ve4:KeyCi3e4:KeyD7:AStringe' coded = bencodepy.encode(od) self.assertEqual(coded, expected_result, msg='Failed to encode complex object.') pass
def torrentToMagnet(cls, torrentByte): try: metadata = bencodepy.decode(torrentByte) subj = metadata[b'info'] hashcontents = bencodepy.encode(subj) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest).decode() return 'magnet:?' \ + 'xt=urn:btih:' + b32hash except: return ""
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 _encodeError(krpcError): """ Encode a KRPC error message. """ error = { 't': krpcError.transactionID, 'y': 'e', 'e': [krpcError.errorCode, krpcError.errorMessage] } return bencodepy.encode(error)
def startProtocol(self): data = { 'y': 'q', 'q': 'ping', 'a': { 'id': hashlib.sha1(b'bla').digest() }, 't': b'42' } self.transport.write(bencodepy.encode(data), ('127.0.0.1', 8043)) print("Sent ping")
def create_resource(call_id, from_tag, to_tag, sock): global kubernetes_apis for a in kubernetes_apis: if a.call_id == call_id: logging.debug( f'A kubernetes resource are exist with this call-id: {call_id}' ) return cookie = ''.join(random.choice(string.ascii_lowercase) for i in range(5)) message = str(cookie) + " " + str( bencodepy.encode(commands.query(call_id)).decode()) ws = False if config["protocol"] == "ws": query = ws_send(message, sock) ws = True else: send(message, sock, (config['rtpe_address'], int(config['rtpe_port']))) logging.debug(f'Received query: {str(query)}') to_port = query['tags'][to_tag]['medias'][0]['streams'][0]['local port'] to_c_address = query['tags'][to_tag]['medias'][0]['streams'][0][ 'endpoint']['address'] to_c_port = query['tags'][to_tag]['medias'][0]['streams'][0]['endpoint'][ 'port'] from_port = query['tags'][from_tag]['medias'][0]['streams'][0][ 'local port'] from_c_address = query['tags'][from_tag]['medias'][0]['streams'][0][ 'endpoint']['address'] from_c_port = query['tags'][from_tag]['medias'][0]['streams'][0][ 'endpoint']['port'] logging.debug('Every port and address is mapped.') kubernetes_apis.append( Client(call_id=call_id, tag=from_tag, local_ip=from_c_address, local_rtp_port=from_c_port, local_rtcp_port=from_c_port + 1, remote_rtp_port=from_port, remote_rtcp_port=from_port + 1, without_jsonsocket=config['without_jsonsocket'], ws=ws)) kubernetes_apis.append( Client(call_id=call_id, tag=to_tag, local_ip=to_c_address, local_rtp_port=to_c_port, local_rtcp_port=to_c_port + 1, remote_rtp_port=to_port, remote_rtcp_port=to_port + 1, without_jsonsocket=config['without_jsonsocket'], ws=ws))
def _encodeResponse(krpcResponse): """ Encode a KRPC response. """ if krpcResponse.type == b'ping': response = { 't': krpcResponse.transactionID, 'y': 'r', 'r': { 'id': bytes(krpcResponse.fromNode) } } elif krpcResponse.type == b'find_node': response = { 't': krpcResponse.transactionID, 'y': 'r', 'r': { 'id': bytes(krpcResponse.fromNode), 'nodes': _encodeNodes(krpcResponse.nodes) } } elif krpcResponse.type == b'get_peers': if krpcResponse.peers != None: response = { 't': krpcResponse.transactionID, 'y': 'r', 'r': { 'id': bytes(krpcResponse.fromNode), 'token': bytes(krpcResponse.token), 'values': _encodePeers(krpcResponse.peers) } } else: response = { 't': krpcResponse.transactionID, 'y': 'r', 'r': { 'id': bytes(krpcResponse.fromNode), 'token': bytes(krpcResponse.token), 'nodes': _encodeNodes(krpcResponse.nodes) } } elif krpcResponse.type == b'announce_peer': response = { 't': krpcResponse.transactionID, 'y': 'r', 'r': { 'id': bytes(krpcResponse.fromNode) } } return bencodepy.encode(response)
def startProtocol(self): data = { 'y': 'q', 'q': 'find_node', 'a': { 'id': hashlib.sha1(b'bla').digest(), 'target': hashlib.sha1(b'bla2').digest() }, 't': b'44' } self.transport.write(bencodepy.encode(data), ('127.0.0.1', 8043)) print("Sent find node")
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 startProtocol(self): data = { 'y': 'q', 'q': 'get_peers', 'a': { 'id': hashlib.sha1(b'bla').digest(), 'info_hash': hashlib.sha1(b'someTorrent').digest() }, 't': b'42' } self.transport.write(bencodepy.encode(data), ('127.0.0.1', 8043)) print("Sent get_peers")
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 from_dict(cls, dictionary: OrderedDict): info_hash = hashlib.sha1(bencodepy.encode(dictionary)).digest() if len(dictionary[b'pieces']) % SHA1_DIGEST_LEN != 0: raise ValueError('Invalid length of "pieces" string') piece_hashes = grouper(dictionary[b'pieces'], SHA1_DIGEST_LEN) if b'files' in dictionary: files = list(map(FileInfo.from_dict, dictionary[b'files'])) else: files = [FileInfo.from_dict(dictionary)] return cls(info_hash, dictionary[b'piece length'], piece_hashes, get_utf8(dictionary, b'name').decode(), files, private=dictionary.get('private', False))
def datagramReceived(self, data, addressPort): (address, port) = addressPort print("Datagram %s received from %s" % (repr(data), repr((address, port)))) data = bencodepy.decode(data) if data[b'y'] == b'r' and data[b't'] == b'42': token = data[b'r'][b'token'] newData = { 'y': 'q', 'q': 'announce_peer', 'a': { 'id': hashlib.sha1(b'bla').digest(), 'info_hash': hashlib.sha1(b'someTorrent').digest(), 'port': 8046, 'token': token }, 't': b'43' } self.transport.write(bencodepy.encode(newData), ('127.0.0.1', 8043)) print("Sent announce")
def infohash(tdict): """ given a decoded torrent file compute the infohash """ return hashlib.sha1(bencodepy.encode(tdict[b'info'])).digest()
def test_no_exception_when_not_strict(self): invalid_obj = None bencodepy.encode(invalid_obj, strict=False) self.assert_(True)
def find_new(self): # find our shows builtins = ('daemon', 'transmission', 'defaults', 'tvdb') shows = [s for s in self.config.sections() if s not in builtins] defaults = self.config.items('defaults', SHOW_DEFAULTS) for cfg_name in shows: show = self.config.items(cfg_name, defaults) show['name'] = show.get('name', cfg_name) show['feed_search'] = show.get('feed_search', show['name']) log.debug('Looking up %s' % show['feed_search']) # if we're at downloading max_concurrent episodes, then stop # processing this show max_concurrent = int(show.get('max_concurrent')) c = self.db.cursor() c.execute( 'select count(*) from shows where cfg_name=? and status=?', (cfg_name, STATUS_INCOMPLETE) ) count = c.fetchone()[0] if count >= max_concurrent: log.debug( 'Reached maximum concurrent torrents (%d) for "%s".' % ( max_concurrent, cfg_name) ) continue # Get the show data from TVDB if show.get('tvdb_id'): try: tvdb_show = self.tvdb.get(show['tvdb_id'], self.tvdb_lang) except tvdb_error.TVDBIdError: result = [] else: result = self.tvdb.search(show['name'], self.tvdb_lang) if not len(result): log.error('Show not found on tvdb: %s' % show['name']) continue if len(result) > 1: log.warning('Multiple matches found for "{r.search}"' .format(r=result)) tvdb_show = result[0] try: # if show has a season 0 (extras), don't count it in the total # number of seasons. tvdb_show[0] except tvdb_error.TVDBIndexError: num_seasons = len(tvdb_show) else: num_seasons = len(tvdb_show) - 1 if num_seasons <= 0: log.error('No seasons found for "{r.search}"'.format(r=result)) continue # Get last downloaded season from the database to see which season # to start with. If no downloads, use start_season c = self.db.cursor() c.execute( 'select max(season) from shows where cfg_name=?', (cfg_name,)) max = c.fetchone()[0] start_season = max or show['start_season'] # load torrent feeds one season at a time, since the feed only # returns a max of 30 shows. entries = [] for season in range(int(start_season), num_seasons + 1): # load rss feed: feed_params = { 'mode': 'rss', 'show_name': show['feed_search'], 'quality': show.get('quality'), 'season': season } if show.get('feed_search_exact', 'false').lower() != 'false': feed_params['show_name_exact'] = 'true' show_feed_url = feed_url + '?' + urlencode(feed_params) log.debug('checking feed url: %s' % show_feed_url) feed = feedparser.parse(show_feed_url) log.debug('found %d entries for %s, season %s' % (len(feed['entries']), show['name'], season)) # assume that feed has given episodes sorted by seed quality, # and maintain that order. for i, e in enumerate(feed['entries']): feed['entries'][i]['ord'] = i # sort feed entries by episode def ordkey(ep): summary = self._parse_summary(ep['summary']) return summary['episode'] * 100 + ep['ord'] entries += sorted(feed['entries'], key=ordkey) eps = [self._parse_summary(e['summary'])['episode'] for e in entries] log.debug(' Found episodes: {}' .format(str([int(s) for s in set(eps)]))) added = 0 for entry in entries: if count >= max_concurrent: log.info( 'Reached maximum concurrent torrents (%d) for this ' 'show "%s".' % (max_concurrent, cfg_name)) break link = entry['link'] summary = entry['summary'] # parse summary details (assuming ezrss keeps this consistent) # ex: 'Show Name: Dexter; Episode Title: My Bad; Season: 5; # Episode: 1' info = self._parse_summary(summary) log.debug( 'Found: %(show_name)s: Season: %(season)s; ' 'Episode: %(episode)s; Title: %(title)s' % info ) season = int(info['season']) episode = int(info['episode']) # skip if less than start_episode. eg, s04e06 would be 406 e2n = lambda s, e: int(s) * 100 + int(e) start_ssn = show['start_season'] start_ep = show['start_episode'] if (e2n(season, episode) < e2n(start_ssn, start_ep)): log.debug( 'Skipping, s%02de%02d is earlier than start_episode' % (season, episode)) continue # Check and see if we need this episode c = self.db.cursor() c.execute( 'SELECT COUNT() FROM shows WHERE cfg_name=? ' 'AND season=? AND episode=?', (cfg_name, season, episode) ) if c.fetchone()[0] > 0: # already have this one, or are already downloading it. log.debug( '"%(show_name)s-%(season)s-%(episode)s" has already ' 'been downloaded or is currently downloading' % info ) continue # Get torrent file so that we can parse info out of it log.debug('Decoding torrent...') try: request = Request(link) request.add_header('Accept-encoding', 'gzip') response = urlopen(request) except HTTPError as e: log.debug('Could not download torrent: %s, %s' % (link, e)) continue if response.info().get('Content-Encoding') == 'gzip': buf = io.BytesIO(response.read()) f = gzip.GzipFile(fileobj=buf) data = f.read() else: data = response.read() try: torrent = bencodepy.decode(data) except DecodingError as e: log.debug(str(e)) log.error('Could not parse torrent: %s' % link) continue filename = torrent[b'info'].get(b'name').decode() if not filename: files = torrent[b'info'][b'files'] # get largest file files = sorted( files, key=lambda f: f['length'], reverse=True) filename = files[0]['path'] ext = os.path.splitext(filename)[1][1:] if ext in show['exclude_extensions'].split(','): log.debug( 'Skipping %s, file extension blacklisted' % filename) continue # Add the show added += 1 log.info( 'Adding %(show_name)s-%(season)s-%(episode)s to ' 'transmission queue' % info) log.debug(link) b64_data = base64.b64encode(data).decode() try: trans_info = self.transmission.add_torrent(b64_data) except transmissionrpc.error.TransmissionError as e: if '"duplicate torrent"' in str(e): log.info('Torrent already exists. Resuming.') # TODO: Find the duplicate torrent binfo = bencodepy.encode(torrent[b'info']) hash = hashlib.sha1(binfo) trans_info = self.transmission.inf(hash.hexdigest()) self.transmission.start(trans_info.id) else: raise # Record in db c = self.db.cursor() show_name = tvdb_show.SeriesName try: title = tvdb_show[season][episode].EpisodeName except (tvdb_error.TVDBIndexError, KeyError): title = info.get('title', '(no title)') c.execute( 'INSERT INTO shows (name, season, episode, title, status, ' 'url, transid, cfg_name) VALUES (?, ?, ? ,? ,? ,?, ?, ?)', (show_name, season, episode, title, STATUS_INCOMPLETE, link, trans_info.id, cfg_name) ) self.db.commit() count += 1 if added == 0: log.info('No new episodes found for %s' % cfg_name)
def test_encode_str(self): coded = bencodepy.encode('ThisIsAString') self.assertEqual(coded, b'13:ThisIsAString', msg='Failed to encode string from str.')
def test_encode_int(self): coded = bencodepy.encode(42) self.assertEqual(coded, b'i42e', msg='Failed to encode integer from int.')
def send_krpc(self, msg, address): try: self.ufd.sendto(encode(msg), address) except Exception: pass
def test_encode_list(self): l = ['a', 'b', 3] coded = bencodepy.encode(l) self.assertEqual(coded, b'l1:a1:bi3ee', msg='Failed to encode list from list.')
def send_krpc(self, message, address): try: self.sock.sendto(encode(message), address) except Exception as error: self.logger.error("send_krpc: {}".format(error))
def test_encode_tuple(self): t = ('a', 'b', 3) coded = bencodepy.encode(t) self.assertEqual(coded, b'l1:a1:bi3ee', msg='Failed to encode list from tuple.')
def send_request_metadata(s, ut_metadata, i): msg_body = {"m": {"msg_type": 0, "piece": i}} msg = b"\x14" + chr(ut_metadata).encode() + bencodepy.encode(msg_body) send_msg(s, msg)
def test_exception_when_strict(self): invalid_obj = None with self.assertRaises(bencodepy.EncodingError): bencodepy.encode(invalid_obj, strict=True)
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')
def dumpTorrent(tdict, fd): """ dump a parsed torrent into a file """ data = bencodepy.encode(tdict) fd.write(data)
def get_hash(binary): decoded_data = bencodepy.decode(binary) decoded_info = decoded_data[b'info'] encoded_info = bencodepy.encode(decoded_info) torrent_hash = hashlib.sha1(encoded_info).hexdigest() return torrent_hash
def send_krpc(self, msg, address): try: self.socket.sendto(bencodepy.encode(msg), address) except Exception: pass