u/mamamelahastaelfondo

▲ 38 r/sonarr

I wrote a script to automatically block and purge fake releases (exe/scr/lnk) from Transmission and Sonarr

Like many of you, I got tired of Sonarr occasionally grabbing fake, malicious releases packed with .exe, .scr, or .lnk files instead of actual video files. Cleaning them out manually, removing them from Transmission, and blocklisting them in Sonarr gets old fast.

I didn't want to switch to a different torrent client just for this, so I wrote a Bash script that acts as a Transmission event hook (script-torrent-added and script-torrent-done).

What it does:

  1. Checks the Label: It verifies if the added torrent matches your Sonarr label so it doesn't mess with your personal, non-Sonarr downloads.
  2. Waits for Metadata: If it’s a magnet link, it safely waits for the file list to populate.
  3. Scans for Fakes: It checks the file extensions against a forbidden list (exe|scr|lnk|bat|vbs).
  4. Triggers Sonarr API: If a fake is detected, it hits the Sonarr API to fail the download, add it to Sonarr's blocklist (so it searches for a new release), and instructs Sonarr to remove it from the client.
  5. Fail-safe Cleanup: If Sonarr doesn't catch it for some reason, the script forces Transmission to remove the torrent and wipe the local data anyway.

The Script

#!/usr/bin/env bash
# sonarr-block-fakes.sh — purge fake releases from Transmission/Sonarr.
# Invoked by Transmission as script-torrent-added / script-torrent-done.

set -euo pipefail

SONARR_URL="http://localhost:8989/" # change it to your sonnar endpoint.
SONARR_API_KEY="" # get it from your sonarr settings.

TRANSMISSION_HOST="127.0.0.1:9091" # change it to your transmission endpoint.
TRANSMISSION_AUTH=""   # e.g. "-n user:pass" if rpc-authentication-required is true

SONARR_LABEL="sonarr-downloads" # the label defined in your sonarr instance for transmission.
FORBIDDEN_EXT="exe|scr|lnk|bat|vbs"

LOG_FILE="${LOG_FILE:-/PATH/TO/LOGS/clean_sonarr_fakes.log}"

mkdir -p "$(dirname "$LOG_FILE")"
log() { printf '%s [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "${TR_TORRENT_NAME:-?}" "$*" >> "$LOG_FILE"; }

: "${TR_TORRENT_ID:?TR_TORRENT_ID not set — run me from Transmission}"
: "${TR_TORRENT_HASH:?TR_TORRENT_HASH not set}"
TR_TORRENT_DIR="${TR_TORRENT_DIR:-}"
TR_TORRENT_NAME="${TR_TORRENT_NAME:-id-$TR_TORRENT_ID}"

log "Triggered: id=$TR_TORRENT_ID hash=$TR_TORRENT_HASH dir=$TR_TORRENT_DIR labels=${TR_TORRENT_LABELS:-}"

tr_remote() {
    # shellcheck disable=SC2086
    transmission-remote "$TRANSMISSION_HOST" $TRANSMISSION_AUTH "$@"
}

labels="${TR_TORRENT_LABELS:-}"
if [[ -z "$labels" ]]; then
    labels="$(tr_remote -t "$TR_TORRENT_ID" -i 2>/dev/null | awk -F': ' '/^[[:space:]]*Labels:/ {print $2; exit}')"
fi

label_matched=0
IFS=',' read -ra _labels <<< "$labels"
for l in "${_labels[@]}"; do
    # trim whitespace
    l="${l#"${l%%[![:space:]]*}"}"
    l="${l%"${l##*[![:space:]]}"}"
    if [[ "${l,,}" == "${SONARR_LABEL,,}" ]]; then
        label_matched=1
        break
    fi
done

if (( label_matched == 0 )); then
    echo "Not a Sonarr download, skipping check."
    log "Skip: torrent labels ('$labels') do not include SONARR_LABEL ($SONARR_LABEL)"
    exit 0
fi

# Magnet metadata can take 10-60s to arrive after script-torrent-added.
META_WAIT_TRIES=30
META_WAIT_SLEEP=2
files=""
metadata_ready=0
for _ in $(seq 1 "$META_WAIT_TRIES"); do
    files="$(tr_remote -t "$TR_TORRENT_ID" -f 2>/dev/null || true)"
    if [[ "$(printf '%s\n' "$files" | wc -l)" -gt 2 ]]; then
        metadata_ready=1
        break
    fi
    sleep "$META_WAIT_SLEEP"
done

if [[ -z "$files" ]]; then
    log "ERROR: could not list files via transmission-remote"
    exit 1
fi

if (( metadata_ready == 0 )); then
    log "WARN: file metadata not available after $((META_WAIT_TRIES * META_WAIT_SLEEP))s — script-torrent-done hook will retry on completion"
    exit 0
fi

offending="$(printf '%s\n' "$files" | grep -Ei "\.($FORBIDDEN_EXT)([[:space:]]|$)" || true)"

if [[ -z "$offending" ]]; then
    log "Clean — no forbidden extensions found"
    exit 0
fi

log "FAKE DETECTED. Offending entries:"
log "$offending"

hash_upper="${TR_TORRENT_HASH^^}"
queue_json="$(curl -fsS -m 15 -H "X-Api-Key: $SONARR_API_KEY" "$SONARR_URL/api/v3/queue?pageSize=1000&includeUnknownSeriesItems=true" || true)"

queue_id=""
if [[ -n "$queue_json" ]]; then
    queue_id="$(printf '%s' "$queue_json" | jq -r --arg h "$hash_upper" '.records[]? | select((.downloadId // "" | ascii_upcase) == $h) | .id' | head -n1)"
fi

if [[ -n "$queue_id" ]]; then
    log "Sonarr queue id=$queue_id — failing + blocklisting"
    http_code="$(curl -sS -m 15 -o /dev/null -w '%{http_code}' -X DELETE -H "X-Api-Key: $SONARR_API_KEY" "$SONARR_URL/api/v3/queue/${queue_id}?removeFromClient=true&blocklist=true&skipRedownload=false" || echo "000")"
    log "Sonarr DELETE /queue/$queue_id -> HTTP $http_code"
else
    log "No matching Sonarr queue entry for hash $hash_upper — purging Transmission only"
fi

if tr_remote -t "$TR_TORRENT_ID" -rad >>"$LOG_FILE" 2>&1; then
    log "Transmission: removed torrent + deleted local data"
else
    log "Transmission: remove returned non-zero (may already be gone via Sonarr)"
fi

exit 0

Setup Notes:

  • You'll need jq, curl, and transmission-remote installed on the host running the script.
  • Update the configuration variables at the top (SONARR_URL, SONARR_API_KEY, LOG_FILE, etc.).
  • Make the script executable (chmod +x) and add the path to your Transmission settings file (settings.json) under script-torrent-added-filename and script-torrent-done-filename. Make sure script-torrent-added-enabled is set to true.

Hope this helps anyone else trying to keep their Transmission setup clean without babysitting the queue. Let me know if you have any questions or improvements.

reddit.com
u/mamamelahastaelfondo — 3 days ago

No puede ser que alguien cree una cuenta hace 20 minutos para venir a darnos cátedra de "salud mental" y "buena onda" en este antro. Me encanta la audacia del infante que todavía tiene el mail de confirmación de Reddit en la bandeja de entrada y ya decidió que todos acá somos "treintañeros amargados".

A ver, "Brayan promedio" que se desahoga por problemas de primer mundo en un país donde el asfalto se derrite a "temperatura ambiente": no es que José el funcionario o Michi la manic pixie sean malas personas. Es que ya pasamos por la etapa de creer que el mundo se arregla con un post de "sean buenos prójimos" mientras esperamos el 27 (QEPD) que no viene nunca.

¿Te da "paja" crear otro subreddit? No te da paja, lo que pasa es que sabés que si abrís un grupo de "Paraguay Osos Cariñosos & Teletubbies con TDAH" vas a estar vos solo hablando con el bot de bienvenida.

reddit.com
u/mamamelahastaelfondo — 16 days ago