Files
arr-init/scripts/bazarr_init.py
Simon Gardling b464a8cea2 refactor: extract Python scripts into standalone files
Move embedded Python scripts out of Nix string interpolation into
standalone files under scripts/.  Each script reads its configuration
from a JSON file passed as the first CLI argument.

Shared utilities (API key reading, API polling, health check loop)
are consolidated into common.py, eliminating three copies of
read_api_key and wait_for_api.

Implementation improvements included in the extraction:
- Remove pyarr dependency; all HTTP calls use raw requests
- Add update semantics: download clients and synced apps are now
  compared against desired state and updated on drift via PUT
- Bazarr configure_provider compares API keys and updates stale ones
- Narrow health_check_loop exception clause from bare Exception to
  (RequestException, ValueError, KeyError)
- Fix double resp.json() call in resolve_profile_id (jellyseerr)
- Replace os.system with subprocess.run for Jellyseerr restart
- Handle missing 'value' key in Servarr field API responses
2026-04-16 16:33:18 -04:00

103 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""Declarative API initialization for Bazarr provider connections.
Idempotently configures Sonarr and Radarr providers in Bazarr via its
settings API. Detects stale API keys and updates them.
"""
import os
import requests as http
from common import (
load_config,
read_api_key_xml,
read_api_key_yaml,
wait_for_api,
)
def configure_provider(base_url, api_key, provider_type, provider_config):
"""Idempotently configure a Sonarr/Radarr provider in Bazarr.
Compares the stored API key against the current one and updates if stale.
"""
ltype = provider_type.lower()
print(f"Checking {provider_type} provider...")
resp = http.get(
f"{base_url}/api/system/settings",
headers={"X-API-KEY": api_key},
timeout=30,
)
resp.raise_for_status()
settings = resp.json()
use_flag = settings.get("general", {}).get(f"use_{ltype}", False)
existing_key = settings.get(ltype, {}).get("apikey", "")
provider_api_key = read_api_key_xml(
f"{provider_config['dataDir']}/config.xml"
)
bind_address = provider_config.get("bindAddress", "127.0.0.1")
if use_flag and existing_key == provider_api_key:
print(f"{provider_type} provider already correct, skipping")
return
action = "Updating" if use_flag else "Adding"
print(f"{action} {provider_type} provider...")
resp = http.post(
f"{base_url}/api/system/settings",
headers={"X-API-KEY": api_key},
data={
f"settings-general-use_{ltype}": "true",
f"settings-{ltype}-ip": bind_address,
f"settings-{ltype}-port": str(provider_config["port"]),
f"settings-{ltype}-apikey": provider_api_key,
f"settings-{ltype}-ssl": "false",
f"settings-{ltype}-base_url": "/",
},
timeout=30,
)
resp.raise_for_status()
print(f"{provider_type} provider configured")
def main():
cfg = load_config()
data_dir = cfg["dataDir"]
bind_address = cfg.get("bindAddress", "127.0.0.1")
port = cfg["port"]
api_timeout = cfg["apiTimeout"]
config_yaml = f"{data_dir}/config/config.yaml"
if not os.path.isfile(config_yaml):
print(f"Config file {config_yaml} not found, skipping bazarr init")
return
api_key = read_api_key_yaml(config_yaml)
base_url = f"http://{bind_address}:{port}"
wait_for_api(
base_url,
api_key,
api_timeout,
"Bazarr",
header_name="X-API-KEY",
status_path="/api/system/status",
)
providers = cfg.get("providers", {})
if providers.get("sonarr", {}).get("enable"):
configure_provider(base_url, api_key, "Sonarr", providers["sonarr"])
if providers.get("radarr", {}).get("enable"):
configure_provider(base_url, api_key, "Radarr", providers["radarr"])
print("Bazarr init complete")
if __name__ == "__main__":
main()