"""Shared HTTP timeout helpers. ``requests`` accepts a single integer timeout and applies it to BOTH the connect and read phases. For slow upstream services (large Jellyfin libraries, qBittorrent with many torrents), the read phase needs a much larger budget than connect. These helpers produce ``(connect, read)`` tuples so the two phases are decoupled. """ from __future__ import annotations #: Short connect timeout — fail fast on unreachable/dead hosts. DEFAULT_CONNECT_TIMEOUT = 5.0 #: Generous read timeout — let slow responses complete. DEFAULT_READ_TIMEOUT = 60.0 def http_timeout( read_timeout: float | int | None = None, connect_timeout: float = DEFAULT_CONNECT_TIMEOUT, ) -> tuple[float, float]: """Build a ``(connect, read)`` timeout tuple for ``requests``. ``read_timeout`` is the per-response read budget (seconds). When omitted or non-positive, :data:`DEFAULT_READ_TIMEOUT` applies. """ effective_read = DEFAULT_READ_TIMEOUT if read_timeout is not None: try: parsed = float(read_timeout) if parsed > 0: effective_read = parsed except (TypeError, ValueError): pass # fall back to default on non-numeric input return (connect_timeout, effective_read)