class TorrentService:
    def __init__(self, address, port, username, password):
        self.client = Client(address=address,
                             port=port,
                             username=username,
                             password=password)

    def torrent_icon(self, status):
        if status == 'stopped':
            return '⏹'
        else:
            return '▶️'

    def torrent_description(self, torrent):
        return '{} {} {:01.0f}%, {}'.format(self.torrent_icon(torrent.status),
                                            torrent.status, torrent.progress,
                                            torrent.name)

    def add_torrent(self, url, path):
        tor = self.client.add_torrent(url, download_dir=path)
        return tor.name

    def torrent_list(self, update, context):
        torrents = self.client.get_torrents()
        torrents = sorted(torrents, key=lambda i: i.queue_position)
        keyboard = []
        for torrent in torrents:
            tname = self.torrent_description(torrent)
            keyboard.append([
                InlineKeyboardButton(tname,
                                     callback_data='t_info_{}'.format(
                                         torrent.id))
            ])
        keyboard.append(
            [InlineKeyboardButton('✕ Cancel', callback_data='cancel')])
        reply_markup = InlineKeyboardMarkup(keyboard)
        update.message.reply_text(text='Torrents', reply_markup=reply_markup)
        return TORRENTLIST

    def torrent_info(self, update, context):
        query = update.callback_query
        tid = re.search('^t_info_(\d+?)$', query.data).group(1)
        tor = self.client.get_torrent(tid)
        stop_resume = []
        if tor.status == 'stopped':
            stop_resume = [
                InlineKeyboardButton('▷ Resume',
                                     callback_data='t_resume_{}'.format(tid)),
                InlineKeyboardButton(
                    '▶︎ Resume now',
                    callback_data='t_resume_now_{}'.format(tid))
            ]
        elif tor.status == 'download pending':
            stop_resume = [
                InlineKeyboardButton(
                    '▶︎ Resume now',
                    callback_data='t_resume_now_{}'.format(tid)),
                InlineKeyboardButton('◼︎ Stop',
                                     callback_data='t_stop_{}'.format(tid))
            ]
        else:
            stop_resume = [
                InlineKeyboardButton('◼︎ Stop',
                                     callback_data='t_stop_{}'.format(tid))
            ]
        keyboard = [[
            InlineKeyboardButton('▲ Top',
                                 callback_data='t_top_{}'.format(tid)),
            InlineKeyboardButton('△ Up', callback_data='t_up_{}'.format(tid)),
            InlineKeyboardButton('▽ Down',
                                 callback_data='t_down_{}'.format(tid)),
            InlineKeyboardButton('▼ Bottom',
                                 callback_data='t_bottom_{}'.format(tid))
        ], stop_resume,
                    [
                        InlineKeyboardButton(
                            '◉ Verify',
                            callback_data='t_verify_{}'.format(tid))
                    ],
                    [
                        InlineKeyboardButton(
                            '☒ Remove',
                            callback_data='t_remove_confirm_{}'.format(tid))
                    ],
                    [InlineKeyboardButton('✕ Cancel', callback_data='cancel')]]
        reply_markup = InlineKeyboardMarkup(keyboard)
        bot = context.bot
        bot.edit_message_text(chat_id=query.message.chat_id,
                              message_id=query.message.message_id,
                              reply_markup=reply_markup,
                              text=self.torrent_description(tor))

        return TORRENTINFO

    def move_up(self, update, context):
        query = update.callback_query
        tid = re.search('^t_up_(\d+?)$', query.data).group(1)
        self.client.queue_up(tid)
        tor = self.client.get_torrent(tid)
        context.bot.edit_message_text(chat_id=query.message.chat_id,
                                      message_id=query.message.message_id,
                                      text='{} has been moved up'.format(
                                          tor.name))
        return ConversationHandler.END

    def move_down(self, update, context):
        query = update.callback_query
        tid = re.search('^t_down_(\d+?)$', query.data).group(1)
        self.client.queue_down(tid)
        tor = self.client.get_torrent(tid)
        context.bot.edit_message_text(chat_id=query.message.chat_id,
                                      message_id=query.message.message_id,
                                      text='{} has been moved down'.format(
                                          tor.name))
        return ConversationHandler.END

    def move_top(self, update, context):
        query = update.callback_query
        tid = re.search('^t_top_(\d+?)$', query.data).group(1)
        self.client.queue_top(tid)
        tor = self.client.get_torrent(tid)
        context.bot.edit_message_text(chat_id=query.message.chat_id,
                                      message_id=query.message.message_id,
                                      text='{} has been moved to top'.format(
                                          tor.name))
        return ConversationHandler.END

    def move_bottom(self, update, context):
        query = update.callback_query
        tid = re.search('^t_bottom_(\d+?)$', query.data).group(1)
        self.client.queue_bottom(tid)
        tor = self.client.get_torrent(tid)
        context.bot.edit_message_text(
            chat_id=query.message.chat_id,
            message_id=query.message.message_id,
            text='{} has been moved to bottom'.format(tor.name))
        return ConversationHandler.END

    def stop_torrent(self, update, context):
        tid = re.search('^t_stop_(\d+?)$', update.callback_query.data).group(1)
        tor = self.client.get_torrent(tid)
        self.client.stop_torrent(tid)
        context.bot.edit_message_text(
            chat_id=update.callback_query.message.chat_id,
            message_id=update.callback_query.message.message_id,
            text='{} has been stopped'.format(tor.name))
        return ConversationHandler.END

    def resume_torrent(self, update, context):
        tid = re.search('^t_resume_(\d+?)$',
                        update.callback_query.data).group(1)
        tor = self.client.get_torrent(tid)
        self.client.start_torrent(tid)
        context.bot.edit_message_text(
            chat_id=update.callback_query.message.chat_id,
            message_id=update.callback_query.message.message_id,
            text='{} has been resumed'.format(tor.name))
        return ConversationHandler.END

    def resume_torrent_now(self, update, context):
        tid = re.search('^t_resume_now_(\d+?)$',
                        update.callback_query.data).group(1)
        tor = self.client.get_torrent(tid)
        self.client.start_torrent(tid, bypass_queue=True)
        context.bot.edit_message_text(
            chat_id=update.callback_query.message.chat_id,
            message_id=update.callback_query.message.message_id,
            text='{} has been resumed'.format(tor.name))
        return ConversationHandler.END

    def verify_torrent(self, update, context):
        tid = re.search('^t_verify_(\d+?)$',
                        update.callback_query.data).group(1)
        tor = self.client.get_torrent(tid)
        self.client.verify_torrent(tid)
        context.bot.edit_message_text(
            chat_id=update.callback_query.message.chat_id,
            message_id=update.callback_query.message.message_id,
            text='{} verification has been started'.format(tor.name))
        return ConversationHandler.END

    def remove_torrent_confirm(self, update, context):
        tid = re.search('^t_remove_confirm_(\d+?)$',
                        update.callback_query.data).group(1)
        tor = self.client.get_torrent(tid)
        keyboard = [[
            InlineKeyboardButton('☒ Remove torrent',
                                 callback_data='t_remove_{}'.format(tid))
        ],
                    [
                        InlineKeyboardButton(
                            '⌧ Remove torrent and delete files',
                            callback_data='t_remove_complete_{}'.format(tid))
                    ],
                    [InlineKeyboardButton('✕ Cancel', callback_data='cancel')]]
        reply_markup = InlineKeyboardMarkup(keyboard)
        context.bot.edit_message_text(
            chat_id=update.callback_query.message.chat_id,
            message_id=update.callback_query.message.message_id,
            reply_markup=reply_markup,
            text='Are you sure you want to remove {}?'.format(tor.name))
        return REMOVETORRENT

    def remove_torrent(self, update, context):
        tid = re.search('^t_remove_(\d+?)$',
                        update.callback_query.data).group(1)
        tor = self.client.get_torrent(tid)
        self.client.remove_torrent(tid)
        context.bot.edit_message_text(
            chat_id=update.callback_query.message.chat_id,
            message_id=update.callback_query.message.message_id,
            text='{} has been removed'.format(tor.name))
        return ConversationHandler.END

    def remove_torrent_complete(self, update, context):
        tid = re.search('^t_remove_complete_(\d+?)$',
                        update.callback_query.data).group(1)
        tor = self.client.get_torrent(tid)
        self.client.remove_torrent(tid, delete_data=True)
        context.bot.edit_message_text(
            chat_id=update.callback_query.message.chat_id,
            message_id=update.callback_query.message.message_id,
            text='{} has been removed'.format(tor.name))
        return ConversationHandler.END
Esempio n. 2
0
class TransmissionClient(BTClientBase):
    def __init__(self,
                 rpc_address,
                 rpc_port,
                 username,
                 password,
                 config={'path': '/transmission/rpc'}):
        """
        Transmission Client for AutoPT

        config: dict
            {path: '/transmission/'}
        """

        self.rpc_address = rpc_address
        self.rpc_port = int(rpc_port)
        self.username = username
        self.password = password
        self.path = config['path']  # For now, only consider path

        self.connected = False
        self.client = None

    def connect(self):
        try:
            self.client = Client(host=self.rpc_address,
                                 port=self.rpc_port,
                                 username=self.username,
                                 password=self.password,
                                 path=self.path)
            self.connected = True
            ret = ClientRet(ret_type=2)
        except:
            ret = ClientRet(ret_type=-2)
        finally:
            return ret

    def add_torrent(self, torrent_path, download_path=None):
        if not self.connected:
            ret = ClientRet(ret_type=-2)
            return ret

        abs_torrent_path = str(Path(torrent_path).resolve())
        try:
            if download_path is None:
                torrent_obj = self.client.add_torrent(abs_torrent_path,
                                                      paused=False)
            else:
                download_path = str(Path(download_path).resolve())
                torrent_obj = self.client.add_torrent(
                    abs_torrent_path, download_dir=download_path,
                    paused=False)  # Must be absolute path
            if torrent_obj is not None:
                ret = ClientRet(ret_type=3, ret_value=torrent_obj.hashString)
        except:
            ret = ClientRet(ret_type=-3)
        finally:
            return ret

    def list_torrents(self):
        if not self.connected:
            ret = ClientRet(ret_type=-2)
            return ret

        try:
            torrent_obj_list = self.client.get_torrents()
            session_status = {}
            for torrent_obj in torrent_obj_list:
                is_finished = math.isclose(torrent_obj.progress, 100)
                torrent_status = TorrentStatus(
                    torrent_id=torrent_obj.hashString,
                    is_finished=is_finished,
                    name=torrent_obj.name)

                session_status[torrent_obj.hashString] = torrent_status

            ret = ClientRet(ret_type=4, ret_value=session_status)
        except:
            ret = ClientRet(ret_type=-4)
        finally:
            return ret

    def get_torrent_status(self, idx):
        if not self.connected:
            ret = ClientRet(ret_type=-2)
            return ret

        try:
            torrent_obj = self.client.get_torrent(idx)
            is_finished = math.isclose(torrent_obj.progress, 100)
            torrent_status = TorrentStatus(torrent_id=torrent_obj.hashString,
                                           is_finished=is_finished,
                                           name=torrent_obj.name)

            ret = ClientRet(ret_type=6, ret_value=torrent_status)
        except:
            ret = ClientRet(ret_type=-6)
        finally:
            return ret

    def del_torrent(self, idx, remove_data=True):
        if not self.connected:
            ret = ClientRet(ret_type=-2)
            return ret

        try:
            torrent_obj = self.client.get_torrent(idx)
            torrent_exist = True
        except:
            torrent_exist = False

        if torrent_exist:
            try:
                self.client.remove_torrent(idx, delete_data=remove_data)
                ret = ClientRet(ret_type=5)
            except:
                ret = ClientRet(ret_type=-5)
            finally:
                return ret
        else:
            ret = ClientRet(ret_type=-5)
            return ret

    def disconnect(self):
        self.connected = False
        self.client = None
        ret = ClientRet(ret_type=0)
        return ret
Esempio n. 3
0
class TransmissionRpcClient(TorrentClient):
    def __init__(self, url: str, port: int, user: str, password: str):
        super().__init__(url, port, user, password)
        parse = urlparse(url)

        self.client_args = {
            "protocol": parse.scheme,
            "host": parse.netloc,
            "port": port,
            "path": parse.path,
            "username": user,
            "password": password,
        }

        # print(self.client_args)
        self.session: Client = None

    def connect(self):
        self.session = Client(**self.client_args)

    def disconnect(self):
        pass

    def add_torrent(self, file: bytes, paused: bool, path: str = None) -> str:

        if self.session is None:
            raise ConnectionError()

        send = BytesIO(file)

        args = {
            "torrent": send,
            "paused": paused,
        }

        if path is not None:
            args["download_dir"] = path

        torrent = self.session.add_torrent(**args)
        return torrent.id

    def del_torrent(self, torrent_id: str):
        self.session.remove_torrent(ids=torrent_id, delete_data=True)

    def get_torrent_status(self, torrent_id: str) -> TorrentStatus:
        torrent = self.session.get_torrent(torrent_id=torrent_id)
        return TransmissionRpcStatus(torrent, self.session)

    def get_torrents_status(self,
                            torrent_id: List[str]) -> List[TorrentStatus]:
        torrents = self.session.get_torrents(ids=torrent_id)
        ret: List[TorrentStatus] = list()
        for torrent in torrents:
            ret.append(TransmissionRpcStatus(torrent, self.session))

        return ret

    def start_torrent(self, torrent_id: str):
        torrent = self.session.get_torrent(torrent_id=torrent_id)
        torrent.start()

    def stop_torrent(self, torrent_id: str):
        torrent = self.session.get_torrent(torrent_id=torrent_id)
        torrent.stop()