mirror of
https://github.com/plexguide/Huntarr.git
synced 2026-04-26 08:38:11 -05:00
update
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
Whisparr-specific API functions
|
||||
Handles all communication with the Whisparr API
|
||||
|
||||
Exclusively uses the Eros API v3
|
||||
Exclusively uses the Whisparr V2 API
|
||||
"""
|
||||
|
||||
import requests
|
||||
@@ -23,7 +23,7 @@ session = requests.Session()
|
||||
|
||||
def arr_request(api_url: str, api_key: str, api_timeout: int, endpoint: str, method: str = "GET", data: Dict = None) -> Any:
|
||||
"""
|
||||
Make a request to the Whisparr Eros API.
|
||||
Make a request to the Whisparr V2 API.
|
||||
|
||||
Args:
|
||||
api_url: The base URL of the Whisparr API
|
||||
@@ -40,9 +40,9 @@ def arr_request(api_url: str, api_key: str, api_timeout: int, endpoint: str, met
|
||||
whisparr_logger.error("API URL or API key is missing. Check your settings.")
|
||||
return None
|
||||
|
||||
# Always use v3 for Eros API
|
||||
api_base = "api/v3"
|
||||
whisparr_logger.debug(f"Using Whisparr Eros API: {api_base}")
|
||||
# Always use v2 for Whisparr API
|
||||
api_base = "api"
|
||||
whisparr_logger.debug(f"Using Whisparr V2 API: {api_base}")
|
||||
|
||||
# Full URL - ensure no double slashes
|
||||
url = f"{api_url.rstrip('/')}/{api_base}/{endpoint.lstrip('/')}"
|
||||
@@ -107,7 +107,7 @@ def get_download_queue_size(api_url: str, api_key: str, api_timeout: int) -> int
|
||||
if response is None:
|
||||
return -1
|
||||
|
||||
# V2 and V3 both use records in queue response, but sometimes the structure is different
|
||||
# V2 API uses records in queue response
|
||||
if isinstance(response, dict) and "records" in response:
|
||||
return len(response["records"])
|
||||
elif isinstance(response, list):
|
||||
@@ -131,7 +131,7 @@ def get_items_with_missing(api_url: str, api_key: str, api_timeout: int, monitor
|
||||
try:
|
||||
whisparr_logger.debug(f"Retrieving missing items...")
|
||||
|
||||
# Endpoint parameters - always use v3 format since we're using v3 API
|
||||
# Endpoint parameters - always use v2 format
|
||||
endpoint = "wanted/missing?pageSize=1000&sortKey=airDateUtc&sortDirection=descending"
|
||||
|
||||
response = arr_request(api_url, api_key, api_timeout, endpoint)
|
||||
@@ -171,7 +171,7 @@ def get_cutoff_unmet_items(api_url: str, api_key: str, api_timeout: int, monitor
|
||||
try:
|
||||
whisparr_logger.debug(f"Retrieving cutoff unmet items...")
|
||||
|
||||
# Endpoint - always use v3 format
|
||||
# Endpoint - always use v2 format
|
||||
endpoint = "wanted/cutoff?pageSize=1000&sortKey=airDateUtc&sortDirection=descending"
|
||||
|
||||
response = arr_request(api_url, api_key, api_timeout, endpoint)
|
||||
@@ -186,7 +186,7 @@ def get_cutoff_unmet_items(api_url: str, api_key: str, api_timeout: int, monitor
|
||||
|
||||
whisparr_logger.debug(f"Found {len(items)} cutoff unmet items")
|
||||
|
||||
# Just filter monitored if needed - we're always using v3 API now
|
||||
# Just filter monitored if needed
|
||||
if monitored_only:
|
||||
items = [item for item in items if item.get("monitored", False)]
|
||||
whisparr_logger.debug(f"Found {len(items)} cutoff unmet items after filtering monitored")
|
||||
@@ -267,7 +267,7 @@ def item_search(api_url: str, api_key: str, api_timeout: int, item_ids: List[int
|
||||
try:
|
||||
whisparr_logger.debug(f"Searching for items with IDs: {item_ids}")
|
||||
|
||||
# Always use the same payload format since we're always using v3 API
|
||||
# Always use the same payload format since we're always using v2 API
|
||||
payload = {
|
||||
"name": "EpisodeSearch",
|
||||
"episodeIds": item_ids
|
||||
@@ -337,7 +337,7 @@ def check_connection(api_url: str, api_key: str, api_timeout: int) -> bool:
|
||||
if response is not None:
|
||||
# Get the version information if available
|
||||
version = response.get("version", "unknown")
|
||||
whisparr_logger.info(f"Successfully connected to Whisparr {version} using API v3")
|
||||
whisparr_logger.info(f"Successfully connected to Whisparr {version} using API v2")
|
||||
return True
|
||||
else:
|
||||
whisparr_logger.error("Failed to connect to Whisparr API")
|
||||
|
||||
@@ -24,7 +24,7 @@ def test_connection():
|
||||
if not api_url or not api_key:
|
||||
return jsonify({"success": False, "message": "API URL and API Key are required"}), 400
|
||||
|
||||
whisparr_logger.info(f"Testing connection to Whisparr Eros API at {api_url}")
|
||||
whisparr_logger.info(f"Testing connection to Whisparr API at {api_url}")
|
||||
|
||||
# Use v3 API endpoint for Whisparr Eros
|
||||
url = f"{api_url}/api/v3/system/status"
|
||||
@@ -35,31 +35,72 @@ def test_connection():
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
response.raise_for_status()
|
||||
|
||||
try:
|
||||
response_data = response.json()
|
||||
version = response_data.get('version', 'unknown')
|
||||
# Check if we received a 404, which might indicate this is a v2 API
|
||||
if response.status_code == 404:
|
||||
# Try v2 API endpoint instead
|
||||
url_v2 = f"{api_url}/api/system/status"
|
||||
response_v2 = requests.get(url_v2, headers=headers, timeout=10)
|
||||
|
||||
# Validate that this is actually Eros API v3
|
||||
if not version.startswith('3'):
|
||||
error_msg = f"Whisparr version {version} detected. Huntarr requires Eros API v3."
|
||||
whisparr_logger.error(error_msg)
|
||||
return jsonify({"success": False, "message": error_msg, "is_eros": False}), 400
|
||||
if response_v2.status_code == 200:
|
||||
try:
|
||||
response_data = response_v2.json()
|
||||
version = response_data.get('version', 'unknown')
|
||||
|
||||
# Make sure it's a version 2.x
|
||||
if version and version.startswith('2'):
|
||||
whisparr_logger.info(f"Successfully connected to Whisparr V2 API version: {version}")
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Successfully connected to Whisparr V2 API (version {version})",
|
||||
"version": version,
|
||||
"is_v2": True
|
||||
})
|
||||
else:
|
||||
error_msg = f"Unexpected Whisparr version {version} detected via v2 API path."
|
||||
whisparr_logger.error(error_msg)
|
||||
return jsonify({"success": False, "message": error_msg}), 400
|
||||
except ValueError:
|
||||
error_msg = "Invalid JSON response from Whisparr V2 API"
|
||||
whisparr_logger.error(f"{error_msg}. Response content: {response_v2.text[:200]}")
|
||||
return jsonify({"success": False, "message": error_msg}), 500
|
||||
|
||||
# If we got a successful response from the v3 endpoint
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
response_data = response.json()
|
||||
version = response_data.get('version', 'unknown')
|
||||
|
||||
whisparr_logger.info(f"Successfully connected to Whisparr Eros API version: {version}")
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Successfully connected to Whisparr Eros API",
|
||||
"version": version,
|
||||
"is_eros": True
|
||||
})
|
||||
except ValueError:
|
||||
error_msg = "Invalid JSON response from Whisparr API"
|
||||
whisparr_logger.error(f"{error_msg}. Response content: {response.text[:200]}")
|
||||
return jsonify({"success": False, "message": error_msg}), 500
|
||||
|
||||
# Special case: check if it's actually a v2 API instance
|
||||
# Some Whisparr v2 instances might respond to v3 endpoint too
|
||||
if version and version.startswith('2'):
|
||||
whisparr_logger.info(f"Successfully connected to Whisparr V2 API version: {version}")
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Successfully connected to Whisparr V2 API (version {version})",
|
||||
"version": version,
|
||||
"is_v2": True
|
||||
})
|
||||
|
||||
# Reject version 3.x (Eros API)
|
||||
if version and version.startswith('3'):
|
||||
error_msg = f"Whisparr version {version} (Eros API) detected. Huntarr requires Whisparr V2."
|
||||
whisparr_logger.error(error_msg)
|
||||
return jsonify({"success": False, "message": error_msg, "is_eros": True}), 400
|
||||
|
||||
# If we're here, it's some other version
|
||||
error_msg = f"Unexpected Whisparr version {version} detected. Huntarr requires Whisparr V2."
|
||||
whisparr_logger.error(error_msg)
|
||||
return jsonify({"success": False, "message": error_msg}), 400
|
||||
except ValueError:
|
||||
error_msg = "Invalid JSON response from Whisparr API"
|
||||
whisparr_logger.error(f"{error_msg}. Response content: {response.text[:200]}")
|
||||
return jsonify({"success": False, "message": error_msg}), 500
|
||||
|
||||
# If we reached here, the status code wasn't 200 or 404
|
||||
error_msg = f"Received HTTP {response.status_code} from Whisparr API"
|
||||
whisparr_logger.error(error_msg)
|
||||
return jsonify({"success": False, "message": error_msg}), 500
|
||||
except requests.exceptions.RequestException as e:
|
||||
error_msg = f"Connection test failed: {str(e)}"
|
||||
whisparr_logger.error(error_msg)
|
||||
@@ -73,39 +114,80 @@ def is_configured():
|
||||
|
||||
@whisparr_bp.route('/get-versions', methods=['GET'])
|
||||
def get_versions():
|
||||
"""Get the version information from the Whisparr Eros API"""
|
||||
"""Get the version information from the Whisparr API"""
|
||||
api_keys = keys_manager.load_api_keys("whisparr")
|
||||
api_url = api_keys.get("api_url")
|
||||
api_key = api_keys.get("api_key")
|
||||
|
||||
if not api_url or not api_key:
|
||||
return jsonify({"success": False, "message": "Whisparr Eros API is not configured"}), 400
|
||||
return jsonify({"success": False, "message": "Whisparr API is not configured"}), 400
|
||||
|
||||
headers = {'X-Api-Key': api_key}
|
||||
version_url = f"{api_url.rstrip('/')}/api/v3/system/status"
|
||||
|
||||
# Try v2 API endpoint first since that's what we want
|
||||
version_url_v2 = f"{api_url.rstrip('/')}/api/system/status"
|
||||
|
||||
try:
|
||||
response = requests.get(version_url, headers=headers, timeout=10)
|
||||
response.raise_for_status()
|
||||
# Check v2 endpoint first
|
||||
response = requests.get(version_url_v2, headers=headers, timeout=10)
|
||||
|
||||
version_data = response.json()
|
||||
version = version_data.get("version", "Unknown")
|
||||
if response.status_code == 200:
|
||||
version_data = response.json()
|
||||
version = version_data.get("version", "Unknown")
|
||||
|
||||
# Validate that it's v2.x
|
||||
if version.startswith('2'):
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"version": version,
|
||||
"is_v2": True
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Unexpected Whisparr version detected: {version}. Huntarr requires Whisparr V2.",
|
||||
"is_v2": False
|
||||
}), 400
|
||||
|
||||
# Validate that it's Eros API v3
|
||||
if not version.startswith('3'):
|
||||
# If v2 failed, check if it's v3 (Eros API)
|
||||
version_url_v3 = f"{api_url.rstrip('/')}/api/v3/system/status"
|
||||
response_v3 = requests.get(version_url_v3, headers=headers, timeout=10)
|
||||
|
||||
if response_v3.status_code == 200:
|
||||
version_data = response_v3.json()
|
||||
version = version_data.get("version", "Unknown")
|
||||
|
||||
# Special case: check if it's actually a v2 API instance
|
||||
# Some Whisparr v2 instances might also respond to v3 endpoint
|
||||
if version and version.startswith('2'):
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"version": version,
|
||||
"is_v2": True
|
||||
})
|
||||
|
||||
# If it's v3, reject it
|
||||
if version and version.startswith('3'):
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Incompatible Whisparr version detected: {version} (Eros API). Huntarr requires Whisparr V2.",
|
||||
"is_eros": True
|
||||
}), 400
|
||||
|
||||
# If we get here, it's some other version
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": f"Incompatible Whisparr version detected: {version}. Huntarr requires Eros API v3.",
|
||||
"message": f"Unexpected Whisparr version: {version}. Huntarr requires Whisparr V2.",
|
||||
"is_eros": False
|
||||
}), 400
|
||||
|
||||
# If we get here, both v2 and v3 failed with non-200 status
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"version": version,
|
||||
"is_eros": True
|
||||
})
|
||||
"success": False,
|
||||
"message": f"Could not determine Whisparr version. V2 API: HTTP {response.status_code}, V3 API: HTTP {response_v3.status_code}."
|
||||
}), 500
|
||||
except requests.exceptions.RequestException as e:
|
||||
error_message = f"Error fetching Whisparr Eros version: {str(e)}"
|
||||
error_message = f"Error fetching Whisparr version: {str(e)}"
|
||||
return jsonify({"success": False, "message": error_message}), 500
|
||||
|
||||
@whisparr_bp.route('/logs', methods=['GET'])
|
||||
|
||||
Reference in New Issue
Block a user