160 lines
6.5 KiB
Bash
160 lines
6.5 KiB
Bash
#!/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 SABnzbd’s 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
|