/ update_tracker.py
update_tracker.py
  1  # /// script
  2  # dependencies = [
  3  #   "qbittorrent-api",
  4  #   "docopt",
  5  #   "rich",
  6  # ]
  7  # ///
  8  
  9  """update_tracker.py
 10  
 11  Description:
 12  This script collects infohashes of all torrents in each qBittorrent instance,
 13  updates opentracker, and reannounces all torrents to their trackers.
 14  
 15  Expectations:
 16  - A JSON qBittorrent authentication file at ~/.config/qbittorrent_auth.json
 17  - SSH pubkey access to torrent tracker server
 18  - rsync installed on the host system running this script
 19  
 20  Usage:
 21      update_tracker.py (--add-tracker DOMAIN)
 22      update_tracker.py -h
 23  
 24  Options:
 25      --add-tracker DOMAIN           ensure the provided tracker domain is added to each torrent's tracker list
 26      -h, --help                     show this help message and exit
 27  
 28  Examples:
 29      update_tracker.py --add-tracker hyperreal.coffee
 30  """
 31  
 32  import json
 33  import subprocess
 34  import tempfile
 35  from pathlib import Path
 36  
 37  import qbittorrentapi
 38  from docopt import docopt
 39  from rich.console import Console
 40  from rich.text import Text
 41  
 42  if __name__ == "__main__":
 43      args = docopt(__doc__)  # type: ignore
 44  
 45      tracker_domain = args["--add-tracker"]
 46  
 47      console = Console()
 48      with console.status("[bold green]Executing the tasks...") as status:
 49          # JSON file containing authentication info for each qBittorrent instance
 50          QBITTORRENT_AUTH_FILE = Path.home().joinpath(".config/qbittorrent_auth.json")
 51  
 52          # Open authentication file and load JSON data
 53          with open(QBITTORRENT_AUTH_FILE, "r") as qbt_auth:
 54              auth_data = json.load(qbt_auth)
 55  
 56          # Collect infohashes of all torrents in each qBittorrent instance
 57          console.log(
 58              "Collecting infohashes of all torrents in each qBittorrent instance."
 59          )
 60          torrent_infohashes = []
 61          for item in auth_data["instances"]:
 62              with qbittorrentapi.Client(
 63                  host=item["hostname"],
 64                  username=item["username"],
 65                  password=item["password"],
 66              ) as qbt_client:
 67                  try:
 68                      qbt_client.auth_log_in()
 69                  except qbittorrentapi.LoginFailed as e:
 70                      print(e)
 71  
 72                  for torrent in qbt_client.torrents_info():
 73                      torrent_infohashes.append(torrent.hash)
 74  
 75          # Format the infohashes to have a \n at the end
 76          console.log("Formatting infohashes to have a newline at the end.")
 77          format_infohashes = set([f"{infohash}\n" for infohash in torrent_infohashes])
 78  
 79          # Create a NamedTemporaryFile and write all infohashes to it, one per line
 80          console.log("Creating temporary file to write infohashes to.")
 81  
 82          with tempfile.NamedTemporaryFile() as ntf:
 83              with open(ntf.name, "w") as tf:
 84                  tf.writelines(format_infohashes)
 85  
 86              # Use `sudo cp -f` to copy the infohashes file to the torrent tracker's config
 87              # directory, overwriting the whitelist.txt file.
 88              console.log(
 89                  "Copying the temporary infohashes file to the torrent tracker's whitelist."
 90              )
 91              subprocess.run(
 92                  ["sudo", "cp", "-f", ntf.name, "/etc/opentracker/whitelist.txt"]
 93              )
 94  
 95              # Run `sudo systemctl restart opentracker.service`
 96              console.log("Restarting opentracker.service")
 97              subprocess.run(["sudo", "systemctl", "restart", "opentracker.service"])
 98  
 99          # Reannounce all torrents in each qBittorrent instance to their trackers
100          console.log("Reannouncing all torrents to their trackers.")
101          for item in auth_data["instances"]:
102              with qbittorrentapi.Client(
103                  host=item["hostname"],
104                  username=item["username"],
105                  password=item["password"],
106              ) as qbt_client:
107                  for torrent in qbt_client.torrents_info():
108                      torrent.reannounce()
109  
110          console.log("Done!")
111  
112      # Print output and make it look sexy ;)
113      console = Console()
114      tasks = Text("\nTasks completed:\n")
115      tasks.stylize("bold magenta")
116      console.print(tasks)
117      console.print(":white_check_mark: update the tracker's whitelist")
118  
119      if tracker_domain:
120          console.print(
121              f":white_check_mark: ensure {tracker_domain}:6969/announce is in each torrent's tracker list"
122          )
123  
124      console.print(":white_check_mark: reannounce all torrents to their trackers")
125  
126      torrents = Text(str(len(torrent_infohashes)))
127      torrents.stylize("bold green")
128      console.print(torrents + " torrents were updated")