import asyncio import logging import typing log = logging.getLogger(__name__) class TorrentInfo: __slots__ = ('dht_seeds', 'http_seeds', 'trackers', 'total_size') def __init__(self, dht_seeds: typing.Tuple[typing.Tuple[str, int]], http_seeds: typing.Tuple[typing.Dict[str, typing.Any]], trackers: typing.Tuple[typing.Tuple[str, int]], total_size: int): self.dht_seeds = dht_seeds self.http_seeds = http_seeds self.trackers = trackers self.total_size = total_size @classmethod def from_libtorrent_info(cls, torrent_info): return cls( torrent_info.nodes(), tuple( { 'url': web_seed['url'], 'type': web_seed['type'], 'auth': web_seed['auth'] } for web_seed in torrent_info.web_seeds() ), tuple( (tracker.url, tracker.tier) for tracker in torrent_info.trackers() ), torrent_info.total_size() ) class Torrent: def __init__(self, loop, handle): self._loop = loop self._handle = handle self.finished = asyncio.Event(loop=loop) def _threaded_update_status(self): status = self._handle.status() if not status.is_seeding: log.info( '%.2f%% complete (down: %.1f kB/s up: %.1f kB/s peers: %d) %s', status.progress * 100, status.download_rate / 1000, status.upload_rate / 1000, status.num_peers, status.state ) elif not self.finished.is_set(): self.finished.set() async def wait_for_finished(self): while True: await self._loop.run_in_executor( None, self._threaded_update_status ) if self.finished.is_set(): log.info("finished downloading torrent!") await self.pause() break await asyncio.sleep(1, loop=self._loop) async def pause(self): log.info("pause torrent") await self._loop.run_in_executor( None, self._handle.pause ) async def resume(self): await self._loop.run_in_executor( None, self._handle.resume )