Updating External IP Dynamically via DDClient

In complex LAN setups where qBittorrent may find itself behind a restrictive firewall, the external IP address reported to trackers and peers can be set by the user using the Connection\InetAddress= configuration key. Unfortunately, there is no built-in dynamic way of updating the external IP just with qBittorrent in case the external IP is dynamic. Furthermore, qBittorrent must be restarted for the Connection\InetAddress= to take effect.

In order to achieve an update of the qBittorrent external address, a bash script will be used that will be called from within a ddclient update block via the postscript configuration key:

use=cmd, \
cmd=/usr/local/sbin/up-ip, \
server=api.dyns.com, \
protocol=dyndns2, \
login=me@mail.us \
password='ribbits', \
me.dyns.net,
postscript=/usr/local/bin/update-qbittorrent-extip

Now, the /usr/local/bin/update-qbittorrent-extip will be executed on a successful update. the contents of the /usr/local/bin/update-qbittorrent-extip are the following:

#!/bin/bash
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2019 - License: GNU GPLv3      ##
###########################################################################
## Update a key-value pair based configuraton and restart the service.   ##
###########################################################################
#                                                                         #
# Remarks: The script will only update the file and/or restart the        #
# service in case the value has changed.                                  #
#                                                                         #
# Requirements:                                                           #
#   * bash                                                                #
#   * awk                                                                 #
#   * SystemD (systemctl)                                                 #
#   * md5sum                                                              #
#                                                                         #
# Applications: This script has been used to update the qbittorrent       #
# configuration from from ddclient after a successful update.             #
#                                                                         #
###########################################################################
 
###########################################################################
##                            CONFIGURATION                              ##
###########################################################################
 
# The configuration file.
CFG_FILE=/etc/qBittorrent/config/qBittorrent.conf
 
# The value to search for.
CFG_KEY='Connection\\InetAddress'
 
# The value to set.
CFG_VAL="$1"
 
# The service name.
SERVICE='qbittorrent-nox'
 
# Whether to restart the service.
RESTART=y
 
###########################################################################
##                              INTERNALS                                ##
###########################################################################
 
# Acquire a lock.
SCRIPT_NAME=$(echo $0 | md5sum)
LOCK_FILE='/var/lock/$SCRIPT_NAME'
if mkdir $LOCK_FILE 2>&1 >/dev/null; then
    trap '{ rm -rf $LOCK_FILE; }' KILL QUIT TERM EXIT INT HUP
else
    exit 0
fi
 
TMP=$(mktemp)
awk -F'=' -v K=${CFG_KEY} -v V="${CFG_VAL}" -v ret="0" '{ \
        if ($1 != K) { \
            print $0 \
        } else { \
            print K"="V; \
            ret = $2 != V \
        } \
    } \
    END { \
        exit ret \
    }' \
    $CFG_FILE >> $TMP
 
[ $? -eq 0 ] && exit
 
mv $TMP $CFG_FILE
 
[ $RESTART = 'y' ] && systemctl restart $SERVICE

External Ratio Management

qBittorrent-Ratio-Manager can be used to externally control when torrents get removed from qBittorrent. The tool is useful because qBittorrent does not yet have options to specify quotas and ratios for individual categories.

One qman file to be used with qBittorrent-Ratio-Manager is the following catch-all file:

all.qman
{
    "category": "*",
    "public": {
        "min_seed_ratio": 1.1,
        "max_seed_ratio": 1.1,
        "min_seed_time": 1,
        "max_seed_time": 1
    },
    "private": {
        "min_seed_ratio": 1.1,
        "max_seed_ratio": 1.1,
        "min_seed_time": 1,
        "max_seed_time": 1
    },
    "delete_files": true
}

that will, for all torrents managed by qBittorrent:

  • keep torrents until they have reached a seeding ratio of $1.1$ or,
  • have reached a maximum seed time of $1$ hour

qBittorrent-Ratio-Manager supports multiple categories such that just by adding a new qman file named myanonamouse-readarr.qman with the following content:

myanonamouse-readarr.qman
{
    "category": "readarr",
    "tracker": "t.myanonamouse.net",
    "public": {
        "min_seed_ratio": 2,
        "max_seed_ratio": 2,
        "min_seed_time": 72,
        "max_seed_time": 120
    },
    "private": {
        "min_seed_ratio": 2,
        "max_seed_ratio": 2,
        "min_seed_time": 72,
        "max_seed_time": 120
    },
    "delete_files": true
}

qBittorrent-Ratio-Manager will then delete all torrents in the readarr category that are downloaded from the t.myanonamouse.net tracker when:

  • a seed ratio of $2$ has been attained,
  • the torrents have been seeding for a minimum of $72$ hours, or
  • have been seeding for over $5$ days

All files can go directly in the qBittorrent-Ratio-Manager directory under configs/. The qbit_ratio_manager.py script should be called periodically and a good interval is $1$ hour since $1$ hour seems to be the minimal possible configurable seed time. This can be done by adding a script at /etc/cron.hourly/qBittorrent-Ratio-Manager with the following contents:

#!/bin/bash
 
/opt/qBittorrent-Ratio-Manager/qbit_ratio_manager.py 2>&1 2>/dev/null >/dev/null

where:

  • /opt/qBittorrent-Ratio-Manager/qbit_ratio_manager.py is the path to the qBittorrent-Ratio-Manager python script.

Torrent Queuing

Although not immediately apparent, when the torrent queuing option is enabled the Maximum active torrents, Maximum active uploads and Maximum active downloads settings can be set to a value of $-1$ in order to represent the infinity value and remove all limitations from those settings.

Solving Bottlenecks with Open Files

As a torrent client, qbittorrent needs to open many files in order to participate in the swarm. The problem is that qbittorrent is governed by the same policies that apply to all processes such that the globally and shared defined value for open files might be consumed entirely by qbittorrent leaving no other resources for other processes.

Given a single user system such as a seedbox, a solution would be to remove any limits for qbittorrent such that the globally shared values can be freely used by other processes.

Using systemd, perhaps the most elegant way is to edit the qbittorrent service file and add the LimitNOFILE under the [Service] section while setting it to infinity:

[Unit]
Description=qBittorrent BitTorrent Daemon
After=network.target

[Service]
LimitNOFILE=infinity
...

Command-Line Script to Add Torrent Files to qBittorrent

A very typical scenario consists in "Hit & Run" events with private trackers where, due to unforeseen circumstances, some torrents get removed from the torrent client before their minimal seed ratio or time has elapsed. What happens then is that the private tracker typically provides a download option for all torrents that have not been properly seeded in order to help the offender add them to the torrent client and seed them properly.

The option provided consists in a download of an archive that contains multiple torrent files but the problem with qBittorrent-nox is that there is no batch add option such that each torrent file would have to be added manually.

To the rescue, you can find the following script, that is a command-line bash script with which you can add a large number of torrent files from a directory. In order to use the script, save the script to a file, make it executable and then run it. Without any command-line parameters the script will print its usage syntax.

The syntax is fairly trivial, it requires a qBittorrent username, password, host and port, as well as a directory of torrent file to add to the qBittorrent instance.

#!/usr/bin/env bash
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2023 - License: GNU GPLv3      ##
##  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  ##
##  rights of fair usage, the disclaimer and warranty conditions.        ##
###########################################################################
# This script requires bash and ensures that specified torrents are added #
# to the qBittorrent queue including setting an optional category.        #
###########################################################################
 
ASCII_SPINNER=( ".oOo" "oOo." "Oo.o" "o.oO" )
ARGV=("$@")
 
print_usage() {
  cat << EOT
Usage: $0 [-u <username>] [-p <password>] [ -a <host or ip:port> ] [ -c <category> ] <FILE|TARGET>
EOT
}
 
while getopts ":u:p:a:c" PARAMETERS; do
    case "${PARAMETERS}" in
        u)
            QBITTORRENT_USERNAME=${OPTARG}
            ;;
        p)
            QBITTORRENT_PASSWORD=${OPTARG}
            ;;
        a)
            SPLIT=$(echo ${OPTARG} | awk -F ":" '{ print NF }')
            [ ${SPLIT} -eq 2 ] || (print_usage && exit 1)
            QBITTORRENT_ADDRESS=${OPTARG}
            ;;
        c)
            QBITTORRENT_CATEGORY=${OPTARG}
            ;;
        *)
            usage
            ;;
    esac
done
 
if [ ${OPTIND} = 1 ]; then
    print_usage
    exit 1
fi
 
shift $((OPTIND-1))
 
TARGET="${ARGV[${OPTIND}]}"
[ ! -d "${TARGET}" ] || [ ! -f "${TARGET}" ] || (print_usage && exit 1)
 
[ -z "${QBITTORRENT_USERNAME}" ] || \
[ -z "${QBITTORRENT_PASSWORD}" ] || \
[ -z "${QBITTORRENT_ADDRESS}" ] || \
[ -z "${QBITTORRENT_CATEGORY}" ] || \
[ -z "${TARGET}" ] || \
    (print_usage && exit 1)
 
COOKIE=$(curl \
    -s \
    -I \
    -X GET "http://${QBITTORRENT_ADDRESS}/api/v2/auth/login?username=${QBITTORRENT_USERNAME}&password=${QBITTORRENT_PASSWORD}" | \
    grep 'set\-cookie' | \
    sed -re 's/^set-cookie: (SID=[^;]+?);.+?$/\1/p' | \
    head -1)
 
for TORRENT_FILE in `find ${TARGET} -type f -print -iregex "^.+?\.torrent$"`; do
    HTTP_CODE=$(curl \
        -s \
        -o /dev/null \
        -w '%{http_code}\n' \
        --cookie "${COOKIE}" \
        --form "torrents=@${TORRENT_FILE}" \
        --form "category=${QBITTORRENT_CATEGORY}" \
        "http://${QBITTORRENT_ADDRESS}/api/v2/torrents/add")
    CAR="${ASCII_SPINNER[0]}"
    CDR=("${ASCII_SPINNER[@]:1:${#ASCII_SPINNER[@]}}")
    ASCII_SPINNER=(${CDR[@]} ${CAR})
    COLUMNS=`tput cols`
    FILE=$(head -c $(($COLUMNS - 19)) <<< ${TORRENT_FILE})
    STATUS=$([[ ${HTTP_CODE} = 200 ]] && echo "GOOD" || echo "FAIL")
    INFO="File ${FILE} ${STATUS} [ ${CAR} ]"
    SIZE=$(($(echo -n -e $INFO | wc -c) + 1)) 
    echo -n -e "\r${INFO}"
    yes "." | head -n $(($COLUMNS - $SIZE)) | xargs | tr -d ' ' | tr -d '\n' | sed  's/\./ /g'
done

fuss/qbittorrent.txt ยท Last modified: 2023/10/15 09:59 by office

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.