def start_url(self, uri): if self._th: raise Exception('Torrent is already started') if uri.startswith('http://') or uri.startswith('https://'): self._url = uri stored = self._cache.get_torrent(url=uri) if stored: tp = self.info_from_file(stored) else: tp = {'url': uri} resume_data = self._cache.get_resume(url=uri) if resume_data: tp['resume_data'] = resume_data elif uri.startswith('magnet:'): self._url = uri stored = self._cache.get_torrent(info_hash=CacheBT.hash_from_magnet(uri)) if stored: tp = self.info_from_file(stored) else: tp = {'url': uri} resume_data = self._cache.get_resume(info_hash=CacheBT.hash_from_magnet(uri)) if resume_data: tp['resume_data'] = resume_data elif os.path.isfile(uri): tp = self.info_from_file(uri) else: raise ValueError("Invalid torrent %s" % uri) tp.update(self._torrent_params) self._th = self._ses.add_torrent(tp) for tr in INITIAL_TRACKERS: self._th.add_tracker({'url': tr}) self._th.set_sequential_download(True) time.sleep(1) self._th.force_dht_announce() self._monitor.start() self._dispatcher.do_start(self._th, self._ses)
def __init__(self, path_to_store, args=None, state_file="", lt=None, **kwargs): super(BTClient, self).__init__(path_to_store, args=args) self.lt=lt self._cache = CacheBT(path_to_store, self.lt) self._torrent_params = {'save_path': path_to_store, 'storage_mode': self.lt.storage_mode_t.storage_mode_sparse } if not state_file: state_file=os.path.join(path_to_store,'.btclient_state') self._state_file = os.path.expanduser(state_file) self._ses = self.lt.session() if os.path.exists(self._state_file): with open(self._state_file) as f: state = pickle.load(f) self._ses.load_state(state) # self._ses.set_alert_mask(self.lt.alert.category_t.progress_notification) if args: s = self._ses.get_settings() s['download_rate_limit'] = int(round(args.bt_download_limit * 1024)) s['upload_rate_limit'] = int(round(args.bt_upload_limit * 1024)) self._ses.set_settings(s) self._ses.listen_on(args.listen_port_min, args.listen_port_max) self.content_id=args.content_id else: self._ses.listen_on(6881, 6891) self._start_services() self._th = None self._monitor.add_listener(self._check_ready) self._dispatcher = BTClient.Dispatcher(self, lt=self.lt) self._dispatcher.add_listener(self._update_ready_pieces) self._hash = None self._url = None if args and args.debug_log and args.trace: self.add_monitor_listener(self.debug_download_queue) self.add_dispatcher_listener(self.debug_alerts)
class BTClient(BaseClient): def __init__(self, path_to_store, args=None, state_file="", lt=None, **kwargs): super(BTClient, self).__init__(path_to_store, args=args) self.lt=lt self._cache = CacheBT(path_to_store, self.lt) self._torrent_params = {'save_path': path_to_store, 'storage_mode': self.lt.storage_mode_t.storage_mode_sparse } if not state_file: state_file=os.path.join(path_to_store,'.btclient_state') self._state_file = os.path.expanduser(state_file) self._ses = self.lt.session() if os.path.exists(self._state_file): with open(self._state_file) as f: state = pickle.load(f) self._ses.load_state(state) # self._ses.set_alert_mask(self.lt.alert.category_t.progress_notification) if args: s = self._ses.get_settings() s['download_rate_limit'] = int(round(args.bt_download_limit * 1024)) s['upload_rate_limit'] = int(round(args.bt_upload_limit * 1024)) self._ses.set_settings(s) self._ses.listen_on(args.listen_port_min, args.listen_port_max) self.content_id=args.content_id else: self._ses.listen_on(6881, 6891) self._start_services() self._th = None self._monitor.add_listener(self._check_ready) self._dispatcher = BTClient.Dispatcher(self, lt=self.lt) self._dispatcher.add_listener(self._update_ready_pieces) self._hash = None self._url = None if args and args.debug_log and args.trace: self.add_monitor_listener(self.debug_download_queue) self.add_dispatcher_listener(self.debug_alerts) @property def is_file_complete(self): pcs = self._th.status().pieces[self._file.first_piece:self._file.last_piece + 1] return all(pcs) def _update_ready_pieces(self, alert_type, alert): if alert_type == 'read_piece_alert' and self._file: self._file.update_piece(alert.piece, alert.buffer) def _check_ready(self, s, **kwargs): if s.state in [3, 4, 5] and not self._file and s.progress > 0: try: self._meta_ready(self._th.torrent_file()) except: self._meta_ready(self._th.get_torrent_info()) logger.debug('Got torrent metadata and start download') self.hash = True self.hash = Hasher(self._file, self._on_file_ready) def _choose_file(self, files, i): if not i and i!=0: videos = filter(lambda f: VIDEO_EXTS.has_key(os.path.splitext(f.path)[1]), files) if not videos: raise Exception('No video files in torrent') f = sorted(videos, key=lambda f: f.size)[-1] i = files.index(f) f.index = i f=files[i] f.index = i return f def _meta_ready(self, meta): fs = meta.files() files = fs if isinstance(fs, list) else [fs.at(i) for i in xrange(fs.num_files())] f = self._choose_file(files, self.content_id) fmap = meta.map_file(f.index, 0, 1) self._file = BTFile(f.path, self._base_path, f.index, f.size, fmap, meta.piece_length(), self.prioritize_piece) self.prioritize_file() print ('File %s pieces (pc=%d, ofs=%d, sz=%d), total_pieces=%d, pc_length=%d' % (f.path, fmap.piece, fmap.start, fmap.length, meta.num_pieces(), meta.piece_length())) try: meta = self._th.torrent_file() except: meta=self._th.get_torrent_info() self._cache.file_complete(meta, self._url if self._url and self._url.startswith('http') else None) def prioritize_piece(self, pc, idx): piece_duration = 1000 min_deadline = 2000 dl = idx * piece_duration + min_deadline self._th.set_piece_deadline(pc, dl, self.lt.deadline_flags.alert_when_available) logger.debug("Set deadline %d for piece %d", dl, pc) # we do not need to download pieces that are lower then current index, but last two pieces are special because players sometime look at end of file if idx == 0 and (self._file.last_piece - pc) > 2: for i in xrange(pc - 1): self._th.piece_priority(i, 0) self._th.reset_piece_deadline(i) def prioritize_file(self): try: meta = self._th.torrent_file() except: meta=self._th.get_torrent_info() priorities = [1 if i >= self._file.first_piece and i <= self.file.last_piece else 0 \ for i in xrange(meta.num_pieces())] self._th.prioritize_pieces(priorities) def encrypt(self): # Encryption settings print 'Encryption enabling...' try: encryption_settings = self.lt.pe_settings() encryption_settings.out_enc_policy = self.lt.enc_policy(self.lt.enc_policy.forced) encryption_settings.in_enc_policy = self.lt.enc_policy(self.lt.enc_policy.forced) encryption_settings.allowed_enc_level = self.lt.enc_level.both encryption_settings.prefer_rc4 = True self._ses.set_pe_settings(encryption_settings) print 'Encryption on!' except Exception, e: print 'Encryption failed! Exception: ' + str(e) pass