This script is somewhat more special than the rest of the provided scripts because instead of reading the download health from the PVR, the script marks each download and then will remove the download the next time it is run iff. the download has not progressed at all.
In order to determine whether a download has not progressed in a certain amount of time, the script checks whether the byte size remaining to be downloaded has changed between the two executions of the script. Intuitively, if the script is placed in, say, /etc/cron.houry
on a Debianeqsque system, then a download will be removed iff. the download has not progressed any bytes within one hour.
Of course, this measure is relative, however, for most usage cases and considering the relatively small file size of music files, TV shows, maybe even movies iff. a download has not managed to download any byte within one hour, then more than likely the download is stalled. The former holds particularly true of torrent downloads where torrents do end up abandoned and beyond recovery if all seeders have left. In any case, the user can just schedule the subsequent execution of scripts at will, using crontab or similar such that the idle time can be scaled to each individual usage case.
#!/usr/bin/env bash ########################################################################### ## Copyright (C) Wizardry and Steamworks 2024 - License: GNU GPLv3 ## ########################################################################### # This script is a companion script for all servarr PVRs that is meant to # # remove stale downloads and additionall trigger a re-adownload of the # # stale download. This works by querrying all the servarr PVRs and then # # comparing the size left to download with the size left to download of # # previous run of this script. The script then assumes that if the size # # left to download is equal to the size to download of the previous run, # # then the torrent is stale and it is removed from the PVR with a new # # download triggered again and with optional blacklisting. # # # # Requirements (non-standard): # # * the sqlite3 command-line utility # # * jq JSON processing command-line utility # # # # The desired stale time to detect is equal to the time between two # # sequential executions of the script such that, ideally, this script # # should be called by crontab or similar. As an example, this script is # # used on Debian and placed in /etc/cron.hourly such that a download that # # has not progressed within an hour is removed from the PVR. # ########################################################################### ########################################################################### ## CONFIGURATION ## ########################################################################### # The path to the database file (temporary storage is ideal). DATABASE_FILE=/tmp/@rr-queue-state.sqlite # The path to a file that will be used as a lock file. LOCK_FILE='/tmp/@rr-queue-state.lock' PAGE_SIZE=1000 # Whether to blacklist a download release (automatically triggers a search # and download for a substitute release to download. BLOCKLIST=true # Whether to remove the release from the download client. REMOVE=false # Both SERVARR_* variables are configured sequentially where the fist URL # within SERVARR_QUEUE_URL matches the first API key in SERVARR_API_KEY. SERVARR_QUEUE_URL=( http://127.0.0.1:8686/lidarr/api/v1/queue http://127.0.0.1:8989/radarr/api/v3/queue http://127.0.0.1:8787/readarr/api/v1/queue http://127.0.0.1:8989/sonarr/api/v3/queue http://127.0.0.1:6969/whisparr/api/v3/queue ) SERVARR_API_KEY=( c0f52b1421be43889e538ef393595faa 49ce41a6241c4b8abb9593ddcfb9de57 39d53f275e044cc99b03f5a1d636a780 655dfefc291b47f382d646acd7f989a0 acb331effed7459e8f5bbde37d446148 ) ########################################################################### ## INTERNALS ## ########################################################################### # Acquire a lock. if mkdir $LOCK_FILE 2>&1 >/dev/null; then trap '{ rm -rf $LOCK_FILE; }' KILL QUIT TERM EXIT INT HUP else exit 0 fi for INDEX in "${!SERVARR_QUEUE_URL[@]}"; do QUEUE=`curl -s -X GET "${SERVARR_QUEUE_URL[$INDEX]}?apikey=${SERVARR_API_KEY[$INDEX]}&pageSize=$PAGE_SIZE" | \ jq -r ".records[] | [.sizeleft, .id] | @tsv"` # Create the database again if it does not exist. echo "CREATE TABLE IF NOT EXISTS 'queue' ( Size INTEGER NOT NULL, Hash STRING NOT NULL PRIMARY KEY );" | sqlite3 "$DATABASE_FILE" echo "$QUEUE" | while read DOWNLOAD; do ACTUAL_SIZE=`echo $DOWNLOAD | awk '{ print $1 }'` DOWNLOAD_ID=`echo $DOWNLOAD | awk '{ print $2 }'` if [ ! -z "$ACTUAL_SIZE" ] && [ ! -z "$DOWNLOAD_ID" ]; then # Check to see if the download was previously read. COUNT=`echo "SELECT COUNT() FROM 'queue' WHERE Hash='$DOWNLOAD_ID';" | sqlite3 "$DATABASE_FILE"` if [ $COUNT -gt 0 ]; then # If the download was previously read, then compare the last read size to the current size. LAST_SIZE=`echo "SELECT Size FROM 'queue' WHERE Hash='$DOWNLOAD_ID';" | sqlite3 "$DATABASE_FILE"` # If the last detected size remaining is lower or equal to the currernt size then the torrent is stale. if [ $ACTUAL_SIZE -eq $LAST_SIZE ]; then curl -X DELETE \ "${SERVARR_QUEUE_URL[$INDEX]}/$DOWNLOAD_ID?&apikey=${SERVARR_API_KEY[$INDEX]}&removeFromClient=$REMOVE&blocklist=$BLOCKLIST" 2>/dev/null 2>&1 echo "DELETE FROM 'queue' WHERE Hash='$DOWNLOAD_ID';" | sqlite3 "$DATABASE_FILE" else echo "REPLACE INTO 'queue' ( Size, Hash ) VALUES ( '$ACTUAL_SIZE' , '$DOWNLOAD_ID' );" | sqlite3 "$DATABASE_FILE" fi else # Insert the current size and the download hash into the datebase. echo "INSERT INTO 'queue' ( Size, Hash ) VALUES ( '$ACTUAL_SIZE' , '$DOWNLOAD_ID' );" | sqlite3 "$DATABASE_FILE" fi fi done done