Added
- Configurable download timeout — Media downloads are now wrapped in
asyncio.wait_forwith aDOWNLOAD_TIMEOUT_SECONDSbudget (default3600,0disables), so a single stalled download can no longer hang a backup indefinitely. - Tunable backoff for transient errors —
BACKOFF_MIN_SECONDSandBACKOFF_MAX_SECONDScontrol exponential backoff with jitter for FloodWait and transient network retries, andFLOOD_WAIT_LOG_THRESHOLDtunes how chatty FloodWait logging is.
Fixed
- Transient network errors no longer abort one-shot API calls —
call_with_flood_retrynow retriesTimeoutError/ConnectionError/OSError/RPCErrorwith bounded exponential backoff, while still re-raising terminal errors (FloodWait, FileReferenceExpired, ChannelPrivate, ChatForbidden, UserBanned) immediately. - Expired file references are refreshed mid-download — Downloads that hit
FileReferenceExpiredErrornow re-fetch the message and retry instead of failing the media. - Concurrent symlink creation is race-safe — Deduplicated media symlinks tolerate
EEXISTfrom concurrent tasks instead of crashing. upsert_userandinsert_mediaretry on locked DB — Both now use@retry_on_locked()for resilience under concurrent SQLite access.- Windows-friendly auth help —
setup_authno longer callsos.getuid()/os.getgid()unconditionally.
Credits
📋 Full changelog: docs/CHANGELOG.md