admin-scripts/python/qbth.py

561 lines
16 KiB
Python
Raw Normal View History

2024-11-09 00:18:47 +01:00
# /// script
# dependencies = [
# "qbittorrent-api",
# "requests",
# "bs4",
# "docopt",
# ]
# ///
2024-07-08 18:30:36 +02:00
2024-07-29 08:48:44 +02:00
"""qbth.py - qbittorrent helper
2024-07-22 15:13:12 +02:00
Usage:
2024-07-29 08:48:44 +02:00
qbth.py (HOSTNAME) (USERNAME) (PASSWORD)
qbth.py -h
2024-07-22 15:13:12 +02:00
Examples:
2024-07-29 08:48:44 +02:00
qbth.py "http://localhost:8080" "admin" "adminadmin"
qbth.py "https://cat.seedhost.eu/lol/qbittorrent" "lol" "meow"
2024-07-22 15:13:12 +02:00
Options:
-h, --help show this help message and exit
"""
2024-07-08 18:30:36 +02:00
import json
import os
import subprocess
2024-11-09 00:18:47 +01:00
from shutil import which
2024-07-08 18:30:36 +02:00
2024-11-09 00:18:47 +01:00
import qbittorrentapi
2024-07-08 18:30:36 +02:00
import requests
from bs4 import BeautifulSoup
2024-07-22 15:13:12 +02:00
from docopt import docopt
2024-07-08 18:30:36 +02:00
2024-07-22 15:13:12 +02:00
args = docopt(__doc__)
2024-11-09 00:18:47 +01:00
conn_info = dict(
host=args["HOSTNAME"],
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)
2024-07-08 18:30:36 +02:00
2024-07-22 15:13:12 +02:00
def add_torrents(urls: list[str]):
2024-07-24 03:00:59 +02:00
"""
Add torrents from their URLs.
Params:
urls: list of strings that are URLs.
"""
2024-11-09 00:18:47 +01:00
with qbittorrentapi.Client(**conn_info) as qbt_client:
for url in urls:
response = requests.get(url)
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)}")
else:
print(f"{response.status_code}: {url}")
2024-07-08 18:30:36 +02:00
def add_torrents_from_html(webpage_url: str, torrent_substring: str):
2024-07-24 03:00:59 +02:00
"""
Add torrents from an HTML web page.
Params:
webpage_url: a string that is the URL for the desired webpage.
torrent_substring: a string that is a substring of the URLs in
the webpage that you want to extract. It serves as a
selector.
"""
2024-07-22 15:13:12 +02:00
reqs = requests.get(webpage_url, timeout=60)
2024-07-08 18:30:36 +02:00
soup = BeautifulSoup(reqs.text, "html.parser")
2024-11-09 00:18:47 +01:00
with qbittorrentapi.Client(**conn_info) as qbt_client:
for link in soup.find_all("a"):
if torrent_substring in link.get("href"):
url = f"{webpage_url}/{link.get('href')}"
response = requests.get(url)
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)}")
else:
print(f"{response.status_code}: {url}")
2024-07-08 18:30:36 +02:00
def remove_torrents(distro_substring: str):
2024-07-24 03:00:59 +02:00
"""
Remove torrents by selecting a substring that corresponds to the
distro's torrent file name. When the substring is found, the
torrent is removed by passing the corresponding hash to the method.
Params:
distro_substring: a string that is a substring of the distro
torrent's file name.
"""
2024-11-09 00:18:47 +01:00
with qbittorrentapi.Client(**conn_info) as qbt_client:
for torrent in qbt_client.torrents_info():
if distro_substring in torrent.name:
qbt_client.torrents_delete(
torrent_hashes=torrent.hash, delete_files=True
)
print(f"Removed {torrent.name}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_almalinux(rel_ver: str):
"""
Add AlmaLinux torrents from a list of URLs. These URLs are partially
hardcoded for convenience and aren't expected to change frequently.
Params:
relver: the AlmaLinux release version.
"""
2024-07-08 18:30:36 +02:00
urls = [
2024-07-24 03:00:59 +02:00
f"https://almalinux-mirror.dal1.hivelocity.net/{rel_ver}/isos/aarch64/AlmaLinux-{rel_ver}-aarch64.torrent",
f"https://almalinux-mirror.dal1.hivelocity.net/{rel_ver}/isos/ppc64le/AlmaLinux-{rel_ver}-ppc64le.torrent",
f"https://almalinux-mirror.dal1.hivelocity.net/{rel_ver}/isos/s390x/AlmaLinux-{rel_ver}-s390x.torrent",
f"https://almalinux-mirror.dal1.hivelocity.net/{rel_ver}/isos/x86_64/AlmaLinux-{rel_ver}-x86_64.torrent",
2024-07-08 18:30:36 +02:00
]
add_torrents(urls)
2024-07-24 03:00:59 +02:00
def remove_almalinux(rel_ver: str):
"""
Remove AlmaLinux torrents given their release version.
Params:
relver: the AlmaLinux release version.
"""
remove_torrents(f"AlmaLinux-{rel_ver}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_debian(rel_ver: str):
"""
Add Debian torrents from a list of URLs.
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
Params:
relver: the Debian release version.
"""
2024-07-08 18:30:36 +02:00
urls = [
2024-07-24 03:00:59 +02:00
f"https://cdimage.debian.org/debian-cd/current/amd64/bt-dvd/debian-{rel_ver}-amd64-DVD-1.iso.torrent",
f"https://cdimage.debian.org/debian-cd/current/arm64/bt-dvd/debian-{rel_ver}-arm64-DVD-1.iso.torrent",
f"https://cdimage.debian.org/debian-cd/current/armel/bt-dvd/debian-{rel_ver}-armel-DVD-1.iso.torrent",
f"https://cdimage.debian.org/debian-cd/current/armhf/bt-dvd/debian-{rel_ver}-armhf-DVD-1.iso.torrent",
f"https://cdimage.debian.org/debian-cd/current/mips64el/bt-dvd/debian-{rel_ver}-mips64el-DVD-1.iso.torrent",
f"https://cdimage.debian.org/debian-cd/current/mipsel/bt-dvd/debian-{rel_ver}-mipsel-DVD-1.iso.torrent",
f"https://cdimage.debian.org/debian-cd/current/ppc64el/bt-dvd/debian-{rel_ver}-ppc64el-DVD-1.iso.torrent",
f"https://cdimage.debian.org/debian-cd/current/s390x/bt-dvd/debian-{rel_ver}-s390x-DVD-1.iso.torrent",
2024-07-08 18:30:36 +02:00
]
add_torrents(urls)
2024-07-24 03:00:59 +02:00
def remove_debian(rel_ver: str):
"""
Remove Debian torrents given their release version.
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
Params:
relver: the Debian release version.
"""
remove_torrents(f"debian-{rel_ver}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_devuan(rel_ver: str):
"""
Add Devuan torrents from a URL.
Params:
relver: the Devuan release version.
"""
url = f"https://files.devuan.org/devuan_{rel_ver}.torrent"
2024-11-09 00:18:47 +01:00
add_torrents([url])
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def remove_devuan(rel_ver: str):
"""
Remove Devuan torrents given their release version.
Params:
relver: the Devuan release version.
"""
remove_torrents(f"devuan_{rel_ver}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_fedora(rel_ver: str):
"""
Add Fedora torrents from URLs extracted from a webpage.
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
Params:
relver: the Fedora release version.
"""
2024-07-08 18:30:36 +02:00
webpage_url = "https://torrent.fedoraproject.org/torrents"
2024-07-24 03:00:59 +02:00
torrent_substring = f"{rel_ver}.torrent"
2024-07-08 18:30:36 +02:00
add_torrents_from_html(webpage_url, torrent_substring)
2024-07-24 03:00:59 +02:00
def remove_fedora(rel_ver: str):
"""
Remove Fedora torrents given their release version.
Params:
relver: the Fedora release version.
"""
2024-11-09 00:18:47 +01:00
with qbittorrentapi.Client(**conn_info) as qbt_client:
for torrent in qbt_client.torrents_info():
if torrent.name.startswith("Fedora") and torrent.name.endswith(rel_ver):
qbt_client.torrents_delete(
torrent_hashes=torrent.hash, delete_files=True
)
print(f"Removed {torrent.name}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_freebsd(rel_ver: str):
"""
Add FreeBSD torrents via a text file on the web that contains their
magnet links.
Params:
relver: the FreeBSD release version.
"""
url = f"https://people.freebsd.org/~jmg/FreeBSD-{rel_ver}-R-magnet.txt"
2024-07-22 15:13:12 +02:00
reqs = requests.get(url, timeout=60)
2024-07-08 18:30:36 +02:00
data = reqs.text.split("\n")
2024-11-09 00:18:47 +01:00
with qbittorrentapi.Client(**conn_info) as qbt_client:
for line in data:
if line.startswith("magnet:"):
if qbt_client.torrents_add(line) != "Ok.":
raise Exception("Failed to add torrent: " + line.split("=")[2])
print(f"Added {line.split('=')[2]}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def remove_freebsd(rel_ver: str):
"""
Remove FreeBSD torrents given their release version.
Params:
relver: the FreeBSD release version.
"""
remove_torrents(f"FreeBSD-{rel_ver}")
2024-07-08 18:30:36 +02:00
def add_kali():
2024-07-24 03:00:59 +02:00
"""
Add Kali Linux torrents from their URLs extracted from a webpage.
This method does not accept any parameters. The latest Kali Linux
version is automatically selected.
Params: none
"""
2024-07-08 18:30:36 +02:00
webpage_url = "https://kali.download/base-images/current"
torrent_substring = ".torrent"
add_torrents_from_html(webpage_url, torrent_substring)
def remove_kali():
2024-07-24 03:00:59 +02:00
"""
Remove Kali Linux torrents. This method does not accept any parameters.
All Kali Linux torrents in the qBittorrent instance will be removed.
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
Params: none
"""
remove_torrents("kali-linux")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_netbsd(rel_ver: str):
"""
Add NetBSD torrents from their URLs extracted from a webpage.
Params:
relver: the NetBSD release version.
"""
webpage_url = f"https://cdn.netbsd.org/pub/NetBSD/NetBSD-{rel_ver}/images/"
torrent_substring = ".torrent"
2024-07-08 18:30:36 +02:00
add_torrents_from_html(webpage_url, torrent_substring)
2024-07-24 03:00:59 +02:00
def remove_netbsd(rel_ver: str):
"""
Remove NetBSD torrents given their release version.
Params:
relver: the NetBSD release version.
"""
remove_torrents(f"NetBSD-{rel_ver}")
2024-07-08 18:30:36 +02:00
def add_nixos():
2024-07-24 03:00:59 +02:00
"""
Add NixOS torrents from their GitHub release at
https://github.com/AninMouse/NixOS-ISO-Torrents. This method does not
accept any paramters. The latest NixOS torrent is automatically selected.
Params: none
"""
2024-07-08 18:30:36 +02:00
url = "https://api.github.com/repos/AnimMouse/NixOS-ISO-Torrents/releases/latest"
2024-07-22 15:13:12 +02:00
reqs = requests.get(url, timeout=60)
2024-07-08 18:30:36 +02:00
json_data = json.loads(reqs.text)
2024-11-09 00:18:47 +01:00
with qbittorrentapi.Client(**conn_info) as qbt_client:
for item in json_data["assets"]:
response = requests.get(item["browser_download_url"])
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'])}")
else:
print(f"{response.status_code}: {item['browser_download_url']}")
2024-07-08 18:30:36 +02:00
def remove_nixos():
2024-07-24 03:00:59 +02:00
"""
Remove NixOS torrents. This method does not accept any parameters. All
NixOS torrents in the qBittorrent instance will be removed.
Params: none
"""
2024-07-08 18:30:36 +02:00
remove_torrents("nixos")
2024-07-24 03:00:59 +02:00
def add_qubes(rel_ver: str):
"""
Add QubesOS torrents from their URLs.
Params:
relver: the QubesOS release version.
"""
url = f"https://mirrors.edge.kernel.org/qubes/iso/Qubes-R{rel_ver}-x86_64.torrent"
2024-11-09 00:18:47 +01:00
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)}")
else:
print(f"{response.status_code}: {url}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def remove_qubes(rel_ver: str):
"""
Remove QubesOS torrents given their release version.
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
Params:
relver: the Qubes OS release version.
"""
remove_torrents(f"Qubes-R{rel_ver}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_rockylinux(rel_ver: str):
"""
Add Rocky Linux torrents from their URLs.
Params:
relver: the Rocky Linux release version.
"""
2024-07-08 18:30:36 +02:00
urls = [
2024-07-24 03:00:59 +02:00
f"https://download.rockylinux.org/pub/rocky/{rel_ver}/isos/aarch64/Rocky-{rel_ver}-aarch64-dvd.torrent",
f"https://download.rockylinux.org/pub/rocky/{rel_ver}/isos/ppc64le/Rocky-{rel_ver}-ppc64le-dvd.torrent",
f"https://download.rockylinux.org/pub/rocky/{rel_ver}/isos/s390x/Rocky-{rel_ver}-s390x-dvd.torrent",
f"https://download.rockylinux.org/pub/rocky/{rel_ver}/isos/x86_64/Rocky-{rel_ver}-x86_64-dvd.torrent",
2024-07-08 18:30:36 +02:00
]
add_torrents(urls)
2024-07-24 03:00:59 +02:00
def remove_rockylinux(rel_ver: str):
"""
Remove Rocky Linux torrents given their release version.
Params:
relver: the Rocky Linux release version.
"""
remove_torrents(f"Rocky-{rel_ver}")
2024-07-08 18:30:36 +02:00
2024-07-24 03:00:59 +02:00
def add_tails(rel_ver: str):
"""
Add Tails torrents from their URLs.
Params:
relver: the Tails release version.
"""
2024-07-08 18:30:36 +02:00
urls = [
2024-07-24 03:00:59 +02:00
f"https://tails.net/torrents/files/tails-amd64-{rel_ver}.img.torrent",
f"https://tails.net/torrents/files/tails-amd64-{rel_ver}.iso.torrent",
2024-07-08 18:30:36 +02:00
]
add_torrents(urls)
2024-07-24 03:00:59 +02:00
def remove_tails(rel_ver: str):
"""
Remove Tails torrents given their release version.
Params:
relver: the Tails release version.
"""
remove_torrents(f"tails-amd64-{rel_ver}")
2024-07-08 18:30:36 +02:00
if __name__ == "__main__":
2024-11-09 00:18:47 +01:00
# Check if gum is installed.
if which("gum") is None:
exit("Please install gum first. https://github.com/charmbracelet/gum")
2024-07-24 03:00:59 +02:00
# Run the gum program in a subprocess to allow easy selecting of distro
# torrents.
2024-07-08 18:30:36 +02:00
distro_selection = subprocess.run(
[
"gum",
"choose",
"--limit=1",
2024-08-11 01:44:57 +02:00
"--header=Available torrents",
2024-07-08 18:30:36 +02:00
"--height=13",
"AlmaLinux",
"Debian",
"Devuan",
"Fedora",
"FreeBSD",
"Kali Linux",
"NetBSD",
"NixOS",
"Qubes",
"Rocky Linux",
"Tails",
],
stdout=subprocess.PIPE,
text=True,
2024-07-24 03:00:59 +02:00
check=True,
2024-07-08 18:30:36 +02:00
).stdout.strip()
2024-07-24 03:00:59 +02:00
# After the distro is selected and stored in the distro_selection variable,
# choose an action to take on the selected distro.
# Add: add the distro torrents to qBittorrent
# Remove: remove the distro torrents from qBittorrent
2024-07-08 18:30:36 +02:00
action_selection = subprocess.run(
["gum", "choose", "--limit=1", "--header='Choose:'", "Add", "Remove"],
stdout=subprocess.PIPE,
text=True,
2024-07-24 03:00:59 +02:00
check=True,
2024-07-08 18:30:36 +02:00
).stdout.strip()
2024-07-24 03:00:59 +02:00
# After the distro is selected and stored in the distro_selection variable,
# and after the action is selected and store in the action_selection
# variable, enter the release version of the selected distro to execute the
# selected action on.
2024-07-08 18:30:36 +02:00
relver = subprocess.run(
2024-07-24 03:00:59 +02:00
[
"gum",
"input",
f"--placeholder='Enter {distro_selection} release version'",
],
2024-07-08 18:30:36 +02:00
stdout=subprocess.PIPE,
text=True,
2024-07-24 03:00:59 +02:00
check=True,
2024-07-08 18:30:36 +02:00
).stdout.strip()
2024-07-24 03:00:59 +02:00
# Match the distro_selection to execute the action_selection on.
2024-07-08 18:30:36 +02:00
match distro_selection:
case "AlmaLinux":
if action_selection == "Add":
add_almalinux(relver)
if action_selection == "Remove":
remove_almalinux(relver)
case "Debian":
if action_selection == "Add":
add_debian(relver)
if action_selection == "Remove":
remove_debian(relver)
case "Devuan":
if action_selection == "Add":
add_devuan(relver)
if action_selection == "Remove":
remove_devuan(relver)
case "Fedora":
if action_selection == "Add":
add_fedora(relver)
if action_selection == "Remove":
remove_fedora(relver)
case "FreeBSD":
if action_selection == "Add":
add_freebsd(relver)
if action_selection == "Remove":
remove_freebsd(relver)
case "Kali Linux":
if action_selection == "Add":
add_kali()
if action_selection == "Remove":
remove_kali()
case "NetBSD":
if action_selection == "Add":
add_netbsd(relver)
if action_selection == "Remove":
remove_netbsd(relver)
case "NixOS":
if action_selection == "Add":
add_nixos()
if action_selection == "Remove":
remove_nixos()
case "Qubes":
if action_selection == "Add":
add_qubes(relver)
if action_selection == "Remove":
remove_qubes(relver)
case "Rocky Linux":
if action_selection == "Add":
add_rockylinux(relver)
if action_selection == "Remove":
remove_rockylinux(relver)
case "Tails":
if action_selection == "Add":
add_tails(relver)
if action_selection == "Remove":
remove_tails(relver)
case _:
print("Nothing to do.")