audit echo vs log across all scripts — outcomes always visible, verbose for per-item loops
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
#!/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
|
||||
case "$show_name" in
|
||||
"Baby.Daddy.S01-S06.1080p.WEB-DL.H.264-ROCCaT"|"Popeye (1960-1961)"|"Tom and Jerry Cartoons Complete Collection (1940-2007)"|"Bugs Bunny"|"2 Stupid Dogs - Super Secret Secret Squirrel")
|
||||
echo "SKIP (bad match): $show_name"
|
||||
continue ;;
|
||||
esac
|
||||
SHOWS+=("$key")
|
||||
done < <(grep "ORPHAN" "$ORPHAN_FILE")
|
||||
|
||||
# Get existing series TVDB IDs in Sonarr
|
||||
EXISTING_IDS=$(sonarr_get "series" | jq -r '.[].tvdbId')
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
# Check by TVDB ID — catches title mismatches (colons, special chars, etc.)
|
||||
if echo "$EXISTING_IDS" | grep -q "^${tvdb_id}$"; then
|
||||
echo "ALREADY: $show_name (\"$matched_title\" tvdb:$tvdb_id)"
|
||||
(( ALREADY++ ))
|
||||
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"
|
||||
Reference in New Issue
Block a user