from __future__ import annotations import logging from pathlib import Path from typing import Iterable, List import qbittorrentapi from .config import QBittorrentConfig from .models import FileState class QBClient: def __init__(self, cfg: QBittorrentConfig, logger: logging.Logger): self.cfg = cfg self.log = logger self.client = qbittorrentapi.Client( host=cfg.host, port=cfg.port, username=cfg.username, password=cfg.password, VERIFY_WEBUI_CERTIFICATE=cfg.use_https, ) self.client.auth_log_in() self.log.info("Connected to qBittorrent WebUI at %s", cfg.host) def fetch_file_states(self) -> List[FileState]: torrents = self.client.torrents_info() files: List[FileState] = [] for torrent in torrents: save_path = torrent.save_path torrent_files = self.client.torrents_files(torrent_hash=torrent.hash) for file_entry in torrent_files: downloaded = int(file_entry.get("downloaded", file_entry["size"])) remaining = max(int(file_entry["size"]) - downloaded, 0) files.append( FileState( torrent_hash=torrent.hash, torrent_name=torrent.name, file_index=file_entry["index"], name=file_entry["name"], size=int(file_entry["size"]), downloaded=downloaded, progress=float(file_entry["progress"]), priority=int(file_entry["priority"]), remaining=remaining, save_path=Path(save_path), ) ) return files def set_priority(self, torrent_hash: str, file_ids: Iterable[int], priority: int) -> None: ids = list(file_ids) if not ids: return self.client.torrents_file_priority( torrent_hash=torrent_hash, file_ids=ids, priority=priority, ) def set_sequential(self, torrent_hashes: Iterable[str], value: bool) -> None: hashes = list(dict.fromkeys(torrent_hashes)) if not hashes: return self.client.torrents_set_sequential_download( torrent_hashes="|".join(hashes), value=value, )