Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lidarr/extended.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enableAudio="true" # true = enabled :: Enables the Audio script
enableVideo="true" # true = enabled :: Enables the Video script to run automatically
enableUnmappedFilesCleaner="false" # true = enabled :: Enables the UnmappedFilesCleaner script to run automatically
enableQueueCleaner="true" # true = enabled :: Enables the QueueCleaner script to run automatically
enableChangeCategory="true" # true = enabled :: Only Applys to Torrents; "enableQueueCleaner" must be true or this is ignored; Used to avoid Hit-and-Runs

##### SCRIPT INTERVALS
audioScriptInterval=15m #s or #m or #h or #d :: s = seconds, m = minutes, h = hours, d = days :: Amount of time between each script run, when script is enabled
Expand Down
1 change: 1 addition & 0 deletions radarr/extended.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ enableAutoConfig="false" # true = enabled :: Enables AutoConfig script to run af
enableExtras="false" # true = enabled :: Enables Extras and AutoExtras scripts to run in the background and during import process
enableRecyclarr="false" # true = enabled :: Enables Recyclarr to run
enableQueueCleaner="false" # true = enabled :: Enables QueueCleaner Script that automatically removes stuck downloads that cannot be automatically imported
enableChangeCategory="true" # true = enabled :: Only Applys to Torrents; "enableQueueCleaner" must be true or this is ignored; Used to avoid Hit-and-Runs
enableUnmappedFolderCleaner="false" # true = enabled :: Purges any folders that are considered Unmapped in Radarr
enableInvalidMoviesAutoCleaner="false" # true = enabled :: Enables InvalidMoviesAutoCleaner script to run, removes movies that are no longer mapped to TMDB site

Expand Down
1 change: 1 addition & 0 deletions readarr/extended.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
##### SCRIPT ENABLEMENT
enableAutoConfig="true" # true = enabled :: Enables AutoConfig script to run after startup
enableQueueCleaner="true" # true = enabled :: Enables QueueCleaner Script that automatically removes stuck downloads that cannot be automatically imported
enableChangeCategory="true" # true = enabled :: Only Applys to Torrents; "enableQueueCleaner" must be true or this is ignored; Used to avoid Hit-and-Runs

##### SCRIPT INTERVALS
queueCleanerScriptInterval=15m #s or #m or #h or #d :: s = seconds, m = minutes, h = hours, d = days :: Amount of time between each script run, when script is enabled
Expand Down
1 change: 1 addition & 0 deletions sonarr/extended.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enableInvalidSeriesAutoCleaner="false" # true = enabled :: Enables InvalidSeries
enableDailySeriesEpisodeTrimmer="false" # true = enabled :: Enables DailySeriesEpisodeTrimmer script to run
enableRecyclarr="false" # true = enabled :: Enables Recyclarr to run
enableQueueCleaner="false" # true = enabled :: Enables QueueCleaner Script that automatically removes stuck downloads that cannot be automatically imported
enableChangeCategory="true" # true = enabled :: Only Applys to Torrents; "enableQueueCleaner" must be true or this is ignored; Used to avoid Hit-and-Runs
enableUnmappedFolderCleaner="false" # true = enabled :: Purges any folders that are considered Unmapped in Sonarr

##### SCRIPT INTERVALS
Expand Down
185 changes: 102 additions & 83 deletions universal/services/QueueCleaner
Original file line number Diff line number Diff line change
@@ -1,108 +1,127 @@
#!/usr/bin/with-contenv bash
scriptVersion="2.0"

scriptVersion="2.1"
scriptName="QueueCleaner"

#### Import Settings
source /config/extended.conf

#### Import Functions
source /config/extended/functions

#### Create Log File
logfileSetup

#### Check Arr App
getArrAppInfo
verifyApiAccess

verifyConfig () {
#### Import Settings
source /config/extended.conf
if [ "$enableQueueCleaner" != "true" ]; then
log "Script is not enabled, enable by setting enableQueueCleaner to \"true\" by modifying the \"/config/extended.conf\" config file..."
log "Sleeping (infinity)"
sleep infinity
fi

if [ -z "$queueCleanerScriptInterval" ]; then
queueCleanerScriptInterval="15m"
fi
## Import Settings
source /config/extended.conf

if [ "$enableQueueCleaner" != "true" ]; then
log "Script is not enabled, enable by setting enableQueueCleaner=\"true\" in /config/extended.conf..."
log "Sleeping (infinity)"
sleep infinity
fi

if [ -z "$queueCleanerScriptInterval" ]; then
queueCleanerScriptInterval="15m"
fi
}

QueueCleanerProcess () {
arrQueueData=""
arrApp=""

# Sonarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v3/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownSeriesItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="sonarr"
fi

# Radarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v3/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownMovieItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="radarr"
fi

# Lidarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v1/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownArtistItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="lidarr"
fi

# Readarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v1/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownAuthorItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="readarr"
fi

arrQueueIdCount=$(echo "$arrQueueData" | jq -r ".id" | wc -l)
arrQueueCompletedIds=$(echo "$arrQueueData" | jq -r 'select(.status=="completed") | select(.trackedDownloadStatus=="warning") | .id')
arrQueueIdsCompletedCount=$(echo "$arrQueueData" | jq -r 'select(.status=="completed") | select(.trackedDownloadStatus=="warning") | .id' | wc -l)
arrQueueFailedIds=$(echo "$arrQueueData" | jq -r 'select(.status=="failed") | .id')
arrQueueIdsFailedCount=$(echo "$arrQueueData" | jq -r 'select(.status=="failed") | .id' | wc -l)
arrQueueStalledIds=$(echo "$arrQueueData" | jq -r 'select(.status=="stalled") | .id')
arrQueueIdsStalledount=$(echo "$arrQueueData" | jq -r 'select(.status=="stalled") | .id' | wc -l)
arrQueuedIds=$(echo "$arrQueueCompletedIds"; echo "$arrQueueFailedIds"; echo "$arrQueueStalledIds")
arrQueueIdsCount=$(( $arrQueueIdsCompletedCount + $arrQueueIdsFailedCount + $arrQueueIdsStalledount ))

# Debugging
#echo "$arrQueueIdsCount :: $arrQueueIdsCompletedCount + $arrQueueIdsFailedCount + $arrQueueIdsStalledount"
#echo "$arrQueueCompletedIds"
#echo "$arrQueueFailedIds"
#echo "$arrQueueStalledIds"
#exit

if [ $arrQueueIdsCount -eq 0 ]; then
log "$arrQueueIdCount items in queue, no items in queue to clean up"
else
for queueId in $(echo $arrQueuedIds); do
arrQueueItemData="$(echo "$arrQueueData" | jq -r "select(.id==$queueId)")"
arrQueueItemTitle="$(echo "$arrQueueItemData" | jq -r .title)"
if [ "$arrApp" == "sonarr" ]; then
arrEpisodeId="$(echo "$arrQueueItemData" | jq -r .episodeId)"
arrEpisodeData="$(curl -s "$arrUrl/api/v3/episode/$arrEpisodeId?apikey=${arrApiKey}")"
arrEpisodeTitle="$(echo "$arrEpisodeData" | jq -r .title)"
arrEpisodeSeriesId="$(echo "$arrEpisodeData" | jq -r .seriesId)"
if [ "$arrEpisodeTitle" == "TBA" ]; then
log "$queueId ($arrQueueItemTitle) :: ERROR :: Episode title is \"$arrEpisodeTitle\" and prevents auto-import, refreshing series..."
refreshSeries=$(curl -s "$arrUrl/api/$arrApiVersion/command" -X POST -H 'Content-Type: application/json' -H "X-Api-Key: $arrApiKey" --data-raw "{\"name\":\"RefreshSeries\",\"seriesId\":$arrEpisodeSeriesId}")
continue
arrQueueData=""
arrApp=""

# Sonarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v3/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownSeriesItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="sonarr"
fi

# Radarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v3/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownMovieItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="radarr"
fi

# Lidarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v1/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownArtistItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="lidarr"
fi

# Readarr
if [ -z "$arrQueueData" ]; then
arrQueueData="$(curl -s "$arrUrl/api/v1/queue?page=1&pagesize=200&sortDirection=descending&sortKey=progress&includeUnknownAuthorItems=true&apikey=${arrApiKey}" | jq -r .records[])"
arrApp="readarr"
fi

arrQueueCompletedIds=$(echo "$arrQueueData" | jq -r 'select(.status=="completed") | select(.trackedDownloadStatus=="warning") | .id')
arrQueueFailedIds=$(echo "$arrQueueData" | jq -r 'select(.status=="failed") | .id')
arrQueueStalledIds=$(echo "$arrQueueData" | jq -r 'select(.status=="stalled") | .id')
arrQueuedIds=$(printf "%s\n%s\n%s" "$arrQueueCompletedIds" "$arrQueueFailedIds" "$arrQueueStalledIds")
arrQueueIdsCount=$(( $(echo "$arrQueueCompletedIds" | wc -l) + $(echo "$arrQueueFailedIds" | wc -l) + $(echo "$arrQueueStalledIds" | wc -l) ))

if [ $arrQueueIdsCount -eq 0 ]; then
log "$(echo "$arrQueueData" | jq -r ".id" | wc -l) items in queue, no items to clean up"
return
fi

for queueId in $arrQueuedIds; do
arrQueueItemData=$(echo "$arrQueueData" | jq -r "select(.id==$queueId)")
arrQueueItemTitle=$(echo "$arrQueueItemData" | jq -r .title)

# Sonarr episode handling (unchanged)
if [ "$arrApp" == "sonarr" ]; then
arrEpisodeId=$(echo "$arrQueueItemData" | jq -r .episodeId)
arrEpisodeData=$(curl -s "$arrUrl/api/v3/episode/$arrEpisodeId?apikey=${arrApiKey}")
arrEpisodeTitle=$(echo "$arrEpisodeData" | jq -r .title)
arrEpisodeSeriesId=$(echo "$arrEpisodeData" | jq -r .seriesId)

if [ "$arrEpisodeTitle" == "TBA" ]; then
log "$queueId ($arrQueueItemTitle) :: ERROR :: Episode title is \"$arrEpisodeTitle\" – refreshing series..."
curl -s "$arrUrl/api/$arrApiVersion/command" -X POST \
-H 'Content-Type: application/json' \
-H "X-Api-Key: $arrApiKey" \
--data-raw "{\"name\":\"RefreshSeries\",\"seriesId\":$arrEpisodeSeriesId}"
continue
fi
fi
fi
log "$queueId ($arrQueueItemTitle) :: Removing Failed Queue Item from $arrName..."
deleteItem=$(curl -sX DELETE "$arrUrl/api/$arrApiVersion/queue/$queueId?removeFromClient=true&blocklist=true&apikey=${arrApiKey}")

# Determine request parameters
removeFromClient="true"
extraParams=""

if [ "$enableChangeCategory" == "true" ]; then
protocol=$(echo "$arrQueueItemData" | jq -r '.protocol // empty')
if [ "$protocol" == "torrent" ]; then
removeFromClient="false"
extraParams="&changeCategory=true"
log "$queueId ($arrQueueItemTitle) :: Torrent – changing category only."
else
log "$queueId ($arrQueueItemTitle) :: Usenet – normal removal."
fi
else
log "$queueId ($arrQueueItemTitle) :: enableChangeCategory disabled – normal removal."
fi

requestUrl="$arrUrl/api/$arrApiVersion/queue/$queueId?removeFromClient=$removeFromClient&blocklist=true${extraParams}&apikey=${arrApiKey}"
deleteResp=$(curl -s -X DELETE "$requestUrl")
log "API response for $queueId: $deleteResp"
done
fi
}

for (( ; ; )); do
let i++
logfileSetup
verifyConfig
log "Starting..."
QueueCleanerProcess
log "Sleeping $queueCleanerScriptInterval..."
sleep $queueCleanerScriptInterval
let i++
logfileSetup
verifyConfig
log "Starting..."
QueueCleanerProcess
log "Sleeping $queueCleanerScriptInterval..."
sleep $queueCleanerScriptInterval
done

exit