Files
Varaverk/claude-data/file-history/c06dbedf-e11b-4a72-9f81-d52cb662225e/189af64ace56c3a7@v2
T

149 lines
4.4 KiB
Bash

#!/bin/bash
# Bulk-add orphaned shows to Sonarr from dry-run output
# Usage: sonarr_bulk_add.sh [--add] (default: dry-run)
SONARR_URL="http://localhost:8989"
SONARR_API_KEY="130decd3db5b4c25afad64864cd03f9f"
ORPHAN_FILE="/tmp/sonarr_dryrun3.txt"
ADD_MODE=false
[[ "${1:-}" == "--add" ]] && ADD_MODE=true
declare -A PATH_ROOT=(
["/mnt/user/Tv_Shows"]="/tv"
["/mnt/user/Kids_Tv_Shows"]="/kids tv"
["/mnt/user/Anime_Shows-Old"]="/ext-anime-shows"
)
declare -A PATH_QUALITY=(
["/mnt/user/Tv_Shows"]="6"
["/mnt/user/Kids_Tv_Shows"]="2"
["/mnt/user/Anime_Shows-Old"]="6"
)
declare -A PATH_TYPE=(
["/mnt/user/Tv_Shows"]="standard"
["/mnt/user/Kids_Tv_Shows"]="standard"
["/mnt/user/Anime_Shows-Old"]="anime"
)
sonarr_get() { curl -sf -H "X-Api-Key: $SONARR_API_KEY" "${SONARR_URL}/api/v3/${1}"; }
sonarr_post() { curl -sf -X POST -H "X-Api-Key: $SONARR_API_KEY" -H "Content-Type: application/json" -d "$2" "${SONARR_URL}/api/v3/${1}"; }
# Build unique list: "fs_root|show_name"
declare -A SEEN
declare -a SHOWS
while IFS= read -r line; do
fs_root=$(echo "$line" | grep -oP '/mnt/user/[^/]+')
show_name=$(echo "$line" | grep -oP '/mnt/user/[^/]+/\K[^/]+')
key="${fs_root}|${show_name}"
[[ -z "$show_name" || -z "$fs_root" ]] && continue
[[ -n "${SEEN[$key]:-}" ]] && continue
SEEN["$key"]=1
SHOWS+=("$key")
done < <(grep "ORPHAN" "$ORPHAN_FILE")
# Get existing series titles in Sonarr
EXISTING=$(sonarr_get "series" | jq -r '.[].title' | sort)
ADDED=0
SKIPPED=0
NOT_FOUND=0
ALREADY=0
for entry in "${SHOWS[@]}"; do
fs_root="${entry%%|*}"
show_name="${entry##*|}"
root_path="${PATH_ROOT[$fs_root]:-}"
quality_id="${PATH_QUALITY[$fs_root]:-6}"
series_type="${PATH_TYPE[$fs_root]:-standard}"
if [[ -z "$root_path" ]]; then
echo "SKIP (unknown path): $show_name ($fs_root)"
(( SKIPPED++ ))
continue
fi
# Check if already in Sonarr
if echo "$EXISTING" | grep -qi "^${show_name}$"; then
echo "ALREADY: $show_name"
(( ALREADY++ ))
continue
fi
# Search TVDB via Sonarr lookup
encoded=$(jq -rn --arg s "$show_name" '$s | @uri')
result=$(sonarr_get "series/lookup?term=${encoded}" 2>/dev/null)
if [[ -z "$result" || "$result" == "[]" ]]; then
echo "NOT FOUND: $show_name"
(( NOT_FOUND++ ))
continue
fi
# Pick best match: exact title, then first result
best=$(echo "$result" | jq --arg name "$show_name" '
. as $all |
(map(select(.title | ascii_downcase == ($name | ascii_downcase))) | first) //
$all[0]
')
tvdb_id=$(echo "$best" | jq -r '.tvdbId // empty')
matched_title=$(echo "$best" | jq -r '.title // empty')
year=$(echo "$best" | jq -r '.year // 0')
if [[ -z "$tvdb_id" ]]; then
echo "NOT FOUND: $show_name"
(( NOT_FOUND++ ))
continue
fi
if [[ "$ADD_MODE" == false ]]; then
echo "WOULD ADD: $show_name → \"$matched_title\" ($year) [tvdb:$tvdb_id] [root:$root_path] [type:$series_type]"
(( ADDED++ ))
continue
fi
# Build payload from lookup result + our settings
payload=$(echo "$best" | jq \
--arg root "$root_path" \
--argjson qid "$quality_id" \
--arg stype "$series_type" \
'{
tvdbId: .tvdbId,
title: .title,
titleSlug: .titleSlug,
images: .images,
seasons: .seasons,
year: .year,
rootFolderPath: $root,
qualityProfileId: $qid,
seriesType: $stype,
seasonFolder: true,
monitored: true,
addOptions: {
monitor: "all",
searchForMissingEpisodes: false,
searchForCutoffUnmetEpisodes: false
}
}')
response=$(sonarr_post "series" "$payload" 2>&1)
if echo "$response" | jq -e '.id' &>/dev/null; then
echo "ADDED: \"$matched_title\" ($year) [tvdb:$tvdb_id]"
(( ADDED++ ))
else
err=$(echo "$response" | jq -r '.[0].errorMessage // .message // "unknown error"' 2>/dev/null)
echo "FAILED: $show_name$err"
(( SKIPPED++ ))
fi
done
echo ""
echo "━━━ Summary ━━━"
if [[ "$ADD_MODE" == false ]]; then
echo "Would add: $ADDED"
else
echo "Added: $ADDED"
fi
echo "Already in: $ALREADY"
echo "Not found: $NOT_FOUND"
echo "Skipped: $SKIPPED"