Files
Unraid_Intel-ARC_Deployment/sab_speed_control.sh
2025-03-01 11:43:06 -05:00

160 lines
6.5 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Adjust SABnzbd Speed Limit Based on Tautulli Remote Bandwidth Usage (Looping)
# -------------------------------------------------------------------
# This script continuously queries Tautulli for Plex activity, counts remote
# sessions, sums their total bandwidth usage, rounds the total up to the nearest MB,
# and adjusts SABnzbds speed limit accordingly.
#
# It also verifies Tautulli returns a valid JSON structure. If Tautulli is
# unreachable or the address is fake, it will log an error instead of claiming success.
#
# -------------------------------------------------------------------
# Configuration Variables:
# -------------------------------------------------------------------
# Tautulli API configuration:
TAUTULLI_API_KEY="dad9bbb78bde43249754b630b58fbf7c"
TAUTULLI_URL="http://10.0.0.10:8181/api/v2" # Make sure protocol & domain are correct!
# SABnzbd API configuration:
SAB_ADDRESS="http://10.0.0.10:8080"
SAB_API_KEY="86a11e19dcb1400a869773be38abc9bf"
# Speed limit settings:
BASE_SPEED_LIMIT_MB=110 # Base SABnzbd speed limit in MB/s
OFFSET_PER_USER_MB=3 # Reduce speed by X MB/s for each remote user
MIN_SPEED_MB=10 # Minimum speed limit in MB/s
# Local network configuration - this is to ignore local connections from Tatutulli (because does not affect speed)
LOCAL_IP_PREFIX="10.0.0."
# Loop interval:
WAIT_INTERVAL=3 # Seconds between checks
# -------------------------------------------------------------------
# Logging Function
# -------------------------------------------------------------------
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# -------------------------------------------------------------------
# check_tautulli_connection:
# Confirms Tautulli returns HTTP 200 and valid JSON with .response.data.sessions
# -------------------------------------------------------------------
check_tautulli_connection() {
log_message "Checking connection to Tautulli API at ${TAUTULLI_URL}"
# Make a request, capture HTTP status & body separately
http_response=$(curl -s -w "HTTPSTATUS:%{http_code}" -o /tmp/tautulli_check.json \
"${TAUTULLI_URL}?apikey=${TAUTULLI_API_KEY}&cmd=get_activity")
# Extract the status code
status_code=$(echo "$http_response" | sed -n 's/.*HTTPSTATUS://p')
# Read the response body from the temp file
body=$(cat /tmp/tautulli_check.json)
if [ "$status_code" -ne 200 ]; then
log_message "ERROR: Tautulli returned HTTP status $status_code. Check your URL or API key."
return 1
fi
# Ensure we have the key .response.data.sessions in the JSON
if ! echo "$body" | jq -e '.response.data.sessions' >/dev/null 2>&1; then
log_message "ERROR: Tautulli's JSON is missing .response.data.sessions. Possibly an invalid response."
return 1
fi
log_message "Successfully connected to Tautulli."
return 0
}
# -------------------------------------------------------------------
# adjust_sab_speed_limit:
# Retrieves current Tautulli data, calculates new SAB speed,
# and updates SABnzbd using the 4.4 API format.
# -------------------------------------------------------------------
adjust_sab_speed_limit() {
# Make a fresh request for current Tautulli data
http_response=$(curl -s -w "HTTPSTATUS:%{http_code}" -o /tmp/tautulli_data.json \
"${TAUTULLI_URL}?apikey=${TAUTULLI_API_KEY}&cmd=get_activity")
status_code=$(echo "$http_response" | sed -n 's/.*HTTPSTATUS://p')
body=$(cat /tmp/tautulli_data.json)
if [ "$status_code" -ne 200 ]; then
log_message "ERROR: Tautulli returned HTTP status $status_code. Skipping SABnzbd update."
return
fi
# Check that the JSON structure is correct
if ! echo "$body" | jq -e '.response.data.sessions' >/dev/null 2>&1; then
log_message "ERROR: Tautulli's JSON is missing .response.data.sessions. Skipping SABnzbd update."
return
fi
# Count remote sessions (where IP does not start with LOCAL_IP_PREFIX)
remote_count=$(echo "$body" | jq "[.response.data.sessions[]?
| select(.ip_address | startswith(\"${LOCAL_IP_PREFIX}\") | not)]
| length")
# Sum the remote sessions' bandwidth
total_bandwidth=$(echo "$body" | jq "[.response.data.sessions[]?
| select(.ip_address | startswith(\"${LOCAL_IP_PREFIX}\") | not)
| .bandwidth]
| add")
if [ -z "$total_bandwidth" ] || [ "$total_bandwidth" = "null" ]; then
total_bandwidth=0
fi
# Round up to the nearest integer
rounded_bandwidth=$(echo "$total_bandwidth" | awk '{if($1==int($1)){print $1}else{print int($1)+1}}')
log_message "Detected ${remote_count} remote streaming session(s) with a total bandwidth of ${rounded_bandwidth} MB/s."
# Subtract both the per-user offset and the total remote bandwidth
reduction=$(( remote_count * OFFSET_PER_USER_MB ))
new_speed=$(( BASE_SPEED_LIMIT_MB - reduction - rounded_bandwidth ))
if [ "$new_speed" -lt "$MIN_SPEED_MB" ]; then
new_speed=$MIN_SPEED_MB
fi
# Log the calculation details first
log_message "(Base: ${BASE_SPEED_LIMIT_MB} MB/s, Offset: ${remote_count} x ${OFFSET_PER_USER_MB} MB/s, Remote BW: ${rounded_bandwidth} MB/s)"
# Then log the final speed
log_message "Calculated new SABnzbd speed limit: ${new_speed} MB/s"
# Update SABnzbd
sab_api_url="${SAB_ADDRESS}/api?mode=config&name=speedlimit&apikey=${SAB_API_KEY}&value=${new_speed}M"
log_message "Sending SABnzbd API request: ${sab_api_url}"
sab_response=$(curl -s -w "HTTPSTATUS:%{http_code}" "$sab_api_url")
sab_body=$(echo "$sab_response" | sed -e 's/HTTPSTATUS\:.*//g')
sab_status=$(echo "$sab_response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
if [ "$sab_status" -eq 200 ]; then
log_message "SABnzbd speed limit successfully updated. Response: ${sab_body}"
else
log_message "Error updating SABnzbd speed limit. HTTP status: ${sab_status}, Response: ${sab_body}"
fi
}
# -------------------------------------------------------------------
# Main Execution Loop
# -------------------------------------------------------------------
while true; do
# First confirm Tautulli is actually reachable & returning valid JSON
if ! check_tautulli_connection; then
log_message "Skipping speed adjustment due to Tautulli connection error."
else
# If Tautulli is valid, do the speed adjustment
adjust_sab_speed_limit
fi
log_message "Waiting for ${WAIT_INTERVAL} seconds before next check..."
echo ""
sleep "${WAIT_INTERVAL}"
done