Compare commits

..

No commits in common. "af5873f37a8a63ae957a93d9c5e7f0696e853945" and "7e09519e626e058abe5eab9447df74d6ee60ee76" have entirely different histories.

14 changed files with 257 additions and 341 deletions

4
.envrc
View File

@ -1,3 +1 @@
source_url "https://raw.githubusercontent.com/cachix/devenv/82c0147677e510b247d8b9165c54f73d32dfd899/direnvrc" "sha256-7u4iDd1nZpxL4tCzmPG0dQgC5V+/44Ba+tHkPob1v2k=" use nix
use devenv

9
.gitignore vendored
View File

@ -1,10 +1 @@
.direnv .direnv
# Devenv
.devenv*
devenv.local.nix
# direnv
.direnv
# pre-commit
.pre-commit-config.yaml

45
add_qbt_trackers.py Executable file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""add_qbt_trackers.py
Description:
This script fetches torrent tracker URLs from plaintext lists hosted on the web
and adds them to each torrent in a qBittorrent instance.
Usage:
add_qbt_trackers.py (HOSTNAME) (USERNAME) (PASSWORD)
add_qbt_trackers.py -h
Examples:
add_qbt_trackers.py "http://localhost:8080" "admin" "adminadmin"
Options:
-h, --help show this help message and exit
"""
import requests
from docopt import docopt
from qbittorrent import Client
if __name__ == "__main__":
args = docopt(__doc__) # type: ignore
# Initialize client and login
qb = Client(args["HOSTNAME"])
qb.login(username=args["USERNAME"], password=args["PASSWORD"])
live_trackers_list_urls = [
"https://newtrackon.com/api/stable",
"https://trackerslist.com/best.txt",
"https://trackerslist.com/http.txt",
"https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt",
]
combined_trackers_urls = []
for url in live_trackers_list_urls:
response = requests.get(url, timeout=60)
tracker_urls = [x for x in response.text.splitlines() if x != ""]
combined_trackers_urls.extend(tracker_urls)
for torrent in qb.torrents():
qb.add_trackers(torrent.get("hash"), "\n".join(combined_trackers_urls)) # type: ignore

View File

@ -1,116 +0,0 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1730745597,
"owner": "cachix",
"repo": "devenv",
"rev": "7cfc04e544e67adf803c3634b53a911c670e046e",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1716977621,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1730741070,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1730814269,
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "d70155fdc00df4628446352fc58adc640cd705c2",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks"
}
}
},
"root": "root",
"version": 7
}

View File

@ -1,34 +0,0 @@
{ pkgs, lib, config, inputs, ... }:
{
# https://devenv.sh/basics/
env.GREET = "devenv";
# https://devenv.sh/packages/
packages = [
pkgs.git
pkgs.python312Packages.beautifulsoup4
pkgs.python312Packages.black
pkgs.python312Packages.bpython
pkgs.python312Packages.docopt
pkgs.python312Packages.isort
pkgs.python312Packages.pandas
pkgs.python312Packages.pytest
pkgs.python312Packages.qbittorrent-api
pkgs.python312Packages.requests
pkgs.python312Packages.resend
pkgs.python312Packages.rich
pkgs.python312Packages.tabulate
pkgs.pyright
pkgs.shellcheck
];
# https://devenv.sh/languages/
# languages.rust.enable = true;
languages.python.enable = true;
enterShell = ''
hello
git --version
'';
}

View File

@ -1,15 +0,0 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling
# If you're using non-OSS software, you can set allowUnfree to true.
# allowUnfree: true
# If you're willing to use a package that's vulnerable
# permittedInsecurePackages:
# - "openssl-1.1.1w"
# If you have more than one devenv you can merge them
#imports:
# - ./backend

View File

@ -15,8 +15,9 @@ Options:
-h, --help show this help message and exit -h, --help show this help message and exit
""" """
import qbittorrentapi
from docopt import docopt from docopt import docopt
from qbittorrent import Client
from tabulate import tabulate
# convert byte units # convert byte units
@ -42,24 +43,35 @@ def human_bytes(input_bytes: int) -> str:
return "" return ""
def print_ssv(): def print_table():
with qbittorrentapi.Client( qb = Client("http://localhost:8080/")
host="localhost", port=8080, username="", password="" qb.login()
) as qbt_client: table = []
try: headers = ["Name", "Total Size", "Trackers Count", "Ratio", "Uploaded"]
qbt_client.auth_log_in() sorted_torrents = sorted(qb.torrents(), key=lambda d: d["ratio"], reverse=True) # type: ignore
except qbittorrentapi.LoginFailed as e:
print(e)
sorted_torrents = sorted(
qbt_client.torrents_info(), key=lambda d: d.ratio, reverse=True
)
for torrent in sorted_torrents: for torrent in sorted_torrents:
name = torrent.name row = []
size = human_bytes(torrent.total_size) row.append(torrent["name"]) # type: ignore
trackers = torrent.trackers_count row.append(human_bytes(int(torrent["total_size"]))) # type: ignore
ratio = torrent.ratio row.append(torrent["trackers_count"]) # type: ignore
uploaded = human_bytes(torrent.uploaded) row.append(torrent["ratio"]) # type: ignore
row.append(human_bytes(int(torrent["uploaded"]))) # type: ignore
table.append(row)
print(tabulate(table, headers, tablefmt="grid"))
def print_ssv():
qb = Client("http://localhost:8080/")
qb.login()
sorted_torrents = sorted(qb.torrents(), key=lambda d: d["ratio"], reverse=True) # type: ignore
print("Name Size Trackers Ratio Uploaded")
for torrent in sorted_torrents:
name = torrent["name"] # type: ignore
size = human_bytes(int(torrent["total_size"])) # type: ignore
trackers = torrent["trackers_count"] # type: ignore
ratio = torrent["ratio"] # type: ignore
uploaded = human_bytes(int(torrent["uploaded"])) # type: ignore
print(f"{name} {size} {trackers} {ratio} {uploaded}") print(f"{name} {size} {trackers} {ratio} {uploaded}")

View File

@ -18,8 +18,8 @@ Options:
-h, --help show this help message and exit -h, --help show this help message and exit
""" """
import qbittorrentapi
from docopt import docopt from docopt import docopt
from qbittorrent import Client
# convert byte units # convert byte units
@ -48,26 +48,21 @@ def human_bytes(bites: int) -> str:
if __name__ == "__main__": if __name__ == "__main__":
args = docopt(__doc__) # type: ignore args = docopt(__doc__) # type: ignore
# Initialize client and login
qb = Client(args["HOSTNAME"])
qb.login(username=args["USERNAME"], password=args["PASSWORD"])
# get total_completed_bytes
completed_torrent_sizes = [] completed_torrent_sizes = []
total_added_bytes = int() for torrent in qb.torrents():
if torrent["completion_on"] != 0: # type: ignore
with qbittorrentapi.Client( completed_torrent_sizes.append(torrent["total_size"]) # type: ignore
host=args["HOSTNAME"], username=args["USERNAME"], password=args["PASSWORD"]
) as qbt_client:
try:
qbt_client.auth_log_in()
except qbittorrentapi.LoginFailed as e:
print(e)
for torrent in qbt_client.torrents_info():
if torrent.completion_on != 0:
completed_torrent_sizes.append(torrent.total_size)
total_added_bytes = sum(
[torrent.total_size for torrent in qbt_client.torrents_info()]
)
total_completed_bytes = sum(completed_torrent_sizes) total_completed_bytes = sum(completed_torrent_sizes)
# get total_added_bytes
total_added_bytes = sum([torrent["total_size"] for torrent in qb.torrents()]) # type: ignore
# print the results
print(f"\nTotal completed size: {human_bytes(total_completed_bytes)}") print(f"\nTotal completed size: {human_bytes(total_completed_bytes)}")
print(f"Total added size: {human_bytes(total_added_bytes)}\n") print(f"Total added size: {human_bytes(total_added_bytes)}\n")

102
qbth.py
View File

@ -17,25 +17,15 @@ Options:
import json import json
import os import os
import subprocess import subprocess
from shutil import which
import qbittorrentapi
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from docopt import docopt from docopt import docopt
from qbittorrent import Client
args = docopt(__doc__) args = docopt(__doc__)
conn_info = dict( qb = Client(args["HOSTNAME"])
host=args["HOSTNAME"], qb.login(username=args["USERNAME"], password=args["PASSWORD"])
username=args["USERNAME"],
password=args["PASSWORD"],
)
try:
with qbittorrentapi.Client(**conn_info) as qbt_client:
qbt_client.auth_log_in()
except qbittorrentapi.LoginFailed as e:
print(e)
def add_torrents(urls: list[str]): def add_torrents(urls: list[str]):
@ -45,16 +35,9 @@ def add_torrents(urls: list[str]):
Params: Params:
urls: list of strings that are URLs. urls: list of strings that are URLs.
""" """
with qbittorrentapi.Client(**conn_info) as qbt_client:
for url in urls: for url in urls:
response = requests.get(url) qb.download_from_link(url, category="distro")
if response.status_code == 200:
if qbt_client.torrents_add(url, category="distro") != "Ok.":
raise Exception("Failed to add torrent: " + os.path.basename(url))
else:
print(f"Added {os.path.basename(url)}") print(f"Added {os.path.basename(url)}")
else:
print(f"{response.status_code}: {url}")
def add_torrents_from_html(webpage_url: str, torrent_substring: str): def add_torrents_from_html(webpage_url: str, torrent_substring: str):
@ -69,21 +52,11 @@ def add_torrents_from_html(webpage_url: str, torrent_substring: str):
""" """
reqs = requests.get(webpage_url, timeout=60) reqs = requests.get(webpage_url, timeout=60)
soup = BeautifulSoup(reqs.text, "html.parser") soup = BeautifulSoup(reqs.text, "html.parser")
with qbittorrentapi.Client(**conn_info) as qbt_client:
for link in soup.find_all("a"): for link in soup.find_all("a"):
if torrent_substring in link.get("href"): if torrent_substring in link.get("href"):
url = f"{webpage_url}/{link.get('href')}" url = f"{webpage_url}/{link.get('href')}"
response = requests.get(url) qb.download_from_link(url, category="distro")
if response.status_code == 200: print(f"Added {link.get('href')}")
if qbt_client.torrents_add(url, category="distro") != "Ok.":
raise Exception(
"Failed to add torrent: " + os.path.basename(url)
)
else:
print(f"Added {os.path.basename(url)}")
else:
print(f"{response.status_code}: {url}")
def remove_torrents(distro_substring: str): def remove_torrents(distro_substring: str):
@ -96,13 +69,10 @@ def remove_torrents(distro_substring: str):
distro_substring: a string that is a substring of the distro distro_substring: a string that is a substring of the distro
torrent's file name. torrent's file name.
""" """
with qbittorrentapi.Client(**conn_info) as qbt_client: for torrent in qb.torrents():
for torrent in qbt_client.torrents_info(): if distro_substring in torrent.get("name"): # type: ignore
if distro_substring in torrent.name: qb.delete_permanently(torrent.get("hash")) # type: ignore
qbt_client.torrents_delete( print(f"Removed {torrent.get('name')}") # type: ignore
torrent_hashes=torrent.hash, delete_files=True
)
print(f"Removed {torrent.name}")
def add_almalinux(rel_ver: str): def add_almalinux(rel_ver: str):
@ -172,7 +142,8 @@ def add_devuan(rel_ver: str):
relver: the Devuan release version. relver: the Devuan release version.
""" """
url = f"https://files.devuan.org/devuan_{rel_ver}.torrent" url = f"https://files.devuan.org/devuan_{rel_ver}.torrent"
add_torrents([url]) qb.download_from_link(url, category="distro")
print(f"Added {os.path.basename(url)}")
def remove_devuan(rel_ver: str): def remove_devuan(rel_ver: str):
@ -204,13 +175,11 @@ def remove_fedora(rel_ver: str):
Params: Params:
relver: the Fedora release version. relver: the Fedora release version.
""" """
with qbittorrentapi.Client(**conn_info) as qbt_client: torrents = qb.torrents()
for torrent in qbt_client.torrents_info(): for torrent in torrents:
if torrent.name.startswith("Fedora") and torrent.name.endswith(rel_ver): if torrent.get("name").startswith("Fedora") and torrent.get("name").endswith(rel_ver): # type: ignore
qbt_client.torrents_delete( qb.delete_permanently(torrent.get("hash")) # type: ignore
torrent_hashes=torrent.hash, delete_files=True print(f"Removed {torrent.get('name')}") # type: ignore
)
print(f"Removed {torrent.name}")
def add_freebsd(rel_ver: str): def add_freebsd(rel_ver: str):
@ -225,12 +194,9 @@ def add_freebsd(rel_ver: str):
reqs = requests.get(url, timeout=60) reqs = requests.get(url, timeout=60)
data = reqs.text.split("\n") data = reqs.text.split("\n")
with qbittorrentapi.Client(**conn_info) as qbt_client:
for line in data: for line in data:
if line.startswith("magnet:"): if line.startswith("magnet:"):
if qbt_client.torrents_add(line) != "Ok.": qb.download_from_link(line, category="distro")
raise Exception("Failed to add torrent: " + line.split("=")[2])
print(f"Added {line.split('=')[2]}") print(f"Added {line.split('=')[2]}")
@ -300,25 +266,9 @@ def add_nixos():
url = "https://api.github.com/repos/AnimMouse/NixOS-ISO-Torrents/releases/latest" url = "https://api.github.com/repos/AnimMouse/NixOS-ISO-Torrents/releases/latest"
reqs = requests.get(url, timeout=60) reqs = requests.get(url, timeout=60)
json_data = json.loads(reqs.text) json_data = json.loads(reqs.text)
with qbittorrentapi.Client(**conn_info) as qbt_client:
for item in json_data["assets"]: for item in json_data["assets"]:
response = requests.get(item["browser_download_url"]) qb.download_from_link(item["browser_download_url"], category="distro")
if response.status_code == 200:
if (
qbt_client.torrents_add(
item["browser_download_url"], category="distro"
)
!= "Ok."
):
raise Exception(
"Failed to add torrent: "
+ os.path.basename(item["browser_download_url"])
)
else:
print(f"Added {os.path.basename(item['browser_download_url'])}") print(f"Added {os.path.basename(item['browser_download_url'])}")
else:
print(f"{response.status_code}: {item['browser_download_url']}")
def remove_nixos(): def remove_nixos():
@ -339,16 +289,8 @@ def add_qubes(rel_ver: str):
relver: the QubesOS release version. relver: the QubesOS release version.
""" """
url = f"https://mirrors.edge.kernel.org/qubes/iso/Qubes-R{rel_ver}-x86_64.torrent" url = f"https://mirrors.edge.kernel.org/qubes/iso/Qubes-R{rel_ver}-x86_64.torrent"
qb.download_from_link(url, category="distro")
response = requests.get(url)
if response.status_code == 200:
with qbittorrentapi.Client(**conn_info) as qbt_client:
if qbt_client.torrents_add(url, category="distro") != "Ok.":
raise Exception("Failed to add torrent: " + os.path.basename(url))
else:
print(f"Added {os.path.basename(url)}") print(f"Added {os.path.basename(url)}")
else:
print(f"{response.status_code}: {url}")
def remove_qubes(rel_ver: str): def remove_qubes(rel_ver: str):
@ -414,10 +356,6 @@ def remove_tails(rel_ver: str):
if __name__ == "__main__": if __name__ == "__main__":
# Check if gum is installed.
if which("gum") is None:
exit("Please install gum first. https://github.com/charmbracelet/gum")
# Run the gum program in a subprocess to allow easy selecting of distro # Run the gum program in a subprocess to allow easy selecting of distro
# torrents. # torrents.
distro_selection = subprocess.run( distro_selection = subprocess.run(

View File

@ -39,9 +39,9 @@ Options:
import json import json
import qbittorrentapi
import requests import requests
from docopt import docopt from docopt import docopt
from qbittorrent import Client
def get_torrent_health_data() -> list[dict]: def get_torrent_health_data() -> list[dict]:
@ -62,8 +62,6 @@ def convert_size_to_bytes(size: str) -> int:
Example: 42G --> 45097156608 bytes Example: 42G --> 45097156608 bytes
""" """
total_bytes = int()
if size.endswith("T"): if size.endswith("T"):
total_bytes = int(size.split("T")[0]) * (1024**4) total_bytes = int(size.split("T")[0]) * (1024**4)
@ -159,14 +157,8 @@ if __name__ == "__main__":
dry_run = args["--dry-run"] dry_run = args["--dry-run"]
# Initialize client and login # Initialize client and login
qbt_client = qbittorrentapi.Client( qb = Client(hostname)
host=hostname, username=username, password=password qb.login(username=username, password=password)
)
try:
qbt_client.auth_log_in()
except qbittorrentapi.LoginFailed as e:
print(e)
# Fill the knapsack # Fill the knapsack
knapsack = fill_knapsack(max_seeders, knapsack_size, smaller) knapsack = fill_knapsack(max_seeders, knapsack_size, smaller)
@ -191,15 +183,13 @@ if __name__ == "__main__":
for torrent in knapsack: for torrent in knapsack:
if "gen.lib.rus.ec" in torrent["link"]: if "gen.lib.rus.ec" in torrent["link"]:
new_torrent = torrent["link"].replace("gen.lib.rus.ec", "libgen.is") new_torrent = torrent["link"].replace("gen.lib.rus.ec", "libgen.is")
qbt_client.torrents_add(new_torrent, category="scihub") qb.download_from_link(new_torrent, category="scihub")
if "libgen.rs" in torrent["link"]: if "libgen.rs" in torrent["link"]:
new_torrent = torrent["link"].replace("libgen.rs", "libgen.is") new_torrent = torrent["link"].replace("libgen.rs", "libgen.is")
qbt_client.torrents_add(new_torrent, category="scihub") qb.download_from_link(new_torrent, category="scihub")
# print(f"Added {torrent['name']}") # print(f"Added {torrent['name']}")
qbt_client.auth_log_out()
print("----------------") print("----------------")
print(f"Count: {len(knapsack)} torrents") print(f"Count: {len(knapsack)} torrents")
print(f"Total combined size: {get_knapsack_weight(knapsack)}") print(f"Total combined size: {get_knapsack_weight(knapsack)}")

63
seed_armbian_torrents.py Executable file
View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
"""seed_armbian_torrents.py
Description:
Armbian torrents seed script
This script will download Armbian torrent files and add them to a qBittorrent
instance. It's intended to be run under /etc/cron.weekly or used in a systemd
timer.
This is a Python implementation of https://docs.armbian.com/Community_Torrent/
for qBittorrent.
Usage:
seed_armbian_torrents.py (HOSTNAME) (USERNAME) (PASSWORD)
seed_armbian_torrents.py -h
Examples:
seed_armbian_torrents.py "http://localhost:8080" "admin" "adminadmin"
seed_armbian_torrents.py "https://cat.seedhost.eu/lol/qbittorrent" "lol" "pw"
Options:
-h, --help show this help message and exit.
"""
import os
from io import BytesIO
from tempfile import TemporaryDirectory
from zipfile import ZipFile
import requests
from docopt import docopt
from qbittorrent import Client
if __name__ == "__main__":
args = docopt(__doc__)
# Initialize client and login
qb = Client(args["HOSTNAME"])
qb.login(username=args["USERNAME"], password=args["PASSWORD"])
with TemporaryDirectory() as tmp_dir:
req = requests.get(
"https://dl.armbian.com/torrent/all-torrents.zip",
stream=True,
timeout=60,
)
with ZipFile(BytesIO(req.content)) as zip_file:
zip_file.extractall(tmp_dir)
for torrent in qb.torrents():
if "Armbian" in torrent.get("name"): # type: ignore
qb.delete_permanently(torrent.get("hash")) # type: ignore
print(f"Removed {torrent.get('name')}") # type: ignore
torrent_files = os.listdir(tmp_dir)
for torrent_file in torrent_files:
with open(os.path.join(tmp_dir, torrent_file), "rb") as tf:
qb.download_from_file(tf, category="distro")
print(
f"Added {os.path.basename(os.path.join(tmp_dir, torrent_file))}"
)

44
shell.nix Normal file
View File

@ -0,0 +1,44 @@
with import <nixpkgs> { };
let
python-qbittorrent = pkgs.python312Packages.buildPythonPackage rec {
name = "python-qbittorrent-${version}";
version = "0.4.3";
src = pkgs.fetchurl {
url = "https://files.pythonhosted.org/packages/86/25/a5ad35ad229c8016a8c98327495e649cb795be2fda63f8cace6c9a739af7/python-qbittorrent-${version}.tar.gz";
sha256 = "4e22cf89890628b054a60aa4bd1161a68c2b0fad48ef0886fa4d325e69d3828a";
};
meta = {
homepage = "https://github.com/v1k45/python-qBittorrent";
description = "Python wrapper for qBittorrent Web API (for versions above v3.1.x)";
license = lib.licenses.mit;
maintainers = with maintainers; [ v1k45 ];
};
nativeBuildInputs = with pkgs.python312Packages; [
pip
requests
];
};
in
mkShell {
buildInputs = with pkgs; [
python312Packages.beautifulsoup4
python312Packages.black
python312Packages.bpython
python312Packages.docopt
python312Packages.isort
python312Packages.pandas
python312Packages.pytest
python312Packages.requests
python312Packages.resend
python312Packages.rich
python312Packages.tabulate
pyright
python-qbittorrent
shellcheck
];
}

View File

@ -28,8 +28,8 @@ import subprocess
import tempfile import tempfile
from pathlib import Path from pathlib import Path
import qbittorrentapi
from docopt import docopt from docopt import docopt
from qbittorrent import Client
from rich.console import Console from rich.console import Console
from rich.text import Text from rich.text import Text
@ -53,18 +53,11 @@ if __name__ == "__main__":
) )
torrent_infohashes = [] torrent_infohashes = []
for item in auth_data["instances"]: for item in auth_data["instances"]:
with qbittorrentapi.Client( qb = Client(item["hostname"])
host=item["hostname"], qb.login(username=item["username"], password=item["password"])
username=item["username"],
password=item["password"],
) as qbt_client:
try:
qbt_client.auth_log_in()
except qbittorrentapi.LoginFailed as e:
print(e)
for torrent in qbt_client.torrents_info(): for torrent in qb.torrents():
torrent_infohashes.append(torrent.hash) torrent_infohashes.append(torrent.get("hash")) # type: ignore
# Format the infohashes to have a \n at the end # Format the infohashes to have a \n at the end
console.log("Formatting infohashes to have a newline at the end.") console.log("Formatting infohashes to have a newline at the end.")
@ -104,16 +97,28 @@ if __name__ == "__main__":
] ]
) )
# Ensure {tracker_domain}:6969/announce is added to each torrent's
# tracker list.
if tracker_domain:
console.log(
f"Ensuring {tracker_domain}:6969/announce is added to each torrent's tracker list."
)
for item in auth_data["instances"]:
qb = Client(item["hostname"])
qb.login(username=item["username"], password=item["password"])
for torrent in qb.torrents():
qb.add_trackers(
torrent.get("hash"), # type: ignore
f"http://{tracker_domain}:6969/announce\nudp://{tracker_domain}:6969/announce",
)
# Reannounce all torrents in each qBittorrent instance to their trackers # Reannounce all torrents in each qBittorrent instance to their trackers
console.log("Reannouncing all torrents to their trackers.") console.log("Reannouncing all torrents to their trackers.")
for item in auth_data["instances"]: for item in auth_data["instances"]:
with qbittorrentapi.Client( qb = Client(item["hostname"])
host=item["hostname"], qb.login(username=item["username"], password=item["password"])
username=item["username"], torrent_infohashes = [torrent.get("hash") for torrent in qb.torrents()] # type: ignore
password=item["password"], qb.reannounce(torrent_infohashes)
) as qbt_client:
for torrent in qbt_client.torrents_info():
torrent.reannounce(torrent.hash)
console.log("Done!") console.log("Done!")