set download client for all indexers
This commit is contained in:
1 parent
aa27e1f350
commit
0a6457abe0
1 file changed
+222
Executable
+222
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from requests.adapters import HTTPAdapter
|
||||
from urllib3.util.retry import Retry
|
||||
import requests
|
||||
import re
|
||||
import time
|
||||
|
||||
# ============================================================================
|
||||
# CONFIG
|
||||
# ============================================================================
|
||||
ip_address = "192.168.0.4"
|
||||
INSTANCES = [
|
||||
{
|
||||
"name": "radarr-de",
|
||||
"url": f"http://{ip_address}:7879",
|
||||
"api_key": "29f67f0ac8894357b22ea3f7fc1abfdf",
|
||||
},
|
||||
{
|
||||
"name": "radarr-en",
|
||||
"url": f"http://{ip_address}:7878",
|
||||
"api_key": "4332aee075c748f2acee41aa26f06007",
|
||||
},
|
||||
{
|
||||
"name": "sonarr",
|
||||
"url": f"http://{ip_address}:8990",
|
||||
"api_key": "707d4fcbb3d74822ba990c6a8b7278e9",
|
||||
},
|
||||
{
|
||||
"name": "lidarr",
|
||||
"url": f"http://{ip_address}:8686",
|
||||
"api_key": "bb41cbf2b17e439290f90ecfaeb24dff",
|
||||
},
|
||||
# {
|
||||
# "name": "listenarr",
|
||||
# "url": f"http://{ip_address}:7878",
|
||||
# "api_key": "READARR_API_KEY",
|
||||
# },
|
||||
]
|
||||
|
||||
PRIVATE_CLIENT = "qbittorrent-private"
|
||||
PUBLIC_CLIENT = "qbittorrent-public"
|
||||
|
||||
PRIVATE_INDEXER_REGEX = re.compile(
|
||||
r"(Bittorrentfiles|NordicQuality|funzone|SeedCore|The Brothers)",
|
||||
re.IGNORECASE
|
||||
)
|
||||
|
||||
DRY_RUN = False
|
||||
|
||||
# ============================================================================
|
||||
|
||||
session = requests.Session()
|
||||
|
||||
retry_strategy = Retry(
|
||||
total=3,
|
||||
connect=3,
|
||||
read=3,
|
||||
backoff_factor=2,
|
||||
status_forcelist=[429, 500, 502, 503, 504],
|
||||
allowed_methods=["GET", "PUT", "POST"],
|
||||
)
|
||||
|
||||
adapter = HTTPAdapter(max_retries=retry_strategy)
|
||||
|
||||
session.mount("http://", adapter)
|
||||
session.mount("https://", adapter)
|
||||
|
||||
|
||||
def get_api_version(base_url, api_key):
|
||||
r = requests.get(
|
||||
f"{base_url}/api",
|
||||
headers={"X-Api-Key": api_key},
|
||||
timeout=30,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()["current"]
|
||||
|
||||
def api_get(base_url, api_key, endpoint, retries=3):
|
||||
last_error = None
|
||||
|
||||
for attempt in range(1, retries + 1):
|
||||
try:
|
||||
r = requests.get(
|
||||
f"{base_url}{endpoint}",
|
||||
headers={"X-Api-Key": api_key},
|
||||
timeout=30,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
except requests.HTTPError as e:
|
||||
print("Status:", e.response.status_code)
|
||||
print("Response:", e.response.text)
|
||||
raise
|
||||
except Exception as e:
|
||||
last_error = e
|
||||
print(f"GET failed ({attempt}/{retries}): {e}")
|
||||
|
||||
if attempt < retries:
|
||||
time.sleep(2 ** attempt)
|
||||
|
||||
raise last_error
|
||||
|
||||
|
||||
def api_put(base_url, api_key, endpoint, payload, retries=3):
|
||||
last_error = None
|
||||
|
||||
for attempt in range(1, retries + 1):
|
||||
try:
|
||||
r = requests.put(
|
||||
f"{base_url}{endpoint}",
|
||||
headers={
|
||||
"X-Api-Key": api_key,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=payload,
|
||||
timeout=30,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json() if r.content else None
|
||||
except requests.HTTPError as e:
|
||||
print("Status:", e.response.status_code)
|
||||
print("Response:", e.response.text)
|
||||
raise
|
||||
except Exception as e:
|
||||
last_error = e
|
||||
print(f"PUT failed ({attempt}/{retries}): {e}")
|
||||
|
||||
if attempt < retries:
|
||||
time.sleep(2 ** attempt)
|
||||
|
||||
raise last_error
|
||||
|
||||
def get_download_client_ids(base_url, endpoint,api_key):
|
||||
clients = api_get(base_url, api_key, endpoint)
|
||||
|
||||
private_id = None
|
||||
public_id = None
|
||||
|
||||
for client in clients:
|
||||
if client["name"] == PRIVATE_CLIENT:
|
||||
private_id = client["id"]
|
||||
|
||||
if client["name"] == PUBLIC_CLIENT:
|
||||
public_id = client["id"]
|
||||
|
||||
return private_id, public_id
|
||||
|
||||
|
||||
def process_instance(instance):
|
||||
name = instance["name"]
|
||||
url = instance["url"]
|
||||
api_key = instance["api_key"]
|
||||
|
||||
print(f"\n{'=' * 80}")
|
||||
print(f"Processing: {name}")
|
||||
print(f"{'=' * 80}")
|
||||
|
||||
api_version = get_api_version(url, api_key)
|
||||
endpoint_download = f"/api/{api_version}/downloadclient"
|
||||
|
||||
private_id, public_id = get_download_client_ids(url, endpoint_download, api_key)
|
||||
|
||||
if not private_id:
|
||||
print(f"ERROR: '{PRIVATE_CLIENT}' not found")
|
||||
return
|
||||
|
||||
if not public_id:
|
||||
print(f"ERROR: '{PUBLIC_CLIENT}' not found")
|
||||
return
|
||||
|
||||
print(f"{PRIVATE_CLIENT} id: {private_id}")
|
||||
print(f"{PUBLIC_CLIENT} id: {public_id}")
|
||||
|
||||
indexers = api_get(url,api_key,f"/api/{api_version}/indexer")
|
||||
for indexer in indexers:
|
||||
idx_id = indexer["id"]
|
||||
idx_name = indexer["name"]
|
||||
print(idx_name)
|
||||
|
||||
if PRIVATE_INDEXER_REGEX.search(idx_name):
|
||||
target_id = private_id
|
||||
target_name = PRIVATE_CLIENT
|
||||
else:
|
||||
target_id = public_id
|
||||
target_name = PUBLIC_CLIENT
|
||||
|
||||
current_id = indexer.get("downloadClientId")
|
||||
|
||||
if current_id == target_id:
|
||||
print(f"SKIP {idx_name} -> {target_name}")
|
||||
continue
|
||||
|
||||
indexer["downloadClientId"] = target_id
|
||||
|
||||
if DRY_RUN:
|
||||
print(f"DRY {idx_name} -> {target_name}")
|
||||
continue
|
||||
endpoint_indexer = f"/api/{api_version}/indexer/{idx_id}?forceSave=true"
|
||||
|
||||
try:
|
||||
api_put(
|
||||
url,
|
||||
api_key,
|
||||
endpoint_indexer,
|
||||
indexer,
|
||||
)
|
||||
|
||||
print(f"SET {idx_name} -> {target_name}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"FAIL {idx_name}: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
for instance in INSTANCES:
|
||||
process_instance(instance)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user