fix disabling alternate limits
This commit is contained in:
parent
43317044f2
commit
4729bd2cc4
@ -32,8 +32,8 @@ class JellyfinQBittorrentMonitor:
|
|||||||
self.session = requests.Session() # Use session for cookies
|
self.session = requests.Session() # Use session for cookies
|
||||||
|
|
||||||
# Hysteresis settings to prevent rapid switching
|
# Hysteresis settings to prevent rapid switching
|
||||||
self.streaming_start_delay = 10 # seconds to wait before throttling
|
self.streaming_start_delay = 10
|
||||||
self.streaming_stop_delay = 60 # seconds to wait before removing throttle
|
self.streaming_stop_delay = 60
|
||||||
self.last_state_change = 0
|
self.last_state_change = 0
|
||||||
|
|
||||||
# Try to authenticate with qBittorrent
|
# Try to authenticate with qBittorrent
|
||||||
@ -50,18 +50,11 @@ class JellyfinQBittorrentMonitor:
|
|||||||
logger.info("Attempting to authenticate with qBittorrent...")
|
logger.info("Attempting to authenticate with qBittorrent...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# First, try to access a simple endpoint to see if auth is needed
|
|
||||||
test_response = self.session.get(
|
test_response = self.session.get(
|
||||||
f"{self.qbittorrent_url}/api/v2/app/version", timeout=5
|
f"{self.qbittorrent_url}/api/v2/app/version", timeout=5
|
||||||
)
|
)
|
||||||
logger.info(
|
|
||||||
f"Version endpoint test: HTTP {test_response.status_code}, Response: {test_response.text}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if test_response.status_code == 200:
|
if test_response.status_code == 200:
|
||||||
logger.info(
|
logger.info("qBittorrent accessible without explicit login - subnet whitelist working")
|
||||||
"qBittorrent accessible without explicit login - subnet whitelist working"
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -75,7 +68,6 @@ class JellyfinQBittorrentMonitor:
|
|||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(f"Attempting login to {self.qbittorrent_url}/login")
|
|
||||||
response = self.session.post(
|
response = self.session.post(
|
||||||
f"{self.qbittorrent_url}/login",
|
f"{self.qbittorrent_url}/login",
|
||||||
data=login_data,
|
data=login_data,
|
||||||
@ -83,22 +75,13 @@ class JellyfinQBittorrentMonitor:
|
|||||||
timeout=10,
|
timeout=10,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(
|
if response.status_code == 200 and ("Ok." in response.text or response.text.strip() == "Ok."):
|
||||||
f"Login response: HTTP {response.status_code}, Response: '{response.text}'"
|
logger.info("Successfully authenticated with qBittorrent")
|
||||||
)
|
return True
|
||||||
|
elif "Fails." in response.text:
|
||||||
if response.status_code == 200:
|
logger.warning("qBittorrent login failed - authentication may be required")
|
||||||
if "Ok." in response.text or response.text.strip() == "Ok.":
|
|
||||||
logger.info("Successfully authenticated with qBittorrent")
|
|
||||||
return True
|
|
||||||
elif "Fails." in response.text:
|
|
||||||
logger.warning(
|
|
||||||
"qBittorrent login failed - authentication may be required"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.info(f"Unexpected login response: '{response.text}'")
|
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Login request failed with HTTP {response.status_code}")
|
logger.warning(f"Login failed: HTTP {response.status_code}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Could not authenticate with qBittorrent: {e}")
|
logger.error(f"Could not authenticate with qBittorrent: {e}")
|
||||||
@ -140,97 +123,65 @@ class JellyfinQBittorrentMonitor:
|
|||||||
|
|
||||||
def check_qbittorrent_alternate_limits(self):
|
def check_qbittorrent_alternate_limits(self):
|
||||||
"""Check if alternate speed limits are currently enabled"""
|
"""Check if alternate speed limits are currently enabled"""
|
||||||
# For qBittorrent v5.1.0, use API v2 with GET requests
|
|
||||||
try:
|
try:
|
||||||
# Try the transfer info endpoint first (more reliable)
|
response = self.session.get(
|
||||||
|
f"{self.qbittorrent_url}/api/v2/transfer/speedLimitsMode", timeout=10
|
||||||
|
)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.text.strip() == "1"
|
||||||
|
else:
|
||||||
|
logger.warning(f"SpeedLimitsMode endpoint returned HTTP {response.status_code}")
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logger.error(f"SpeedLimitsMode endpoint failed: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to parse speedLimitsMode response: {e}")
|
||||||
|
|
||||||
|
# Fallback: try transfer info endpoint
|
||||||
|
try:
|
||||||
response = self.session.get(
|
response = self.session.get(
|
||||||
f"{self.qbittorrent_url}/api/v2/transfer/info", timeout=10
|
f"{self.qbittorrent_url}/api/v2/transfer/info", timeout=10
|
||||||
)
|
)
|
||||||
logger.info(f"Transfer info endpoint: HTTP {response.status_code}")
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
logger.info(f"Transfer info keys: {list(data.keys())}")
|
|
||||||
|
|
||||||
# Check for alternative speed limit status in the response
|
|
||||||
if "use_alt_speed_limits" in data:
|
if "use_alt_speed_limits" in data:
|
||||||
is_enabled = data["use_alt_speed_limits"]
|
return data["use_alt_speed_limits"]
|
||||||
logger.info(f"Alternative speed limits enabled: {is_enabled}")
|
|
||||||
return is_enabled
|
|
||||||
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
logger.error(f"Transfer info endpoint failed: {e}")
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
logger.error(f"Failed to parse transfer info JSON: {e}")
|
|
||||||
|
|
||||||
# Fallback: try app preferences endpoint
|
|
||||||
try:
|
|
||||||
response = self.session.get(
|
|
||||||
f"{self.qbittorrent_url}/api/v2/app/preferences", timeout=10
|
|
||||||
)
|
|
||||||
logger.info(f"Preferences endpoint: HTTP {response.status_code}")
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
# Look for alternative speed settings
|
|
||||||
if "alt_up_limit" in data or "scheduler_enabled" in data:
|
|
||||||
# Check if alternative speeds are currently active
|
|
||||||
# This is a bit indirect but should work
|
|
||||||
logger.info(
|
|
||||||
"Found preferences data, assuming alt speeds not active by default"
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Preferences endpoint failed: {e}")
|
logger.error(f"Transfer info fallback failed: {e}")
|
||||||
|
|
||||||
logger.error(
|
logger.warning("Could not determine qBittorrent alternate limits status, using tracked state")
|
||||||
"Failed to check qBittorrent alternate limits status: all endpoints failed"
|
return self.throttle_active
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def toggle_qbittorrent_limits(self, enable_throttle):
|
def toggle_qbittorrent_limits(self, enable_throttle):
|
||||||
"""Toggle qBittorrent alternate speed limits"""
|
"""Toggle qBittorrent alternate speed limits"""
|
||||||
try:
|
try:
|
||||||
# Check current state
|
|
||||||
current_throttle = self.check_qbittorrent_alternate_limits()
|
current_throttle = self.check_qbittorrent_alternate_limits()
|
||||||
|
|
||||||
|
if current_throttle == enable_throttle:
|
||||||
|
action = "enabled" if enable_throttle else "disabled"
|
||||||
|
logger.info(f"Alternate speed limits already {action}, no action needed")
|
||||||
|
return
|
||||||
|
|
||||||
if enable_throttle and not current_throttle:
|
response = self.session.post(
|
||||||
try:
|
f"{self.qbittorrent_url}/api/v2/transfer/toggleSpeedLimitsMode",
|
||||||
# Use API v2 POST endpoint to toggle alternative speed limits
|
timeout=10,
|
||||||
response = self.session.post(
|
)
|
||||||
f"{self.qbittorrent_url}/api/v2/transfer/toggleSpeedLimitsMode",
|
response.raise_for_status()
|
||||||
timeout=10,
|
|
||||||
)
|
self.throttle_active = enable_throttle
|
||||||
logger.info(
|
|
||||||
f"Toggle enable response: HTTP {response.status_code}, {response.text[:100]}"
|
# Verify the change took effect
|
||||||
)
|
new_state = self.check_qbittorrent_alternate_limits()
|
||||||
response.raise_for_status()
|
if new_state == enable_throttle:
|
||||||
self.throttle_active = True
|
action = "enabled" if enable_throttle else "disabled"
|
||||||
logger.info("✓ Enabled alternate speed limits (throttling)")
|
logger.info(f"✓ Successfully {action} alternate speed limits")
|
||||||
return
|
else:
|
||||||
except requests.exceptions.RequestException as e:
|
logger.warning(f"Toggle may have failed: expected {enable_throttle}, got {new_state}")
|
||||||
logger.error(f"Failed to enable alternate speed limits: {e}")
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
elif not enable_throttle and current_throttle:
|
action = "enable" if enable_throttle else "disable"
|
||||||
try:
|
logger.error(f"Failed to {action} alternate speed limits: {e}")
|
||||||
# Use API v2 POST endpoint to toggle alternative speed limits
|
|
||||||
response = self.session.post(
|
|
||||||
f"{self.qbittorrent_url}/api/v2/transfer/toggleSpeedLimitsMode",
|
|
||||||
timeout=10,
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
f"Toggle disable response: HTTP {response.status_code}, {response.text[:100]}"
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
self.throttle_active = False
|
|
||||||
logger.info("✓ Disabled alternate speed limits (normal)")
|
|
||||||
return
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
logger.error(f"Failed to disable alternate speed limits: {e}")
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to toggle qBittorrent limits: {e}")
|
logger.error(f"Failed to toggle qBittorrent limits: {e}")
|
||||||
|
|
||||||
@ -244,24 +195,28 @@ class JellyfinQBittorrentMonitor:
|
|||||||
"""Apply hysteresis to prevent rapid state changes"""
|
"""Apply hysteresis to prevent rapid state changes"""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
|
||||||
# If state hasn't changed, no action needed
|
|
||||||
if new_streaming_state == self.last_streaming_state:
|
if new_streaming_state == self.last_streaming_state:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Calculate time since last state change
|
|
||||||
time_since_change = now - self.last_state_change
|
time_since_change = now - self.last_state_change
|
||||||
|
|
||||||
# If we want to start throttling (streaming started)
|
# Start throttling (streaming started)
|
||||||
if new_streaming_state and not self.last_streaming_state:
|
if new_streaming_state and not self.last_streaming_state:
|
||||||
if time_since_change >= self.streaming_start_delay:
|
if time_since_change >= self.streaming_start_delay:
|
||||||
self.last_state_change = now
|
self.last_state_change = now
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
remaining = self.streaming_start_delay - time_since_change
|
||||||
|
logger.info(f"Streaming started - waiting {remaining:.1f}s before enabling throttling")
|
||||||
|
|
||||||
# If we want to stop throttling (streaming stopped)
|
# Stop throttling (streaming stopped)
|
||||||
elif not new_streaming_state and self.last_streaming_state:
|
elif not new_streaming_state and self.last_streaming_state:
|
||||||
if time_since_change >= self.streaming_stop_delay:
|
if time_since_change >= self.streaming_stop_delay:
|
||||||
self.last_state_change = now
|
self.last_state_change = now
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
remaining = self.streaming_stop_delay - time_since_change
|
||||||
|
logger.info(f"Streaming stopped - waiting {remaining:.1f}s before disabling throttling")
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -287,8 +242,8 @@ class JellyfinQBittorrentMonitor:
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"Active streams ({len(active_streams)}): {', '.join(active_streams)}"
|
f"Active streams ({len(active_streams)}): {', '.join(active_streams)}"
|
||||||
)
|
)
|
||||||
else:
|
elif len(active_streams) == 0 and self.last_streaming_state:
|
||||||
logger.debug("No active streaming sessions")
|
logger.info("No active streaming sessions")
|
||||||
|
|
||||||
# Apply hysteresis and change state if needed
|
# Apply hysteresis and change state if needed
|
||||||
if self.should_change_state(streaming_active):
|
if self.should_change_state(streaming_active):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user