Skip to content

Commit 8533489

Browse files
authored
Update sonarr-hunter.sh
1 parent e97ee7b commit 8533489

File tree

1 file changed

+106
-126
lines changed

1 file changed

+106
-126
lines changed

sonarr-hunter.sh

Lines changed: 106 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -5,187 +5,167 @@
55
# ---------------------------
66
# Use environment variables if provided; otherwise, fall back to defaults.
77
API_KEY=${API_KEY:-"your-api-key"}
8-
API_URL=${API_URL:-"http://your-address:8989"}
8+
API_URL=${API_URL:-"http://your-radarr-address:7878"}
99

10-
# How many shows to process before restarting the search cycle
11-
MAX_SHOWS=${MAX_SHOWS:-1}
10+
# How many movies to process before restarting the search cycle
11+
MAX_MOVIES=${MAX_MOVIES:-1}
1212

13-
# Sleep duration in seconds after finding a show with missing episodes
14-
# (900=15min, 600=10min, etc.)
15-
SLEEP_DURATION=${SLEEP_DURATION:-900}
13+
# Sleep duration in seconds after fully processing a movie (300=5min)
14+
SLEEP_DURATION=${SLEEP_DURATION:-300}
1615

17-
# Set to true to pick shows randomly, false to go in order
16+
# Shorter sleep duration between each processed movie (30=0.5min)
17+
REFRESH_DURATION=${REFRESH_DURATION:-30}
18+
19+
# Set to true to pick movies randomly, false to go in order
1820
RANDOM_SELECTION=${RANDOM_SELECTION:-true}
1921

2022
# ---------------------------
2123
# Main infinite loop
2224
# ---------------------------
2325
while true; do
24-
echo "Retrieving missing episodes data from Sonarr..."
25-
# Get all shows first
26-
SHOWS_JSON=$(curl -s \
26+
echo "Retrieving missing movies from Radarr..."
27+
28+
# Fetch all monitored movies that do not have files
29+
MISSING_MOVIES_JSON=$(curl -s \
2730
-H "X-Api-Key: $API_KEY" \
28-
"$API_URL/api/v3/series")
31+
"$API_URL/api/v3/movie" | \
32+
jq '[.[] | select(.monitored == true and .hasFile == false)]'
33+
)
2934

30-
# If the above command fails or returns nothing, wait and retry
31-
if [ -z "$SHOWS_JSON" ]; then
32-
echo "ERROR: Unable to retrieve series data from Sonarr. Retrying in 60 seconds..."
35+
if [ -z "$MISSING_MOVIES_JSON" ]; then
36+
echo "ERROR: Unable to retrieve movie data from Radarr. Retrying in 60 seconds..."
3337
sleep 60
3438
continue
3539
fi
3640

37-
# Filter to only get shows with missing episodes
38-
INCOMPLETE_SHOWS_JSON=$(echo "$SHOWS_JSON" | jq '[.[] | select(has("statistics") and .statistics.episodeCount > .statistics.episodeFileCount)]')
39-
40-
# Count how many incomplete shows are in the list
41-
TOTAL_INCOMPLETE=$(echo "$INCOMPLETE_SHOWS_JSON" | jq 'length')
42-
if [ "$TOTAL_INCOMPLETE" -eq 0 ]; then
43-
echo "No shows with missing episodes found in Sonarr. Waiting 60 seconds before checking again..."
41+
TOTAL_MISSING=$(echo "$MISSING_MOVIES_JSON" | jq 'length')
42+
if [ "$TOTAL_MISSING" -eq 0 ]; then
43+
echo "No missing movies found. Waiting 60 seconds before checking again..."
4444
sleep 60
4545
continue
4646
fi
47-
echo "Found $TOTAL_INCOMPLETE show(s) with missing episodes."
4847

48+
echo "Found $TOTAL_MISSING missing movie(s)."
4949
echo "Using ${RANDOM_SELECTION:+random}${RANDOM_SELECTION:-sequential} selection."
50-
echo "Will process up to ${MAX_SHOWS:-all} shows with ${SLEEP_DURATION}s pause between each."
50+
echo "Will process up to $MAX_MOVIES movies with a longer sleep of $SLEEP_DURATION seconds after the final one."
5151

52-
SHOWS_PROCESSED=0
52+
MOVIES_PROCESSED=0
5353
ALREADY_CHECKED=()
5454

5555
while true; do
56-
# Check if we've reached the maximum number of shows to process
57-
if [ "$MAX_SHOWS" -gt 0 ] && [ "$SHOWS_PROCESSED" -ge "$MAX_SHOWS" ]; then
58-
echo "Reached maximum number of shows to process ($MAX_SHOWS). Restarting search cycle..."
56+
# Check if we've reached the maximum number of movies to process
57+
if [ "$MAX_MOVIES" -gt 0 ] && [ "$MOVIES_PROCESSED" -ge "$MAX_MOVIES" ]; then
58+
echo "Reached maximum number of movies ($MAX_MOVIES). Restarting search cycle..."
5959
break
6060
fi
6161

62-
# Check if we've checked all incomplete shows
63-
if [ ${#ALREADY_CHECKED[@]} -eq "$TOTAL_INCOMPLETE" ] || [ "$TOTAL_INCOMPLETE" -eq 0 ]; then
64-
echo "All shows with missing episodes have been checked. Waiting before starting a new cycle..."
62+
# Check if we've checked all missing movies
63+
if [ ${#ALREADY_CHECKED[@]} -eq "$TOTAL_MISSING" ]; then
64+
echo "All missing movies have been checked. Waiting before starting a new cycle..."
6565
sleep 60
6666
break
6767
fi
6868

69-
# Select next show index based on selection method
70-
if [ "$RANDOM_SELECTION" = true ] && [ "$TOTAL_INCOMPLETE" -gt 1 ]; then
71-
# Keep generating random indices until we find one we haven't checked yet
69+
# Select next movie index based on selection method
70+
if [ "$RANDOM_SELECTION" = true ] && [ "$TOTAL_MISSING" -gt 1 ]; then
7271
while true; do
73-
INDEX=$((RANDOM % TOTAL_INCOMPLETE))
72+
INDEX=$((RANDOM % TOTAL_MISSING))
7473
if [[ ! " ${ALREADY_CHECKED[*]} " =~ " ${INDEX} " ]]; then
7574
break
7675
fi
7776
done
7877
else
79-
for ((i=0; i<TOTAL_INCOMPLETE; i++)); do
78+
for ((i=0; i<TOTAL_MISSING; i++)); do
8079
if [[ ! " ${ALREADY_CHECKED[*]} " =~ " ${i} " ]]; then
8180
INDEX=$i
8281
break
8382
fi
8483
done
8584
fi
8685

87-
# Add this index to the list of checked indices
8886
ALREADY_CHECKED+=("$INDEX")
8987

90-
# Extract show information
91-
SHOW=$(echo "$INCOMPLETE_SHOWS_JSON" | jq ".[$INDEX]")
92-
SHOW_ID=$(echo "$SHOW" | jq '.id')
93-
SHOW_TITLE=$(echo "$SHOW" | jq -r '.title')
94-
EPISODE_COUNT=$(echo "$SHOW" | jq '.statistics.episodeCount')
95-
EPISODE_FILE_COUNT=$(echo "$SHOW" | jq '.statistics.episodeFileCount')
96-
MISSING=$((EPISODE_COUNT - EPISODE_FILE_COUNT))
97-
98-
echo "Selected show \"$SHOW_TITLE\" with $MISSING missing episode(s)..."
99-
100-
# ---------------------------
101-
# Step 1: Refresh the series to make sure Sonarr has latest information
102-
# ---------------------------
103-
echo "1. Refreshing series information for \"$SHOW_TITLE\" (ID: $SHOW_ID)..."
104-
88+
# Extract movie information
89+
MOVIE=$(echo "$MISSING_MOVIES_JSON" | jq ".[$INDEX]")
90+
MOVIE_ID=$(echo "$MOVIE" | jq '.id')
91+
MOVIE_TITLE=$(echo "$MOVIE" | jq -r '.title')
92+
MOVIE_YEAR=$(echo "$MOVIE" | jq -r '.year')
93+
94+
echo "Selected missing movie \"$MOVIE_TITLE ($MOVIE_YEAR)\"..."
95+
96+
# 1. Refresh the movie
97+
echo "1. Refreshing movie information for \"$MOVIE_TITLE\"..."
10598
REFRESH_COMMAND=$(curl -s -X POST \
10699
-H "X-Api-Key: $API_KEY" \
107100
-H "Content-Type: application/json" \
108-
-d "{\"name\":\"RefreshSeries\",\"seriesId\":$SHOW_ID}" \
109-
"$API_URL/api/v3/command")
110-
111-
# Check if the refresh command succeeded
101+
-d "{\"name\":\"RefreshMovie\",\"movieIds\":[$MOVIE_ID]}" \
102+
"$API_URL/api/v3/command"
103+
)
104+
112105
REFRESH_ID=$(echo "$REFRESH_COMMAND" | jq '.id // empty')
113-
if [ -n "$REFRESH_ID" ]; then
114-
echo "Refresh command accepted (ID: $REFRESH_ID)."
115-
116-
# Wait for the refresh to complete
117-
echo "Waiting for refresh to complete..."
118-
sleep 5
119-
120-
# ---------------------------
121-
# Step 2: Tell Sonarr to search for missing episodes
122-
# ---------------------------
123-
echo "2. Telling Sonarr to perform a missing-episode search for \"$SHOW_TITLE\" (ID: $SHOW_ID)..."
124-
125-
SEARCH_COMMAND=$(curl -s -X POST \
126-
-H "X-Api-Key: $API_KEY" \
127-
-H "Content-Type: application/json" \
128-
-d "{\"name\":\"MissingEpisodeSearch\",\"seriesId\":$SHOW_ID}" \
129-
"$API_URL/api/v3/command")
130-
131-
# Verify the response from Sonarr
132-
SEARCH_ID=$(echo "$SEARCH_COMMAND" | jq '.id // empty')
133-
if [ -n "$SEARCH_ID" ]; then
134-
echo "Search command accepted (ID: $SEARCH_ID)."
135-
136-
# Wait a moment to let Sonarr process the command
137-
echo "Waiting 2 seconds to check command status..."
138-
sleep 2
139-
140-
# Check the status of the command
141-
COMMAND_STATUS=$(curl -s \
142-
-H "X-Api-Key: $API_KEY" \
143-
"$API_URL/api/v3/command/$SEARCH_ID" | jq -r '.status')
144-
145-
echo "Command status: $COMMAND_STATUS"
146-
SHOWS_PROCESSED=$((SHOWS_PROCESSED + 1))
147-
148-
# Sleep after processing a show with missing episodes
149-
echo "Show with missing episodes processed. Sleeping for $SLEEP_DURATION seconds to avoid overloading indexers..."
150-
sleep "$SLEEP_DURATION"
151-
else
152-
echo "WARNING: Search command did not return an ID. Response was:"
153-
echo "$SEARCH_COMMAND"
154-
echo "Trying alternative commands..."
155-
156-
# Try an alternative command for Sonarr v3
157-
SEARCH_COMMAND2=$(curl -s -X POST \
158-
-H "X-Api-Key: $API_KEY" \
159-
-H "Content-Type: application/json" \
160-
-d "{\"name\":\"EpisodeSearch\",\"seriesId\":$SHOW_ID}" \
161-
"$API_URL/api/v3/command")
162-
163-
SEARCH_ID2=$(echo "$SEARCH_COMMAND2" | jq '.id // empty')
164-
if [ -n "$SEARCH_ID2" ]; then
165-
echo "Alternative search command accepted (ID: $SEARCH_ID2)."
166-
SHOWS_PROCESSED=$((SHOWS_PROCESSED + 1))
167-
echo "Show with missing episodes processed. Sleeping for $SLEEP_DURATION seconds to avoid overloading indexers..."
168-
sleep "$SLEEP_DURATION"
169-
else
170-
echo "All search commands failed. Skipping this show."
171-
sleep 10
172-
fi
173-
fi
174-
else
175-
echo "WARNING: Refresh command did not return an ID. Response was:"
106+
if [ -z "$REFRESH_ID" ]; then
107+
echo "WARNING: Could not refresh \"$MOVIE_TITLE\". Response was:"
176108
echo "$REFRESH_COMMAND"
177-
echo "Skipping search for this show."
178-
179-
# Sleep a shorter time since we didn't actually do a search
109+
echo "Skipping this movie. Sleeping 10 seconds..."
180110
sleep 10
111+
continue
112+
fi
113+
114+
echo "Refresh command accepted (ID: $REFRESH_ID). Waiting 5 seconds for refresh to complete..."
115+
sleep 5
116+
117+
# 2. Search for the movie using "MoviesSearch"
118+
echo "2. Searching for \"$MOVIE_TITLE\"..."
119+
SEARCH_COMMAND=$(curl -s -X POST \
120+
-H "X-Api-Key: $API_KEY" \
121+
-H "Content-Type: application/json" \
122+
-d "{\"name\":\"MoviesSearch\",\"movieIds\":[$MOVIE_ID]}" \
123+
"$API_URL/api/v3/command"
124+
)
125+
126+
SEARCH_ID=$(echo "$SEARCH_COMMAND" | jq '.id // empty')
127+
if [ -n "$SEARCH_ID" ]; then
128+
echo "Search command accepted (ID: $SEARCH_ID)."
129+
else
130+
echo "WARNING: Search command failed for \"$MOVIE_TITLE\". Response was:"
131+
echo "$SEARCH_COMMAND"
132+
fi
133+
134+
echo "Waiting 5 seconds for search operation..."
135+
sleep 5
136+
137+
# 3. Rescan the movie folder
138+
echo "3. Rescanning movie folder for \"$MOVIE_TITLE\"..."
139+
RESCAN_COMMAND=$(curl -s -X POST \
140+
-H "X-Api-Key: $API_KEY" \
141+
-H "Content-Type: application/json" \
142+
-d "{\"name\":\"RescanMovie\",\"movieIds\":[$MOVIE_ID]}" \
143+
"$API_URL/api/v3/command"
144+
)
145+
146+
RESCAN_ID=$(echo "$RESCAN_COMMAND" | jq '.id // empty')
147+
if [ -n "$RESCAN_ID" ]; then
148+
echo "Rescan command accepted (ID: $RESCAN_ID)."
149+
else
150+
echo "WARNING: Rescan command not available or failed."
151+
fi
152+
153+
MOVIES_PROCESSED=$((MOVIES_PROCESSED + 1))
154+
155+
# Sleep before processing the next movie
156+
if [ "$MOVIES_PROCESSED" -ge "$MAX_MOVIES" ]; then
157+
echo "Processed $MOVIES_PROCESSED movies. Sleeping for $SLEEP_DURATION seconds..."
158+
sleep "$SLEEP_DURATION"
159+
else
160+
echo "Movie refreshed. Sleeping for $REFRESH_DURATION seconds before continuing..."
161+
sleep "$REFRESH_DURATION"
181162
fi
182163
done
183164

184-
echo "Done. Processed $SHOWS_PROCESSED shows with missing episodes in this cycle."
185-
186-
# If we didn't find any shows to process in this cycle, wait a bit before starting a new cycle
187-
if [ "$SHOWS_PROCESSED" -eq 0 ]; then
188-
echo "No shows with missing episodes processed this cycle. Waiting 60 seconds before starting a new cycle..."
165+
echo "Done. Processed $MOVIES_PROCESSED missing movies in this cycle."
166+
167+
if [ "$MOVIES_PROCESSED" -eq 0 ]; then
168+
echo "No missing movies processed this cycle. Waiting 60 seconds before starting a new cycle..."
189169
sleep 60
190170
fi
191171
done

0 commit comments

Comments
 (0)