From a52c912a27c60dbc80ab352b0aaa90899e509c7d Mon Sep 17 00:00:00 2001 From: Admin9705 <24727006+Admin9705@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:39:17 -0500 Subject: [PATCH] Update sab_speed_control.sh --- sab_speed_control.sh | 207 ++++++++++++++++++++++++++++++------------- 1 file changed, 143 insertions(+), 64 deletions(-) diff --git a/sab_speed_control.sh b/sab_speed_control.sh index 1e10038..15263d9 100644 --- a/sab_speed_control.sh +++ b/sab_speed_control.sh @@ -1,80 +1,159 @@ #!/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: +# ------------------------------------------------------------------- -# ============================================================ -# Script Name: SAB Speed Control -# Author: Admin9705 -# ============================================================ -# NOTE: Control DL speeds while others are watching PLEX -# ============================================================ - -# v1 - Initial Script | v2 - Added Night Speeds - -# Configuration -SABNZBD_API_KEY="60x7fega60f642d489ed89f08c4f8a80fake" -SABNZBD_URL="http://10.0.0.10:8081/sabnzbd/api" -SLOW_SPEED="65000000" # DL Speed when Plex IS playing for a user -NORMAL_SPEED="85000000" # DL Speed when Plex is NOT playing for a user -NIGHT_SPEED="125000000" # DL Speed when not using Internet and when Plex NOT playing for a user (such as Night) - -# 125000000 is 118.2 MB | 80000000 is 76.3 MB - -NIGHT_START="01" # Start hour for nighttime speed (24-hour format) (01 is 0100 AM or 0100hrs) -NIGHT_END="07" # End hour for nighttime speed (24-hour format) (07 is 0700 AM or 0700hrs) - -# Type Date in CMD Line to ENSURE that SERVER TIME matches/aligns as a test - -CHECK_INTERVAL=10 # Seconds between checks +# Tautulli API configuration: TAUTULLI_API_KEY="dad9bbb78bde43249754b630b58fbf7c" -TAUTULLI_URL="http://10.0.0.10:8181/api/v2" +TAUTULLI_URL="http://10.0.0.10:8181/api/v2" # Make sure protocol & domain are correct! -# Function to set SABnzbd speed limit -set_sab_speed() { - local speed=$1 - local full_url="${SABNZBD_URL}?mode=config&name=speedlimit&value=${speed}&apikey=${SABNZBD_API_KEY}" +# SABnzbd API configuration: +SAB_ADDRESS="http://10.0.0.10:8080" +SAB_API_KEY="86a11e19dcb1400a869773be38abc9bf" - echo "$(date '+%Y-%m-%d %H:%M:%S') - Sending request to set SABnzbd speed to ${speed} KB/s" - response=$(curl -s "${full_url}") +# Speed limit settings: +BASE_SPEED_LIMIT_MB=50 # Base SABnzbd speed limit in MB/s +OFFSET_PER_USER_MB=5 # Reduce speed by X MB/s for each remote user +MIN_SPEED_MB=10 # Minimum speed limit in MB/s - if [[ -z $response ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - No response received from SABnzbd API." - else - echo "$(date '+%Y-%m-%d %H:%M:%S') - SABnzbd API response: ${response}" - fi +# Local network configuration: +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" } -# Function to check if Plex is playing a file via Tautulli API -is_plex_playing() { - local full_url="${TAUTULLI_URL}?apikey=${TAUTULLI_API_KEY}&cmd=get_activity" - echo "$(date '+%Y-%m-%d %H:%M:%S') - Checking Plex activity via Tautulli API" - - response=$(curl -s "${full_url}" | jq -r '.response.data.sessions | length') +# ------------------------------------------------------------------- +# 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}" - if [[ "$response" -gt 0 ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - Plex is currently playing $response file(s)" - return 0 - else - echo "$(date '+%Y-%m-%d %H:%M:%S') - No Plex playback detected" + # 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 } -# Monitoring loop -while true; do - if is_plex_playing; then - # If Plex is playing/transcoding, use SLOW_SPEED - set_sab_speed "${SLOW_SPEED}" - else - # If Plex is not playing/transcoding, check the current hour - current_hour=$(date +%H) +# ------------------------------------------------------------------- +# 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) - # Compare current hour to NIGHT_START and NIGHT_END - if [ "${current_hour}" -ge "${NIGHT_START}" ] && [ "${current_hour}" -lt "${NIGHT_END}" ]; then - # If current time is between NIGHT_START and NIGHT_END (exclusive of NIGHT_END), use NIGHT_SPEED - set_sab_speed "${NIGHT_SPEED}" - else - # Otherwise, use NORMAL_SPEED - set_sab_speed "${NORMAL_SPEED}" - fi + if [ "$status_code" -ne 200 ]; then + log_message "ERROR: Tautulli returned HTTP status $status_code. Skipping SABnzbd update." + return fi - sleep "${CHECK_INTERVAL}" + + # 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