def bencode_cmd(): """ Synopsis:: beencode [999, 99, 1, 2218, 2318, 2462, 2250] li999ei99ei1ei2218ei2318ei2462ei2250ee beencode {'h': [890, 377], 't': [3455, 3455, 3455, 3455], 'w': 12333} d1:tli3455ei3455ei3455ei3455ee1:hli890ei377ee1:wi12333ee """ boot_logging() if len(sys.argv) >= 2: return bencode.bencode(sys.argv[1]) data_01 = [999, 99, 1, 2218, 2318, 2462, 2250] data_02 = { 't': [1234, 5678, 4242], 'h': [587, 476], 'w': 42 } data_03 = {'#': 999, '_': 'h1', 't': [2163, 1925, 1092, 1354], 'h': [488, 572], 'w': 10677} return bencode.bencode(data_03)
def all(): from cbencode import Decoder from itertools import islice import mmap, time dec = Decoder(json_decode=BenJson) f = file('/tmp/sa/testdata') buf = mmap.mmap(f.fileno(), 0, mmap.PROT_READ, mmap.MAP_SHARED) chu = ChunkedList() #it = islice(dec.decode_iter(buf), 500000) it = dec.decode_iter(buf) t1 = time.time() c = 0 while True: try: n = it.next() chu.push((n,)) c += 1 except StopIteration: break chu.push(islice(it, 10)) c += 10 print 'iter (%d items) took %dms' % (c, (time.time() - t1) * 1000) buf = None f.close() t1 = time.time() enc = bencode(chu) print 'sze', len(bencode(chu)) print 'encode took %dms' % ((time.time() - t1) * 1000) t1 = time.time() c = 0 for item in dec.decode(enc): # bdecode(enc): c += 1 #print item print 'decode (%d items) took %dms' % (c, (time.time() - t1) * 1000)
def __init__(self, torrent_file): with open (torrent_file, 'r') as t: parsed_torrent = t.read() self.info_dict = bencode.bdecode(parsed_torrent) self.tracker_url = self.info_dict['announce'] self.info_hash = hashlib.sha1(bencode.bencode(self.info_dict['info'])).digest() self.info_hash_readable = hashlib.sha1(bencode.bencode(self.info_dict['info'])).hexdigest() if self.info_dict['info'].get('name'): self.name = self.info_dict['info']['name'] self.encoding = self.info_dict.get('encoding', None) if self.info_dict['info'].get('files'): self.no_of_files = len(self.info_dict['info']['files']) self.total_length = 0 for files in self.info_dict['info']['files']: self.total_length += files['length'] else: self.no_of_files = 1 self.total_length = self.info_dict['info']['length'] self.subpieces = self.info_dict['info']['pieces'] self.piece_length = self.info_dict['info']['piece length'] #['pieces'] is a concatenated string of the hashes of each piece (each takes 20 characters). Splitting these up into a list: self.list_of_subpieces_hashes = [] for i in range(0, len(self.subpieces), 20): self.list_of_subpieces_hashes.append(self.subpieces[i:i+20]) self.no_of_subpieces = len(self.list_of_subpieces_hashes) self.bitfield = Bitfield(self) self.block_size = 16384
def scrape(): try: stats = Swarm.from_hex_hash(request.query["infohash"]).stats() return bencode(stats) except KeyError: stats = {} for swarm in Swarm.nonsecret(): stats.update(swarm.stats()) return bencode(stats)
def test(): c = ChunkedList(chunk_size=14) c.push(('0')) c.push(('1')) c.push(('2')) c.push(('a', 'b', 'c')) c.push(('d', 'e', 'f')) d = bdecode(bencode(c)) d = ChunkedList(d.encode()) d.push(('g', 'h', 'i')) print list(d) print list(bdecode(bencode(d)))
def got_message(self, msg, conn): t = msg[0] r = None if t == UTORRENT_MSG: print "UTORRENT_MSG" if t == CHOKE: print "CHOKE" elif t == UNCHOKE: print "UNCHOKE" elif t == INTERESTED: print "INTERESTED" elif t == NOT_INTERESTED: print "NOT_INTERESTED" elif t == HAVE: i = struct.unpack("!i", msg[1:])[0] print "HAVE", i elif t == BITFIELD: print "BITFIELD" self.calc_bitfield(msg[1:]) elif t == REQUEST: print "REQUEST" elif t == CANCEL: print "CANCEL" elif t == PIECE: print "PIECE" elif t == PORT: print "PORT", struct.unpack("!H", msg[1:])[0] #self.peerlist[conn.addr]["DHT"] = True #self.peerlist[conn.addr]["DHT_PORT"] = struct.unpack("!H", msg[1:])[0] #elif t == SUGGEST_PORT: # print "SUGGEST_PORT" elif t == HAVE_ALL: print "HAVE_ALL" elif t == HAVE_NONE: print "HAVE_NONE" elif t == REJECT_REQUEST: print "REJECT_REQUEST" elif t == ALLOWED_FAST: print "ALLOWED FAST" elif t == UTORRENT_MSG: ext_type = ord(msg[1]) d = bdecode(msg[2:]) print "?"*10, d infodict = bencode(self.honey[self.honey.keys()[0]]) response = {"msg_type": ord(chr(1)), "piece":d["piece"], "total_size":16*2**10} response = chr(20) + chr(conn.ut_metadata) + bencode(response) + infodict[d["piece"]*2**14: (d["piece"]+1)*2**14] response = struct.pack("!i", len(response)) + response print response[:300] conn.sock.sendall(response) else: print "got unknown message", repr(msg) # Continue return r
def build_meta_file(self, path, file_length, piece_length, pieces_hash): port = TRACKER_PORT.__str__() ip = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1][0] #Gets the IP and port of the tracker. announce = "udp://" + ip + ":" + port #Creates an announce URL. filename = path.split("\\")[-1] temp = filename.split(".") temp[-1] = "torrent" torrent_name = temp[0] for i in temp[1:]: torrent_name += "." + i #turns the file into a .torrent file info = {'name' : filename, 'piece length': piece_length, 'length': file_length, 'pieces': pieces_hash } file = {"announce" : announce, "info" : info} #Builds the info dictionary and the file print file MemoryHandler.save_file(torrent_name, bencode.bencode(file)) #Saves them as bencoded data return self.hash_piece(bencode.bencode(info)) #Returns the info_hash
def compute_hash(videoObj): """ Return torrent hash """ torrent = urllib.urlopen(videoObj.download_url).read() info = bencode.bdecode(torrent)['info'] h = hashlib.sha1() h.update(bencode.bencode(info)) return h.hexdigest()
def _get_torrent_hash(self, result): if result.url.startswith('magnet'): result.hash = re.findall('urn:btih:([\w]{32,40})', result.url)[0] if len(result.hash) == 32: result.hash = b16encode(b32decode(result.hash)).lower() else: if not result.content: logger.log('Torrent without content', logger.ERROR) raise Exception('Torrent without content') try: torrent_bdecode = bdecode(result.content) except BTFailure as e: logger.log('Unable to bdecode torrent', logger.ERROR) logger.log('Torrent bencoded data: {0}'.format(str(result.content)), logger.DEBUG) raise try: info = torrent_bdecode["info"] except Exception as e: logger.log('Unable to find info field in torrent', logger.ERROR) raise result.hash = sha1(bencode(info)).hexdigest() return result
def to_metainfo(self): try: info_as_dict = bdecode(redis_connection.get(self.info_hash + ".info")) return bencode({"announce": announce_url, "info": info_as_dict }) except TypeError: raise NoInfoException()
def multi_file(self, basePath, check_md5=False): """ Generate multi-file torrent check_md5: adds md5sum to the torrentlist basePath: path to folder Torrent name will automatically be basePath """ if 'length' in self.tdict['info']: raise TypeError('Cannot add multi-file to single-file torrent') if basePath.endswith('/'): basePath = basePath[:-1] realPath = path.abspath(basePath) toGet = [] fileList = [] info_pieces = '' data = '' for root, subdirs, files in walk(realPath): for f in files: subPath = path.relpath(root, start=realPath).split('/') subPath.append(f) subPath = [str(p) for p in subPath] toGet.append(subPath) for pathList in toGet: length = 0 filePath = ('/').join(pathList) if check_md5: md5sum = md5() fileDict = { 'path': pathList, 'length': len(open(path.join(basePath, filePath), "rb").read()) } with open(path.join(basePath, filePath), "rb") as fn: while True: filedata = fn.read(self.piece_length) if len(filedata) == 0: break length += len(filedata) data += filedata if len(data) >= self.piece_length: info_pieces += sha1(data[:self.piece_length]).digest() data = data[self.piece_length:] if check_md5: md5sum.update(filedata) fileDict['md5sum'] = md5sum.hexdigest() fileList.append(fileDict) if len(data) > 0: info_pieces += sha1(data).digest() self.tdict['info'].update( { 'name': str(path.basename(realPath)), 'files': fileList, 'pieces': info_pieces } ) info_hash = sha1(bencode(self.tdict['info'])).hexdigest() return({'Created': info_hash})
def render_GET(self, request): HashTableNew.HashTable.do_clean_up() start = time.clock() info_hash_lst = [] if 'info_hash' in request.args: info_hash_lst = request.args['info_hash'] else: return bencode_faild_str('Mising info_hash') ret = {} for info_hash in info_hash_lst: peers_cnt = HashTable.get_torrent_peers_count(info_hash) seeders_cnt = HashTable.get_torrent_seeders_count(info_hash) leechers_cnt = peers_cnt - seeders_cnt completed_cnt = HashTable.get_completed_by_info_hash(info_hash) info_table = {"complete": seeders_cnt, "downloaded": completed_cnt, "incomplete": leechers_cnt} ret.update({info_hash:info_table}) ret = {'files': ret} ret = bencode.bencode(ret) end = time.clock() logging.debug('process scrape query at:%lf' % (end-start)) Config.process_scrape_query_at = end-start return ret
def send_msg(self, name_, **msg): ''' Send an outgoing Message, translating function keyword arguments into the Message arguments. Before sending the message down the wire, run our own validation checks against it, and raise a DecoderError() Exception if it fails. After validation, bencode the Python dict, and prefix it with an ASCII length field. For human readability, put a space between length field and the bencoded blob, and send a \r\n after the blob. ''' try: msg['msg'] = name_ self.validate_message(msg.copy()) except DecoderError as e: # This debugging output is hard to read, but fortunately it # shouldn't happen very often. print timestamp(), self, "Our own outgoing message failed validation?", msg self.close() raise buf = bencode(msg) buf = ('%0' + str(config.msg_len_bytes) + 'x') % len(buf) + ' ' + buf + '\r\n' del msg['msg'] print timestamp(), self, "--> ", name_, repr_msg(msg) self.send(buf)
def generate_magnet(metadata, dn=None): import hashlib import base64 import urllib from bencode import bencode tr = [] if "announce-list" in metadata: tmp = metadata["announce-list"] if isinstance(tmp, list): for i in tmp: if isinstance(i, list): tr += i else: tr.append(i) if "announce" in metadata and not metadata["announce"] in tr: tr.append(metadata["announce"]) params = { "dn": dn or metadata["info"].get("name", None), "tr": tr } b32hash = base64.b32encode(hashlib.sha1(bencode(metadata["info"])).digest()) return "magnet:?%s&%s" % ("xt=urn:btih:%s" % b32hash, urllib.urlencode(params, True))
def create_torrent(cls, file_name, tracker_url, content, piece_length=512, write=True): # TODO: add other options like: announce-list, creation date, comment, created by, encoding info_dict = { 'name': file_name, 'length': len(contents), # Fields common to single and multi-file below 'piece length': piece_length * 1024, 'pieces': cls._pieces_hashes(contents) } metainfo = { 'info': info_dict, 'announce': tracker_url } if write: with open(file_name, 'w') as f: f.write(bencode.bencode(metainfo)) return cls(file_name, metainfo)
def _get_info_hash(result): if result.url.startswith('magnet:'): result.hash = re.findall(r'urn:btih:([\w]{32,40})', result.url)[0] if len(result.hash) == 32: result.hash = b16encode(b32decode(result.hash)).lower() else: try: # `bencode.bdecode` is monkeypatched in `medusa.init` torrent_bdecode = bdecode(result.content, allow_extra_data=True) info = torrent_bdecode['info'] result.hash = sha1(bencode(info)).hexdigest() except (BencodeDecodeError, KeyError): log.warning( 'Unable to bdecode torrent. Invalid torrent: {name}. ' 'Deleting cached result if exists', {'name': result.name} ) cache_db_con = db.DBConnection('cache.db') cache_db_con.action( 'DELETE FROM [{provider}] ' 'WHERE name = ? '.format(provider=result.provider.get_id()), [result.name] ) except Exception: log.error(traceback.format_exc()) return result
def _get_torrent_hash(self, result): if result.url.startswith('magnet'): result.hash = re.findall(r'urn:btih:([\w]{32,40})', result.url)[0] if len(result.hash) == 32: result.hash = b16encode(b32decode(result.hash)).lower() else: if not result.content: sickrage.LOGGER.error('Torrent without content') raise Exception('Torrent without content') try: torrent_bdecode = bdecode(result.content) except BTFailure: sickrage.LOGGER.error('Unable to bdecode torrent') sickrage.LOGGER.debug('Torrent bencoded data: %r' % result.content) raise try: info = torrent_bdecode[b"info"] except Exception: sickrage.LOGGER.error('Unable to find info field in torrent') raise result.hash = sha1(bencode(info)).hexdigest() return result
def __init__(self, trackerFile): """ Initalizes the PeerManager, which handles all the peers it is connected to. Input: trackerFile -- takes in a .torrent tracker file. Instance Variables: self.peer_id -- My id that I give to other peers. self.peers -- List of peers I am currently connected to. Contains Peer Objects self.pieces -- List of Piece objects that store the actual data we we are downloading. self.tracker -- The decoded tracker dictionary. self.infoHash -- SHA1 hash of the file we are downloading. """ self.peer_id = '-lita38470993824756-' self.peers = [] self.pieces = [] self.tracker = bencode.bdecode(open(trackerFile,'rb').read()) bencodeInfo = bencode.bencode(self.tracker['info']) self.infoHash = hashlib.sha1(bencodeInfo).digest() self.getPeers() self.generatePieces() self.peer_id = '-lita38470993887523-'
def handle_fn_qdata(self, data, addr): print "Receive find node query" target_node_id = data["a"]["target"] rtable_index = utility.get_rtable_index(utility.xor(self.node_id, target_node_id)) response_nodes = [] for node in self.rtable[rtable_index]: if node[0] == target_node_id: response_nodes.append(node) break if len(response_nodes) == 0: response_nodes = self.get_k_closest_nodes(target_node_id) node_message = utility.encode_nodes(response_nodes) response = {} response["t"] = data["t"] response["y"] = "r" response["r"] = {} response["r"]["id"] = self.node_id response["r"]["nodes"] = node_message response = bencode(response) try: self.socket.sendto(response, addr) except: pass
def _save_info_(self, info_as_dict): bencoded_info_dict = bencode(info_as_dict) h = hashlib.new("sha1") h.update(bencoded_info_dict) self.info_hash = h.hexdigest() print("info_hash = " + self.info_hash) redis_connection.set(self.info_hash + ".info", bencoded_info_dict)
def __init__(self, raw, ip, pid): d = bencode.bdecode(raw) try: self.announce = [d['announce']] except KeyError: try: self.announce = [ l[0] for l in d['announce-list'] ] except KeyError: self.magnetinfo = d['magnet-info'] self.announce = [self.magnetinfo['announce']] self.comment = getattr(d, 'comment', 'No Comment') self.creator = getattr(d, 'created by', 'Unknown') self.date = getattr(d, 'created on', None) self.encoding = getattr(d, 'encoding', None) info = d['info'] sha = hashlib.sha1() sha.update(bencode.bencode(info)) self.info_hash = sha.digest() print self.info_hash self.info = InfoDict(info, self.encoding) self.trackers = [ Tracker(TrackerRequest(na=ip, hash=self.info_hash, ID=pid, url=url, stats=self.info.sessionstats())) for url in self.announce ] self.info['started'] == True
def db_put(co, cdb, key, value, txn): cdb.put(key, bencode(value), txn=txn) try: cache = co.db_cache[db] except KeyError: cache = co.db_cache[db] = {} cache[key] = value
def process(self, event): """ event.event_type 'modified' | 'created' | 'moved' | 'deleted' event.is_directory True | False event.src_path path/to/observed/file """ if event.event_type == 'created' and event.is_directory == False: path = event.src_path logger.debug('New torrent file detected at: %s', path) logger.info('Uploading torrent to the cloud: %s', path) if upload_torrent(event.src_path): # Open torrent file to get hash torrent_file = open(sys.argv[1], "rb") metainfo = bencode.bdecode(torrent_file.read()) info = metainfo['info'] hash = hashlib.sha1(bencode.bencode(info)).hexdigest() dirname = os.path.dirname(path) if dirname in prem_config.get('downloads', 'download_categories').split(','): category = dirname else: category = '' add_task(hash, category) logger.debug('Deleting torrent from the watchdir: %s', path) os.remove(path)
def get_magnet(file_name): torrent = open(file_name, 'rb').read() metadata = bencode.bdecode(torrent) hash_info = metadata['info'] hash_info = hashlib.sha1(bencode.bencode(hash_info)).hexdigest() magnet = "magnet:?xt=urn:btih:" + hash_info return magnet
def parse_torrent(torrent_path): """Reads a tracker from disk and returns metadata information about it, including a list of trackers for the torrent and the hash for the torrent. Args: torrent_path -- A path to read a torrent file from on disk Returns: A tuple of three values, 1) a list of zero or more trackers, 2) the info hash for the files in the tracker, and 3) the total size of the files in the torrent """ trackers = [] size = 0 info_hash = None with open(torrent_path, 'r') as h: torrent_data = h.read() data = bencode.bdecode(torrent_data) trackers.append(data['announce']) try: trackers += [t[0] for t in data['announce-list']] except KeyError: pass info_hash = hashlib.sha1(bencode.bencode(data['info'])).digest() try: for files_data in data['info']['files']: size += files_data['length'] except KeyError: size = data['info']['length'] return trackers, info_hash, size
def torrent(self): try: data = b64decode(self.torrent_data.encode('utf-8')) except TypeError: return None if not data: return None data = bdecode(data) # transform the data into a template-friendly dict info = data.get('info', {}) metadata = { 'comment': data.get('comment', None), 'created_by': data.get('created by', None), 'creation_date': None, 'announce': data.get('announce', None), 'file_name': info.get('name', None), 'file_length': info.get('length', None), 'piece_count': len(info.get('pieces', '')) / 20, 'piece_length': info.get('piece length', None), 'url_list': data.get('url-list', []), 'info_hash': None, } if 'creation date' in data: created= datetime.utcfromtimestamp(data['creation date']) metadata['creation_date'] = created.replace(tzinfo=utc) if info: metadata['info_hash'] = hashlib.sha1(bencode(info)).hexdigest() return metadata
def addtorrent(context, request): u = get_current_user(request) announce_url = ('http://%s/%s/announce' % (request.registry.settings['hostname'], u.passkey)).encode('utf-8') if request.method=="POST": form = AddTorrentForm(request.params) if form.validate(): filename = save_torrent(form.torrent_file.data, request) abs_filename = os.path.join(request.registry.settings['torrent_dir'], filename) info = bencode.bencode(bencode.bdecode(open(abs_filename).read())['info']) name = form.name.data info_hash = hashlib.sha1(info).hexdigest() log.error('INFOHASH: '+info_hash) torrent = Torrent() torrent.info_hash = info_hash torrent.name = unicode(name) torrent.info = {} torrent.uploaded_time = datetime.datetime.now() torrent.torrent_file = filename torrent.last_checked = datetime.datetime.now() DBSession.add(torrent) DBSession.commit() log.error(filename) return {'form': form, 'announce': announce_url} else: form = AddTorrentForm() return {'form': form, 'announce': announce_url}
def _send_command_v2(self, command, *parameters): """sends a command for protocol version 2. Input is the command name as string followed by an arbitrary amount of parameters. """ # we need to add an empty parameter if none is supplied to satisfy the protocol: if not parameters: parameters = (0,) commandlist = [command] commandlist.extend(parameters) self.TAGNUMBER += 1 commandlist.append(self.TAGNUMBER) payload = bencode(commandlist) hexlength = hex(len(payload))[2:].zfill(8) encoded = "%s%s" % (hexlength, payload) try: self.socket.send(encoded) return self.TAGNUMBER except Exception, info: try: errno, ermess = info if errno in [32, 57]: self._connect(ping=False) self.socket.send(encoded) return self.TAGNUMBER elif errno == 61: raise TransmissionClientFailure, """No socket at %s. Make sure your daemon is up and running!""" % self.socketpath except ValueError: raise TransmissionClientFailure, "No connection."
def initialize_from_torrent_file(self): torrent_dict = bencode.bdecode(open(self.filename).read()) self.creation_date = datetime.datetime.fromtimestamp(torrent_dict['creation date']) self.announce_url = torrent_dict['announce'] self.created_by = torrent_dict.get('created by', None) self.encoding = torrent_dict.get('encoding', None) info_dict = torrent_dict['info'] self.info_hash = sha.new(bencode.bencode(info_dict)).digest() self.piece_length = info_dict['piece length'] self.piece_hashes = [info_dict['pieces'][i:i+20] for i in range(0, len(info_dict['pieces']), 20)] self.private = bool(info_dict.get('private', 0)) if 'files' in info_dict: self.mode = 'multi-file' self.files = [os.path.join(*f['path']) for f in info_dict['files']] self.file_sizes = [f['length'] for f in info_dict['files']] self.length = sum([f['length'] for f in info_dict['files']]) self.name = '; '.join([f['path'][-1] for f in info_dict['files']]) else: self.mode = 'single-file' self.name = info_dict['name'] self.length = info_dict['length'] self.files = [self.name] self.file_sizes = [self.length] if self.length > len(self.piece_hashes) * self.piece_length: raise Torrent.ParsingException('File size is greater than total size of all pieces')
def tracker_request_url(metainfo_file, peer_id, port, uploaded, downloaded, left, event): """Generate the URL to request from the tracker""" from urllib.parse import urlparse, urlencode, quote, urlunparse #create the info_hash from the info section of the metainfo file. info_string = bencode(metainfo_file["info"]) s = sha1() s.update(bytes(info_string, "UTF-8")) info_hash = quote(s.digest()) #generate the URL to request, take the existing announce URL from #the metainfo_file scheme, netloc, path, params, query, fragment = urlparse(metainfo_file["announce"]) #add query parameters query = urlencode({"info_hash": info_hash, "peer_id": peer_id, "port": port, "uploaded": uploaded, "downloaded": downloaded, "left": left, "event": event}) #put the URL together and return it. return urlunparse((scheme, netloc, path, params, query, fragment))
def send_krpc(self, msg, address): try: self.ufd.sendto(bencode(msg), address) except Exception: pass
def _send_msg(self, s, data): self.nh.send_msg(s, bencode(data))
def _send_response(self, s, mid, data): return self.nh.send_response(s, mid, bencode(data))
def send_krpc(self, msg, address): try: # print(bencode(msg), address) self.socket.sendto(bencode(msg), address) except Exception: pass
def __new__(typ, itr): obj = tuple.__new__(typ, itr) obj.md5hash = hashlib.md5(bencode.bencode(itr)).hexdigest() return obj
def download(self, data, movie, filedata=None): log.debug('Sending "%s" to rTorrent.', (data.get('name'))) if not self.connect(): return False group_name = 'cp_' + data.get('provider').lower() if not self._update_provider_group(group_name, data): return False torrent_params = {} if self.conf('label'): torrent_params['label'] = self.conf('label') if not filedata and data.get('protocol') == 'torrent': log.error('Failed sending torrent, no data') return False # Try download magnet torrents if data.get('protocol') == 'torrent_magnet': filedata = self.magnetToTorrent(data.get('url')) if filedata is False: return False data['protocol'] = 'torrent' info = bdecode(filedata)["info"] torrent_hash = sha1(bencode(info)).hexdigest().upper() # Convert base 32 to hex if len(torrent_hash) == 32: torrent_hash = b16encode(b32decode(torrent_hash)) # Send request to rTorrent try: # Send torrent to rTorrent torrent = self.rt.load_torrent(filedata) if not torrent: log.error('Unable to find the torrent, did it fail to load?') return False # Set label if self.conf('label'): torrent.set_custom(1, self.conf('label')) if self.conf('directory') and self.conf('append_label'): torrent.set_directory( os.path.join(self.conf('directory'), self.conf('label'))) elif self.conf('directory'): torrent.set_directory(self.conf('directory')) # Set Ratio Group torrent.set_visible(group_name) # Start torrent if not self.conf('paused', default=0): torrent.start() return self.downloadReturnId(torrent_hash) except Exception, err: log.error('Failed to send torrent to rTorrent: %s', err) return False
def send_krpc(self, msg, address): self.message_queue.put((bencode(msg), address))
def send_msg(self, msg, dst): self.s.sendto(bencode(msg), dst)
def parsedir(directory, parsed, files, blocked, exts=['.torrent'], return_metainfo=False, errfunc=_errfunc): if NOISY: errfunc('checking dir') dirs_to_check = [directory] new_files = {} new_blocked = {} torrent_type = {} while dirs_to_check: # first, recurse directories and gather torrents directory = dirs_to_check.pop() newtorrents = False for f in os.listdir(directory): newtorrent = None for ext in exts: if f.endswith(ext): newtorrent = ext[1:] break if newtorrent: newtorrents = True p = os.path.join(directory, f) new_files[p] = [(os.path.getmtime(p), os.path.getsize(p)), 0] torrent_type[p] = newtorrent if not newtorrents: for f in os.listdir(directory): p = os.path.join(directory, f) if os.path.isdir(p): dirs_to_check.append(p) new_parsed = {} to_add = [] added = {} removed = {} # files[path] = [(modification_time, size), hash], hash is 0 if the file # has not been successfully parsed for p, v in new_files.items(): # re-add old items and check for changes oldval = files.get(p) if not oldval: # new file to_add.append(p) continue h = oldval[1] if oldval[0] == v[0]: # file is unchanged from last parse if h: if blocked.has_key(p): # parseable + blocked means duplicate to_add.append(p) # other duplicate may have gone away else: new_parsed[h] = parsed[h] new_files[p] = oldval else: new_blocked[p] = 1 # same broken unparseable file continue if parsed.has_key(h) and not blocked.has_key(p): if NOISY: errfunc('removing ' + p + ' (will re-add)') removed[h] = parsed[h] to_add.append(p) to_add.sort() for p in to_add: # then, parse new and changed torrents new_file = new_files[p] v, h = new_file if new_parsed.has_key(h): # duplicate if not blocked.has_key(p) or files[p][0] != v: errfunc('**warning** ' + p + ' is a duplicate torrent for ' + new_parsed[h]['path']) new_blocked[p] = 1 continue if NOISY: errfunc('adding ' + p) try: ff = open(p, 'rb') d = bdecode(ff.read()) check_info(d['info']) h = sha(bencode(d['info'])).digest() new_file[1] = h if new_parsed.has_key(h): errfunc('**warning** ' + p + ' is a duplicate torrent for ' + new_parsed[h]['path']) new_blocked[p] = 1 continue a = {} a['path'] = p f = os.path.basename(p) a['file'] = f a['type'] = torrent_type[p] i = d['info'] l = 0 nf = 0 if i.has_key('length'): l = i.get('length', 0) nf = 1 elif i.has_key('files'): for li in i['files']: nf += 1 if li.has_key('length'): l += li['length'] a['numfiles'] = nf a['length'] = l a['name'] = i.get('name', f) def setkey(k, d=d, a=a): if d.has_key(k): a[k] = d[k] setkey('failure reason') setkey('warning message') setkey('announce-list') if return_metainfo: a['metainfo'] = d except: errfunc('**warning** ' + p + ' has errors') new_blocked[p] = 1 continue try: ff.close() except: pass if NOISY: errfunc('... successful') new_parsed[h] = a added[h] = a for p, v in files.items(): # and finally, mark removed torrents if not new_files.has_key(p) and not blocked.has_key(p): if NOISY: errfunc('removing ' + p) removed[v[1]] = parsed[v[1]] if NOISY: errfunc('done checking') return (new_parsed, new_files, new_blocked, added, removed)
def update_file(co, handle, pre_heads, rhead, names, dcache, txn): def gen_file_points(prune): file_points, points = [], ['1'] true_pre_heads = simplify_precursors(co, handle, co.contents, pre_heads, txn)[0] # don't use pre_heads which are ancestors of rhead for pre, index in true_pre_heads: if prune and is_ancestor(co, pre, rhead, txn): continue info = handle_contents_at_point(co, handle, pre, txn, dcache=dcache) if info is None: continue points = dmerge(points, info['points']) file_points.append( (info['lines'], info['line points'], info['points'])) return (file_points, points) if not co.merge: return 0 rinfo = handle_contents_at_point(co, handle, rhead, txn, dcache=dcache) if rinfo.has_key('delete'): # File was deleted remotely, we're done # XXX: validate remote history return 0 elif co.editsdb.has_key(handle) and bdecode( co.editsdb.get(handle)).has_key('hash'): lfile = _handle_to_filename(co, handle, names, txn) lfile = path.join(co.local, lfile) h = open(lfile, 'rb') lines = h.read().split('\n') h.close() file_points, points = gen_file_points(0) line_points = find_resolution(file_points, lines)[0] for i in xrange(len(line_points)): if line_points[i] is None: line_points[i] = '1' olines = find_conflict(lines, line_points, points, rinfo['lines'], rinfo['line points'], rinfo['points']) else: file_points, points = gen_file_points(1) if file_points == []: # The remote copy is a superset of local changes olines = rinfo['lines'] else: lines, line_points, points = find_conflict_multiple_safe( file_points) olines = find_conflict(lines, line_points, points, rinfo['lines'], rinfo['line points'], rinfo['points']) ls, conflict = [], 0 for l in olines: if type(l) is str: ls.append(l) else: conflict = 1 ls.append('<<<<<<< local') ls.extend(l[0]) ls.append('=======') ls.extend(l[1]) ls.append('>>>>>>> remote') lfile = path.join(co.temppath, binascii.hexlify(handle)) h = open(lfile, 'wb') h.write('\n'.join(ls)) h.close() if conflict: set_edit(co, handle, {'hash': 1}, txn) mtime = int(path.getmtime(lfile)) co.modtimesdb.put(handle, bencode(mtime), txn=txn) return conflict
max_rate_period, fudge) ratemeasure = RateMeasure(storagewrapper.get_amount_left()) rm[0] = ratemeasure.data_rejected picker = PiecePicker(len(pieces), config['rarest_first_cutoff']) for i in xrange(len(pieces)): if storagewrapper.do_I_have(i): picker.complete(i) downloader = Downloader(storagewrapper, picker, config['request_backlog'], config['max_rate_period'], len(pieces), downmeasure, config['snub_time'], ratemeasure.data_came_in) connecter = Connecter(make_upload, downloader, choker, len(pieces), upmeasure, config['max_upload_rate'] * 1024, rawserver.add_task) infohash = sha(bencode(info)).digest() encoder = Encoder(connecter, rawserver, myid, config['max_message_length'], rawserver.add_task, config['keepalive_interval'], infohash, config['max_initiate']) rerequest = Rerequester( response['announce'], config['rerequest_interval'], rawserver.add_task, connecter.how_many_connections, config['min_peers'], encoder.start_connection, rawserver.add_task, storagewrapper.get_amount_left, upmeasure.get_total, downmeasure.get_total, listen_port, config['ip'], myid, infohash, config['http_timeout'], errorfunc, config['max_initiate'], doneflag, upmeasure.get_rate, downmeasure.get_rate, encoder.ever_got_incoming) if config['spew']: spewflag.set() DownloaderFeedback(choker, rawserver.add_task, statusfunc, upmeasure.get_rate, downmeasure.get_rate,
def _send_request(self, s, data): return self.nh.send_request(s, bencode(data))
def ping(self, id): query = self.query_head("ping") query["a"] = dict(id=id) return bencode(query)
def main(): ss = Preferences() oldfile = open(ss.get("utresumedat"),'rb').read() newfile = open(os.path.join(ss.get("maindir"),u"NEWDAT.dat"),'wb') namesandhashfile = open(ss.getwpath("outpath3"),'rb').readlines() beforeafterpath = ss.getwpath("outpath4") #this holds the intermediate changes to happen before actually renaming so you have a chance to edit/change it. (4beforepath-afterpath.txt) torrentlist = bencode.bdecode(oldfile) #These two things interfere with the processing on the next line fileguarduseless = torrentlist.pop(".fileguard",None) rec = torrentlist.pop("rec",None) #Remove this. #(dict. comprehension expects only dicts as the root keys) #create a reverse lookup dict with "Dict comprehension". nice and simple eh? ;-) reverselookup={base64.b16encode(value["info"]):[key,value["caption"],value["path"]] for key,value in torrentlist.iteritems()} listofbeforeafter = [] #to modify paths in reverse lookup dict, start by getting the names and hash out of the namesandhashfile for eachline in namesandhashfile: nameandhash = eachline.strip().split(' / ') #strip out the \n with strip() and split on the " / " i put there as a seperator. theNewname = nameandhash[0] thehash = nameandhash[1] #searches the dict's keys for a Hash, if exists. and if so, can be used as the [indexid] if thehash in reverselookup: key = reverselookup[thehash][0] theOldPath = torrentlist[key]["path"] theNewPath = os.path.join(os.path.dirname(theOldPath),theNewname) if theOldPath != theNewPath: listofbeforeafter.append([theOldPath,theNewPath,thehash]) # make a list of a list (stringtoOutputtoFile=[0], hash=[1]) #sort, then write file detailing changes to path (before / after) listofbeforeafter.sort() beforeafterfile = open(beforeafterpath,'wb') for eachline in listofbeforeafter: try: beforeafterfile.write(eachline[0] + " / " + eachline[2] + "\n") #write oldpath + hash on 1st line /The hash is duplicated for error checking in case the user accidentally bungles a character while editing... beforeafterfile.write(eachline[1] + " / " + eachline[2] + "\n") #write newpath + hash on 2nd line / except: print "Error writing the before+after file, probably a encoding/unicode error: \n", eachline[0],"\n",eachline[1] print "This was a fatal error and program could not continue." return beforeafterfile.close() #At this point the script pauses, and asks the user to confirm changes shown in the beforepath-afterpath.txt file raw_input("Press Enter to begin Renaming files.......\\> ") #wait for the user to press Enter before continuing with anything. #WRITE TORRENT RESUME.DAT beforeafterfile = open(beforeafterpath,'rb').readlines() for i in xrange(0, len(beforeafterfile), 2): beforeandhash = beforeafterfile[i].strip().split(' / ') afterandhash = beforeafterfile[i+1].strip().split(' / ') before = beforeandhash[0].decode('utf-8') beforehash = beforeandhash[1] after = afterandhash[0].decode('utf-8') afterhash = afterandhash[1] if beforehash == afterhash: thehash = beforehash else: print "Error. You have inadvertently modified one of the hash files, and there is a hash mismatch between before/after entries." print "Cannot continue. Exiting. Please save your changes into a new file, locate your error, and re-run and fix it..." print "Another possibility is you were missing a / (with 1 character of whitespace on each side surrounding it) as a seperator." #searches the dict's keys for a Hash, if exists. and if so, can be used as the [indexid] if thehash in reverselookup: key = reverselookup[thehash][0] torrentlist[key]["caption"] = after[after.rfind("\\")+1:] try: # prints a number to console to show progress. corresponds to the numbers in the file (every-two-lines). (tip:) to show incremental numbers use (((i+1)/2)+1) # filenames printed to console, will be missing any unicode chars because the windows console is not unicode compatible!!!! (annoying) print i,before.encode('ascii', errors='ignore') print i+1,after.encode('ascii', errors='ignore') os.rename(before, after) except Exception as e: traceback.print_exc() #will output any errors to console but keep going torrentlist[key]["path"] = after if after.endswith(".mp3") or after.endswith(".flac"): #.mp3 .flac = I personally didnt have any "Single file" .ogg, .aac, etc that needed special handling in this manner if torrentlist[key].has_key("targets"): #these lines are a quick fix, for an oversight in the uTorrent process. changing path is not enough torrentlist[key]["targets"][0][1] = after[after.rfind("\\")+1:] #single-file-mode torrents have a "targets" list that controls the filename torrentlist["rec"]=rec #add the thing we removed back in so we dont break anything (not sure what this is) #fileguard does not need to go back, in fact, purposefully needs to stay out. newfile.write(bencode.bencode(torrentlist)) newfile.close() print "Finished writing: ", newfile.name
def find_peer(self, id, node): query = self.query_head("find_node") query["a"] = dict(id=id, target=node) return bencode(query)
def __send_metadata_request(self, extension_id, piece): msg_data = bencode({"msg_type": 0, "piece": piece}) self.__send( (pack("!I", len(msg_data) + 2) + chr(20) + chr(extension_id) + msg_data))
def write_torrent_file(torrent_dict, output_file_path): """ Bencodes, then writes the torrent file to disk. """ with open(output_file_path, 'wb') as file_handle: file_handle.write(bencode(torrent_dict))
def get_info_hash(info_dict): """ Calculates the hash of the info dictionary. """ return sha1(bencode(info_dict)).hexdigest()
def save_dfile(self): self.rawserver.add_task(self.save_dfile, self.save_dfile_interval) h = open(self.dfile, 'wb') h.write(bencode(self.state)) h.close()
def transfer_torrent(a_url): t_hash = a_url.split('/')[-1] t_html = requests.get(a_url).content # Announce list for trackers announce_id = re.findall( r'href=.([^>]+)["\']', t_html.split('This lists all the active trackers', 1)[1].split('compatible list here', 1)[0])[0].split('announcelist_', 1)[-1] announce_url = 'http://torrentz.eu/announcelist_%s' % announce_id alt_trackers = requests.get(announce_url).content alt_trackers = [x.strip() for x in alt_trackers.split('\n') if x.strip()] # Slice out the downloads downloads = t_html.split('<div class="download">', 1)[-1].split('<div class="trackers">', 1)[0] downloads = [ x for x in downloads.split('<dl><dt>')[1:] if '<dd>Sponsored Link</dd>' not in x ] downloads = [re.findall('^.+(http://[^"\']+)', x)[0] for x in downloads] # Filter out sites that don't give obvious direct links to .torrent files site_blacklist = set([ 'www.torrenthound.com', 'www.houndmirror.com', 'www.torrentreactor.net', 'www.limetorrents.com', 'www.monova.org', 'www.torrentcrazy.com' ]) downloads = [ x for x in downloads if re.findall('//([^/]+)', x)[0] not in site_blacklist ] # Limit it to just 10 sites to visit downloads = downloads[:10] # Need some formulas # Try a generic link extraction, should be enough - we just need *a* torrent torrent_files = set() for a_site in downloads: print "> Getting:", a_site a_site_html = requests.get(a_site).content torrent_files.update( set([ x for x in re.findall( r'<a [^>]*href=["\'](http:[^"\'>]+\.torrent[^"\'>]*)["\']', a_site_html) if t_hash in x.lower() ])) torrent_files = sorted(torrent_files) # Filter out malware downloads malware_blacklist = set(['clickdownloader.com']) torrent_files = [ x for x in torrent_files if re.findall('//[^/]*?([^/.]+[.][^/.]+)/', x) [0] not in malware_blacklist ] # Keep only URLs for domains 'known good' to direct download so far site_whitelist = set(['torcache.net']) whitelist_torrent_files = [ x for x in torrent_files if re.findall('//([^/]+)', x)[0] in site_whitelist ] # Check if we have at least one good URL if not whitelist_torrent_files: print "Error: No whitelisted download locations found" print "Downloads:", torrent_files.__repr__() print "Sites:", downloads.__repr__() return # We're only here if we have at least one confirmed direct downloadable .torrent URL target_tor = whitelist_torrent_files[0] print '\n*** Downloading .torrent:', target_tor # Get the contents of the .torrent file print '*** Modifying .torrent ...' bcode = requests.get(target_tor).content bdict = bencode.bdecode(bcode) # Get the announce-list - should be a list of lists b_announce = bdict.get('announce-list', []) # Need to flatten the list and inject our own alt_trackers, using that trick b_announce = [y for x in b_announce for y in x] # Combine in our alt_trackers and reset to unique and sorted b_announce = sorted(set(b_announce + alt_trackers)) # Split and re-set with udp:// URLs first - and filter out non-sense urls, potentially http_t, udp_t = [ x for x in b_announce if x.lower().startswith('http://') ], [x for x in b_announce if x.lower().startswith('udp://')] b_announce = udp_t + http_t # Refashion into list wrapped items b_announce = [[x] for x in b_announce] # Set the announce-list to the new value bdict['announce-list'] = b_announce # Form a newly encoded torrent file new_torrent = bencode.bencode(bdict) # Save the output to a tempfile temp_tor = tempfile.TemporaryFile() temp_tor.write(new_torrent) temp_tor.seek(0) # Upload the file to Dropbox print '*** Uploading .torrent:', t_hash + '.torrent' response = dropbox_client.put_file('/%s.torrent' % t_hash, temp_tor) # Release the tempfile temp_tor.close() # Get the sharing URL print '*** Getting share link ...' share_info = dropbox_client.share('/%s.torrent' % t_hash, short_url=False) share_url = share_info['url'] # Fake download it at least once so Dropbox is famliar with our IP address (probably unnecessary) _ = requests.get(share_url).content[0:0] # Update the URL to include the direct download action share_url += '?dl=1' # Now to send this URL onto the web interface ... rpc_id = requests.get(rpc_url).headers['x-transmission-session-id'] headers = { 'Content-Type': 'application/json', 'Accept': '*/*', 'X-Requested-With': 'XMLHttpRequest', 'X-Transmission-Session-Id': rpc_id } payload = {'method': 'torrent-add', 'arguments': {'filename': share_url}} print '*** Transferring to Transmission ...' r_upload = requests.post(rpc_url, data=json.dumps(payload), headers=headers) r_response = json.loads(r_upload.content) print r_response.__repr__() print "DONE !"
class Tracker: def __init__(self, config, rawserver): self.response_size = config['response_size'] self.dfile = config['dfile'] self.natcheck = config['nat_check'] self.max_give = config['max_give'] self.reannounce_interval = config['reannounce_interval'] self.save_dfile_interval = config['save_dfile_interval'] self.show_names = config['show_names'] self.only_local_override_ip = config['only_local_override_ip'] favicon = config['favicon'] self.favicon = None if favicon: try: h = open(favicon, 'rb') self.favicon = h.read() h.close() except: print "**warning** specified favicon file -- %s -- does not exist." % favicon self.rawserver = rawserver self.becache1 = {} self.becache2 = {} self.cache1 = {} self.cache2 = {} self.times = {} if exists(self.dfile): h = open(self.dfile, 'rb') ds = h.read() h.close() tempstate = bdecode(ds) else: tempstate = {} if tempstate.has_key('peers'): self.state = tempstate else: self.state = {} self.state['peers'] = tempstate self.downloads = self.state.setdefault('peers', {}) self.completed = self.state.setdefault('completed', {}) statefiletemplate(self.state) for x, dl in self.downloads.items(): self.times[x] = {} for y, dat in dl.items(): self.times[x][y] = 0 if not dat.get('nat', 1): ip = dat['ip'] gip = dat.get('given ip') if gip and is_valid_ipv4(gip) and ( not self.only_local_override_ip or is_local_ip(ip)): ip = gip self.becache1.setdefault(x, {})[y] = Bencached( bencode({ 'ip': ip, 'port': dat['port'], 'peer id': y })) self.becache2.setdefault(x, {})[y] = compact_peer_info( ip, dat['port']) rawserver.add_task(self.save_dfile, self.save_dfile_interval) self.prevtime = time() self.timeout_downloaders_interval = config[ 'timeout_downloaders_interval'] rawserver.add_task(self.expire_downloaders, self.timeout_downloaders_interval) self.logfile = None self.log = None if (config['logfile'] != '') and (config['logfile'] != '-'): try: self.logfile = config['logfile'] self.log = open(self.logfile, 'a') sys.stdout = self.log print "# Log Started: ", isotime() except: print "Error trying to redirect stdout to log file:", sys.exc_info( )[0] self.allow_get = config['allow_get'] if config['allowed_dir'] != '': self.allowed_dir = config['allowed_dir'] self.parse_allowed_interval = config['parse_allowed_interval'] self.parse_allowed() else: self.allowed = None if unquote('+') != ' ': self.uq_broken = 1 else: self.uq_broken = 0 self.keep_dead = config['keep_dead'] def get_infopage(self): if not self.config['show_infopage']: return (404, 'Not Found', { 'Content-Type': 'text/plain', 'Pragma': 'no-cache' }, alas) red = self.config['infopage_redirect'] if red != '': return (302, 'Found', { 'Content-Type': 'text/html', 'Location': red }, '<A HREF="' + red + '">Click Here</A>') s = StringIO() s.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n' \ '<html><head><title>BitTorrent download info</title>\n') if self.favicon != None: s.write('<link rel="shortcut icon" href="/favicon.ico" />\n') s.write('</head>\n<body>\n' \ '<h3>BitTorrent download info</h3>\n'\ '<ul>\n' '<li><strong>tracker version:</strong> %s</li>\n' \ '<li><strong>server time:</strong> %s</li>\n' \ '</ul>\n' % (version, isotime())) names = self.downloads.keys() if not names: s.write('<p>not tracking any files yet...</p>\n') else: names.sort() tn = 0 tc = 0 td = 0 tt = 0 # Total transferred ts = 0 # Total size nf = 0 # Number of files displayed uc = {} ud = {} if self.allowed != None and self.show_names: s.write('<table summary="files" border="1">\n' \ '<tr><th>info hash</th><th>torrent name</th><th align="right">size</th><th align="right">complete</th><th align="right">downloading</th><th align="right">downloaded</th><th align="right">transferred</th></tr>\n') else: s.write('<table summary="files">\n' \ '<tr><th>info hash</th><th align="right">complete</th><th align="right">downloading</th><th align="right">downloaded</th></tr>\n') for name in names: l = self.downloads[name] n = self.completed.get(name, 0) tn = tn + n lc = [] for i in l.values(): if type(i) == DictType: if i['left'] == 0: lc.append(1) uc[i['ip']] = 1 else: ud[i['ip']] = 1 c = len(lc) tc = tc + c d = len(l) - c td = td + d if self.allowed != None and self.show_names: if self.allowed.has_key(name): nf = nf + 1 sz = self.allowed[name]['length'] # size ts = ts + sz szt = sz * n # Transferred for this torrent tt = tt + szt if self.allow_get == 1: linkname = '<a href="/file?info_hash=' + quote( name ) + '">' + self.allowed[name]['name'] + '</a>' else: linkname = self.allowed[name]['name'] s.write('<tr><td><code>%s</code></td><td>%s</td><td align="right">%s</td><td align="right">%i</td><td align="right">%i</td><td align="right">%i</td><td align="right">%s</td></tr>\n' \ % (b2a_hex(name), linkname, size_format(sz), c, d, n, size_format(szt))) else: s.write('<tr><td><code>%s</code></td><td align="right"><code>%i</code></td><td align="right"><code>%i</code></td><td align="right"><code>%i</code></td></tr>\n' \ % (b2a_hex(name), c, d, n)) ttn = 0 for i in self.completed.values(): ttn = ttn + i if self.allowed != None and self.show_names: s.write( '<tr><td align="right" colspan="2">%i files</td><td align="right">%s</td><td align="right">%i/%i</td><td align="right">%i/%i</td><td align="right">%i/%i</td><td align="right">%s</td></tr>\n' % (nf, size_format(ts), len(uc), tc, len(ud), td, tn, ttn, size_format(tt))) else: s.write( '<tr><td align="right">%i files</td><td align="right">%i/%i</td><td align="right">%i/%i</td><td align="right">%i/%i</td></tr>\n' % (nf, len(uc), tc, len(ud), td, tn, ttn)) s.write('</table>\n' \ '<ul>\n' \ '<li><em>info hash:</em> SHA1 hash of the "info" section of the metainfo (*.torrent)</li>\n' \ '<li><em>complete:</em> number of connected clients with the complete file (total: unique IPs/total connections)</li>\n' \ '<li><em>downloading:</em> number of connected clients still downloading (total: unique IPs/total connections)</li>\n' \ '<li><em>downloaded:</em> reported complete downloads (total: current/all)</li>\n' \ '<li><em>transferred:</em> torrent size * total downloaded (does not include partial transfers)</li>\n' \ '</ul>\n') s.write('</body>\n' \ '</html>\n') return (200, 'OK', { 'Content-Type': 'text/html; charset=iso-8859-1' }, s.getvalue()) def scrapedata(self, name, return_name=True): l = self.downloads[name] n = self.completed.get(name, 0) c = len([1 for i in l.values() if i['left'] == 0]) d = len(l) - c f = {'complete': c, 'incomplete': d, 'downloaded': n} if (return_name and self.show_names and self.allowed is not None and self.allowed.has_key(name)): f['name'] = self.allowed[name]['name'] return (f) def get_scrape(self, paramslist): fs = {} if paramslist.has_key('info_hash'): if self.config['scrape_allowed'] not in ['specific', 'full']: return ( 400, 'Not Authorized', { 'Content-Type': 'text/plain', 'Pragma': 'no-cache' }, bencode({ 'failure reason': 'specific scrape function is not available with this tracker.' })) for infohash in paramslist['info_hash']: if infohash in self.downloads.keys(): fs[infohash] = self.scrapedata(infohash) else: if self.config['scrape_allowed'] != 'full': return ( 400, 'Not Authorized', { 'Content-Type': 'text/plain', 'Pragma': 'no-cache' }, bencode({ 'failure reason': 'full scrape function is not available with this tracker.' })) names = self.downloads.keys() names.sort() for name in names: fs[name] = self.scrapedata(name) return (200, 'OK', { 'Content-Type': 'text/plain' }, bencode({'files': fs})) def get(self, connection, path, headers): try: (scheme, netloc, path, pars, query, fragment) = urlparse(path) if self.uq_broken == 1: path = path.replace('+', ' ') query = query.replace('+', ' ') path = unquote(path)[1:] paramslist = {} params = {} for s in query.split('&'): if s != '': i = s.index('=') kw = unquote(s[:i]) key, value = unquote(s[:i]), unquote(s[i + 1:]) paramslist.setdefault(key, []).append(value) params[key] = value except ValueError, e: return (400, 'Bad Request', { 'Content-Type': 'text/plain' }, 'you sent me garbage - ' + str(e)) if path == '' or path == 'index.html': return self.get_infopage() elif path == 'scrape': return self.get_scrape(paramslist) elif (path == 'file') and (self.allow_get == 1) and params.has_key( 'info_hash') and self.allowed.has_key(params['info_hash']): hash = params['info_hash'] fname = self.allowed[hash]['file'] fpath = self.allowed[hash]['path'] return (200, 'OK', { 'Content-Type': 'application/x-bittorrent', 'Content-Disposition': 'attachment; filename=' + fname }, open(fpath, 'rb').read()) elif path == 'favicon.ico' and self.favicon != None: return (200, 'OK', {'Content-Type': 'image/x-icon'}, self.favicon) if path != 'announce': return (404, 'Not Found', { 'Content-Type': 'text/plain', 'Pragma': 'no-cache' }, alas) try: if not params.has_key('info_hash'): raise ValueError, 'no info hash' if params.has_key('ip') and not is_valid_ipv4(params['ip']): raise ValueError('DNS name or invalid IP address given for IP') infohash = params['info_hash'] if self.allowed != None: if not self.allowed.has_key(infohash): return ( 200, 'OK', { 'Content-Type': 'text/plain', 'Pragma': 'no-cache' }, bencode({ 'failure reason': 'Requested download is not authorized for use with this tracker.' })) ip = connection.get_ip() ip_override = 0 if params.has_key('ip') and is_valid_ipv4( params['ip']) and (not self.only_local_override_ip or is_local_ip(ip)): ip_override = 1 if params.has_key('event') and params['event'] not in [ 'started', 'completed', 'stopped' ]: raise ValueError, 'invalid event' port = long(params.get('port', '')) uploaded = long(params.get('uploaded', '')) downloaded = long(params.get('downloaded', '')) left = long(params.get('left', '')) myid = params.get('peer_id', '') if len(myid) != 20: raise ValueError, 'id not of length 20' rsize = self.response_size if params.has_key('numwant'): rsize = min(long(params['numwant']), self.max_give) except ValueError, e: return (400, 'Bad Request', { 'Content-Type': 'text/plain' }, 'you sent me garbage - ' + str(e))
def __init__(self, config, rawserver): self.response_size = config['response_size'] self.dfile = config['dfile'] self.natcheck = config['nat_check'] self.max_give = config['max_give'] self.reannounce_interval = config['reannounce_interval'] self.save_dfile_interval = config['save_dfile_interval'] self.show_names = config['show_names'] self.only_local_override_ip = config['only_local_override_ip'] favicon = config['favicon'] self.favicon = None if favicon: try: h = open(favicon, 'rb') self.favicon = h.read() h.close() except: print "**warning** specified favicon file -- %s -- does not exist." % favicon self.rawserver = rawserver self.becache1 = {} self.becache2 = {} self.cache1 = {} self.cache2 = {} self.times = {} if exists(self.dfile): h = open(self.dfile, 'rb') ds = h.read() h.close() tempstate = bdecode(ds) else: tempstate = {} if tempstate.has_key('peers'): self.state = tempstate else: self.state = {} self.state['peers'] = tempstate self.downloads = self.state.setdefault('peers', {}) self.completed = self.state.setdefault('completed', {}) statefiletemplate(self.state) for x, dl in self.downloads.items(): self.times[x] = {} for y, dat in dl.items(): self.times[x][y] = 0 if not dat.get('nat', 1): ip = dat['ip'] gip = dat.get('given ip') if gip and is_valid_ipv4(gip) and ( not self.only_local_override_ip or is_local_ip(ip)): ip = gip self.becache1.setdefault(x, {})[y] = Bencached( bencode({ 'ip': ip, 'port': dat['port'], 'peer id': y })) self.becache2.setdefault(x, {})[y] = compact_peer_info( ip, dat['port']) rawserver.add_task(self.save_dfile, self.save_dfile_interval) self.prevtime = time() self.timeout_downloaders_interval = config[ 'timeout_downloaders_interval'] rawserver.add_task(self.expire_downloaders, self.timeout_downloaders_interval) self.logfile = None self.log = None if (config['logfile'] != '') and (config['logfile'] != '-'): try: self.logfile = config['logfile'] self.log = open(self.logfile, 'a') sys.stdout = self.log print "# Log Started: ", isotime() except: print "Error trying to redirect stdout to log file:", sys.exc_info( )[0] self.allow_get = config['allow_get'] if config['allowed_dir'] != '': self.allowed_dir = config['allowed_dir'] self.parse_allowed_interval = config['parse_allowed_interval'] self.parse_allowed() else: self.allowed = None if unquote('+') != ' ': self.uq_broken = 1 else: self.uq_broken = 0 self.keep_dead = config['keep_dead']
def request_metadata(self): msgcode = self._remote_extension_handshake['m']['ut_metadata'] self._meta_requested = True sz = self._remote_extension_handshake['metadata_size'] chunksz = 2**14 #request blocks... msg_types = { 'REQUEST': 0, 'DATA': 1, 'REJECT': 2 } for chunk in range(int( math.ceil(float(sz) / chunksz) )): offset = chunk * chunksz msg = {'msg_type': msg_types['REQUEST'], 'piece': chunk} self.send_message('UTORRENT_MSG', chr(self._remote_extension_handshake['m']['ut_metadata']) + bencode.bencode(msg))
'Content-Type': 'text/plain' }, 'you sent me garbage - ' + str(e)) peers = self.downloads.setdefault(infohash, {}) self.completed.setdefault(infohash, 0) ts = self.times.setdefault(infohash, {}) confirm = 0 if peers.has_key(myid): myinfo = peers[myid] if myinfo.has_key('key'): if params.get('key') != myinfo['key']: return (200, 'OK', { 'Content-Type': 'text/plain', 'Pragma': 'no-cache' }, bencode({ 'failure reason': 'key did not match key supplied earlier' })) confirm = 1 elif myinfo['ip'] == ip: confirm = 1 else: confirm = 1 if params.get('event', '') != 'stopped' and confirm: ts[myid] = time() if not peers.has_key(myid): peers[myid] = {'ip': ip, 'port': port, 'left': left} if params.has_key('key'): peers[myid]['key'] = params['key'] if params.has_key('ip') and is_valid_ipv4(params['ip']): peers[myid]['given ip'] = params['ip'] mip = ip
def download(self, data = None, media = None, filedata = None): """ Send a torrent/nzb file to the downloader :param data: dict returned from provider Contains the release information :param media: media dict with information Used for creating the filename when possible :param filedata: downloaded torrent/nzb filedata The file gets downloaded in the searcher and send to this function This is done to have failed checking before using the downloader, so the downloader doesn't need to worry about that :return: boolean One faile returns false, but the downloaded should log his own errors """ if not media: media = {} if not data: data = {} log.debug('Sending "%s" to rTorrent.', (data.get('name'))) if not self.connect(): return False torrent_params = {} if self.conf('label'): torrent_params['label'] = self.conf('label') if not filedata and data.get('protocol') == 'torrent': log.error('Failed sending torrent, no data') return False # Try download magnet torrents if data.get('protocol') == 'torrent_magnet': filedata = self.magnetToTorrent(data.get('url')) if filedata is False: return False data['protocol'] = 'torrent' info = bdecode(filedata)["info"] torrent_hash = sha1(bencode(info)).hexdigest().upper() # Convert base 32 to hex if len(torrent_hash) == 32: torrent_hash = b16encode(b32decode(torrent_hash)) # Send request to rTorrent try: # Send torrent to rTorrent torrent = self.rt.load_torrent(filedata, verify_retries=10) if not torrent: log.error('Unable to find the torrent, did it fail to load?') return False # Set label if self.conf('label'): torrent.set_custom(1, self.conf('label')) if self.conf('directory'): torrent.set_directory(self.conf('directory')) # Start torrent if not self.conf('paused', default = 0): torrent.start() return self.downloadReturnId(torrent_hash) except Exception as err: log.error('Failed to send torrent to rTorrent: %s', err) return False
def get_info_hash_from_data(torrent_data): metainfo = bencode.bdecode(torrent_data) info = metainfo['info'] return hashlib.sha1(bencode.bencode(info)).hexdigest().upper()
def error_message(self, code, msg): resp = {"t": "aa", "y": "e", "e": [code, msg]} return bencode(resp)
def get_peers(self, id, torrent): query = self.query_head("get_peers") query["a"] = dict(id=id, info_hash=torrent) return bencode(query)
def request_metadata(the_socket, ut_metadata, piece): """bep_0009""" msg = chr(BT_MSG_ID) + chr(ut_metadata) + bencode({"msg_type": 0, "piece": piece}) send_message(the_socket, msg)
def send_ext_handshake(the_socket): msg = chr(BT_MSG_ID) + chr(EXT_HANDSHAKE_ID) + bencode( {"m": { "ut_metadata": 1 }}) send_message(the_socket, msg)