Skip to content

fix: premature torrent removals, HnR clear mode, tests, .cursor in gi… - #308

Merged
Feramance merged 70 commits into
masterfrom
fix/premature-torrent-removals-hnr-clear-mode
Mar 1, 2026
Merged

Feramance merged 70 commits into
masterfrom
fix/premature-torrent-removals-hnr-clear-mode

Conversation

@Feramance

@Feramance Feramance commented Feb 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fixes premature torrent removals (removed before meeting max seeding/ratio and tracker minimums), adds configurable HnR clear mode, and includes operational hardening (DB repair, FSM category monitoring, Docker/CI/docs fixes) plus WebUI and docs consistency updates.

Changes

Sentinel / removal logic

  • Unset limits: Ratio and time limits <= 0 (e.g. -5) are treated as unset; seeding-based removal only runs when at least one limit is set and met.
  • torrent_limit_check: Modes 1–4 only remove when the relevant limit is set; if neither MaxUploadRatio nor MaxSeedingTime is set, a single warning per run is logged and removal is skipped.

Logging

  • _mark_for_deletion(): Logs reason, progress, ratio, seeding time, and effective limits (INFO) before adding to delete set.
  • _process_failed(): Logs counts by category (delete, missing_files_post_delete, etc.) and optional DEBUG sample.

HitAndRunClearMode

  • New option: HitAndRunClearMode = "and" | "or" | "disabled" (default "disabled").
  • Migration 5.9.2: HitAndRunMode = true → HitAndRunClearMode = "and" for backwards compatibility.
  • and: Require both MinSeedRatio and MinSeedingTimeDays when both set.
  • or: Require either ratio or time.
  • disabled: No HnR protection.
  • Implemented in arss.py and qbit_category_manager.py; added to gen_config, main, config.example.toml, Web UI, tooltips.
  • qBit category manager: Stalled-download removal now respects HnR (gate added so stalled torrents are only removed when tracker-dead bypass applies or HnR obligations are satisfied).

Database

  • Automated startup repair: Run PRAGMA integrity_check at startup; on failure, attempt WAL checkpoint and repair via db_recovery; on unrecoverable corruption, offer fresh DB (delete corrupt DB so a new one is created).
  • DatabaseRecoveryError: Caught on startup with option to start fresh when repair fails.
  • Unclean shutdown: Reduced DB corruption risk; corrupt DB deleted when repair fails.

FreeSpaceManager

  • qBit-managed categories: FSM now monitors qBit.ManagedCategories in addition to Arr-managed paths; disk-usage path handling improved (incl. Docker mount warnings).
  • Docs updated for FSM category monitoring.

qBit / config

  • has_internet: Pass qBit client to avoid "Instance default not found" warning when checking connectivity.
  • DownloadRateLimit: Reset download limit with set_download_limit when DownloadRateLimit < 0.

WebUI

  • Processes view: One card per qBit instance; removed badges; avoid duplicate "qBit" prefix in process names.
  • ConfigView: Parse types and Configuration link on home for strict build.

Docker & CI

  • Dockerfile: Use tini for proper SIGTERM forwarding.
  • docker-compose.yml: Added for local/CI use.
  • CI/docs: PR and docs workflows fixed; MkDocs build fixes: disable parallel processing in git-revision-date plugin (fix CI AssertionError), include root CHANGELOG in docs/changelog.md, ensure docs/changelog.md exists in CI (copy CHANGELOG.md when missing), remove symlink before copying changelog in CI.

Docs

  • Changelog: docs/changelog.md includes root CHANGELOG.md for MkDocs build.
  • Health: Health endpoint documented as /health; Built With stack updated.
  • Consistency: Full doc vs code consistency pass (advanced, config-file, environment, seeding, torrents, disk-space, process-management, database, docker, common-issues, webui api/config-editor/index, migration, quickstart, installation/docker).
  • API: Documented /web/qbit/categories and related webui API.

Code quality

  • _should_leave_alone (arss.py): Return type corrected to 5-tuple (bool, int, bool, dict | None, dict | None).
  • Unit tests: tests/unit/test_torrent_limit_check.py for removal modes 1–4 and unset/partial limits (5 tests).
  • .gitignore: Added .cursor.

Config & schema

  • Config version 5.9.2; migration _migrate_hnr_clear_mode.
  • seeding.md: HitAndRunClearMode section, unset-limits troubleshooting note.
  • torrents.md: DoNotRemoveSlow/MaximumETA clarification.

High Risk
Changes core torrent deletion/retention logic (seeding-limit evaluation, HnR enforcement, stalled-removal, free-space pausing scope) and adds startup DB integrity repair that can delete the DB on unrecoverable corruption; misconfigurations could alter cleanup behavior or cause data loss.


Note

Medium Risk
Medium risk due to Docker runtime changes (new tini/gosu entrypoint, non-root user setup, permission/chown behavior) and CI workflow adjustments that can affect build/publish pipelines; most other changes are documentation-only.

Overview
Improves operational reliability and release/CI hygiene by updating GitHub Actions workflows (CodeQL adds JS/TS scanning, pre-commit installs the package for import resolution, PR Docker builds are skipped for forks, nightly builds are multi-arch, and version detection no longer relies on setup.py).

Hardens the Docker image by switching to python:3.12-slim, installing tini/gosu/curl, creating a dedicated qbitrr user, and using a new docker-entrypoint.sh to fix /config ownership and properly forward signals.

Fixes MkDocs/docsite build issues by replacing the docs/changelog.md symlink with an include-markdown include, ensuring the changelog file exists in docs CI, adjusting MkDocs plugins/nav/logo, and updating documentation consistency (notably using /health instead of /api/health, plus new/updated configuration and troubleshooting pages).

Written by Cursor Bugbot for commit 29de695. This will update automatically on new commits. Configure here.

Shaun Agius and others added 6 commits February 26, 2026 12:00
… release date

- Use instance name as-is when it already starts with 'qbit'

- Update docs index latest release date to February 2026
…found' warning

has_internet() was given qBitManager in PlaceHolderArr and FreeSpaceManager
loops; it then called transfer_info() with default instance_name='default'.
Config uses section names (e.g. 'qBit'), so get_client('default') logged a
warning. Use manager.client (first available client) at both call sites.
cursor[bot]

This comment was marked as resolved.

Repository owner deleted a comment from cursor Bot Feb 26, 2026
Feramance added 3 commits February 26, 2026 14:13
Run PRAGMA integrity_check before first connect; if not ok, attempt
WAL checkpoint then full dump/restore repair. Ensures corrupted
qbitrr.db is repaired automatically on restart without manual steps.
…mit < 0

When tracker DownloadRateLimit is negative (unlimited), the elif branch
was incorrectly calling set_upload_limit(limit=-1) instead of
set_download_limit(limit=-1), resetting upload instead of download.
…ir fails

- Wrap repair_database() in try/except so startup does not crash on
  'database disk image is malformed' or other repair failures.
- On DatabaseRecoveryError, move corrupt DB to qbitrr.db.corrupt.<ts>
  so a fresh database is created on connect (avoids repeated failures).
Comment thread qBitrr/gen_config.py Resolved
Feramance added 3 commits February 26, 2026 14:30
…ailed repair

- Docker: add tini as PID 1 so SIGTERM reaches Python (enables checkpoint on stop)
- docker-compose: stop_grace_period: 30s so cleanup runs before SIGKILL
- database: on failed repair delete corrupt DB (not move) so fresh DB is created
- docs: document why corruption happens, tini/stop_grace_period, prevention
Pass arr_categories | qbit_managed_categories to FreeSpaceManager so
torrents in ManagedCategories (e.g. autobrr) are included in free-space
checks and can be paused when disk is low.
- requirements.docs.txt: pin mkdocs<2.0 for Material compatibility
- mkdocs.yml: use logo SVG, update copyright to 2026
- disk-space.md: document Arr + qBit-managed categories for FSM;
  add troubleshooting step for unmonitored categories
Comment thread qBitrr/qbit_category_manager.py Resolved
Comment thread qBitrr/arss.py Resolved
- pull_requests: skip docker_image job on fork PRs (no secrets); use brew install sdl2 on macOS instead of full Homebrew installer
- mkdocs: remove missing favicon reference so --strict build passes in CI
- requirements.docs: pin mkdocs<1.6 to avoid 2.x incompatibility warning
Comment thread qBitrr/database.py Resolved
Comment thread qBitrr/arss.py Resolved
Comment thread qBitrr/qbit_category_manager.py Resolved
Feramance added 5 commits February 26, 2026 16:46
- Remove kind badges from qBit process cards and Arr/qBit badge from category chips
- Ensure a card is shown for every qBit instance in status, even with no processes
- Show instance alive status when a qBit card has no processes
- Hide Restart All footer when card has no processes
Comment thread qBitrr/arss.py Resolved
Comment thread docs/changelog.md Resolved
Feramance added 2 commits February 26, 2026 18:10
- Correct all references from /api/health to /health (actual route is GET /health)
- Update index Built With: replace Mantine with custom CSS (no external UI runtime)
- Update webui/index.md intro to say TypeScript and custom CSS
- config-file: ConfigVersion string/default, FreeSpaceFolder default CHANGE_ME,
  WebUI ViewDensity, qBit ManagedCategories, minimal config without ConfigVersion
- config-editor: ViewDensity key fields/reload table, rate limits KB/s,
  MaximumDeletablePercentage decimal 0-1
- environment: SearchLoopDelay -1 = 30s delay not disabled, note on process/WebUI env
- api: document GET /web/qbit/categories (public only)
- disk-space: clarify pause only managed categories
- health-monitoring: note [Settings.FFprobe] not in gen-config
- process-management: fix env var name, shutdown wording, process API example
- tooltips: add WebUI.ViewDensity
- gen_config: IgnoreTorrentsYoungerThan default 180 in settings_defaults
Comment thread qBitrr/arss.py Resolved
Comment thread qBitrr/arss.py Resolved
Comment thread qBitrr/main.py Fixed
- Docker: add entrypoint that chowns /config to PUID/PGID so app can write
  (fixes 'attempt to write a readonly database' on mounted volumes)
- Dockerfile: install gosu, use entrypoint, remove USER so root can chown at start
- home_path/logger: make chmod non-fatal when volume does not allow it
- database: ensure db dir writable, retry on readonly with clear error message
- WebUI: fix ProcessesView.tsx QUALITY_TOKEN_REGEX name and usage
- WebUI: add Hashable index signature to RadarrMovie and LidarrAlbumEntry
Comment thread .github/workflows/nightly.yml Resolved
Comment thread mkdocs.yml Resolved
Feramance added 2 commits March 1, 2026 09:06
- Backend: add lines/offset params to log API for efficient tail and pagination
- Logs view: Live checkbox disables polling; Refresh fetches current tail
- Load older logs button to prepend older lines (scroll up indefinitely)
- Auto-scroll remains separate from Live
- WelcomeModal: use ReactMarkdown for release notes instead of pre
- Check Updates: show popup after check - either 'already on latest' with
  current version changelog (markdown) or update-available modal with
  latest changelog (markdown)
- refreshMeta now returns fetched MetaResponse for callers
- Add AlreadyUpToDateModal for Check Updates when no update available
Comment thread .github/workflows/nightly.yml Resolved
Comment thread Dockerfile Resolved
Comment thread .github/workflows/nightly.yml Resolved
Comment thread mkdocs.yml Resolved
Comment thread docker-entrypoint.sh Resolved
Feramance added 2 commits March 1, 2026 10:04
- AGENTS.md: correct locked_database() to database_lock()
- config: load from CONFIG_FILE or resolved CONFIG_PATH after copy
- database: wrap init (connect, create_tables) in database_lock()
- search_activity_store: wrap all DB ops in database_lock()
- arss: wrap TorrentLibrary/tagless, db_reset_*, queue cleanup in database_lock()
- webui: wrap Radarr/Lidarr/Sonarr DB access in database_lock()
- webui: add debug logging to remaining silent except blocks
- webui: harden _resolve_log_file (sanitize name, log on exception)
Comment thread .github/workflows/nightly.yml Resolved
@Feramance

Copy link
Copy Markdown
Owner Author

@cursor push df315d3

@cursor

cursor Bot commented Mar 1, 2026

Copy link
Copy Markdown
Contributor

Could not push Autofix changes. The PR branch has conflicting changes.

@Feramance

Copy link
Copy Markdown
Owner Author

@cursor push b48b537

cursor Bot and others added 2 commits March 1, 2026 10:13
…ents

PlaceHolderArr._process_failed was unioning original to_delete_all into
the cleanup set even when the qBit delete API failed, causing torrents
to be removed from name_cache/cache while still in qBittorrent. Now
only cleaned_hashes = deleted_hashes | temp_to_delete are used for
cache cleanup, matching Arr._process_failed behavior.
Comment thread .github/workflows/nightly.yml Resolved
Comment thread .github/workflows/nightly.yml Resolved
- Add explicit permissions to pre-commit and dockerhub-description workflows
- Mask qBit username in debug log (main.py) to avoid clear-text logging
- Stop exposing exception/stack trace in WebUI API error responses (webui.py)
Comment thread .github/workflows/nightly.yml Resolved
Comment thread mkdocs.yml Resolved
Comment thread Dockerfile Resolved
The CodeQL security fix (37b6dcf) accidentally removed the @app.get('/web/config')
decorator when editing exception handling, so the Config tab received 405 Method
Not Allowed and users could not load or adjust config. Re-add the decorator so
GET /web/config is registered again.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Comment thread .github/workflows/nightly.yml Resolved
Comment thread mkdocs.yml Resolved
- Always strip sensitive keys in GET /api/config and GET /web/config
- Skip overwriting secrets when update sends redaction placeholder
- Add REDACTED_PLACEHOLDER and _is_sensitive_dotted_key helper

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Comment thread .github/workflows/nightly.yml Resolved
Comment thread Dockerfile Resolved
Feramance added 3 commits March 1, 2026 23:28
- Add comparison-huntarr.md focusing on missing-item search and torrent handling
- Add nav entry under Getting Started and From Huntarr subsection in migration.md
@Feramance
Feramance merged commit 356b53d into master Mar 1, 2026
16 checks passed
@Feramance
Feramance deleted the fix/premature-torrent-removals-hnr-clear-mode branch March 1, 2026 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants