Skip to content

Commit 436bd18

Browse files
committed
feat!: remove search_mode, unify browse loop with max_pages budget
BREAKING CHANGE: search_mode config key removed. Existing configs are auto-migrated on startup — the key is silently dropped. - Remove search_mode from config (MetacriticPlatformConfig), scheduler, and pipeline (AcquisitionConfig, run_acquisition, all helper signatures) - Consolidate pending_games_backlog + pending_games_latest into single pending_games table with startup migration (INSERT OR IGNORE + DROP) - Merge all 10 _backlog/_latest DB method pairs into unified methods targeting PendingGame - Collapse backlog/latest browse branching into single unified loop with max_pages budget, max_cycle_pages pacing, progress tracking, and infinite auto-reset to page 1 when budget exhausted - Remove five _by_mode dispatch helpers; callers use db.* directly - Fix infinite-retry on exhausted browse pages (max(last_page, start_page)) - Remove dead platform param from get_known_slugs - Update README, config migration, and 797 tests - Bump version to 3.0.0
1 parent d51358d commit 436bd18

11 files changed

Lines changed: 763 additions & 1414 deletions

File tree

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,8 @@ download_sites:
170170
| `min_metascore_reviews` | Minimum number of critic reviews required. | `10` |
171171
| `min_user_score` | Minimum Metacritic user score (0–10). | `7.5` |
172172
| `min_user_reviews` | Minimum number of user reviews required. | `10` |
173-
| `search_mode` | Scanning mode: `"backlog"` (historical deep scan) or `"latest"` (recent releases only). | `"latest"` |
174-
| `max_pages` | In `"backlog"` mode: total browse page window depth. The scanner progressively advances through `max_pages` pages across cycles. In `"latest"` mode: ignored. `0` = unlimited. | `500` |
175-
| `max_cycle_pages` | In `"backlog"` mode: max pages per cycle (pacing). In `"latest"` mode: the window of recent pages to scan (always pages 1-N). `0` = unlimited. | `0` |
173+
| `max_pages` | Total browse page depth budget. The scanner progressively advances through pages across cycles. When the budget is exhausted, scanning resets to page 1. `0` = unlimited. | `500` |
174+
| `max_cycle_pages` | Maximum pages per cycle (pacing). `0` = unlimited. | `0` |
176175
| `sort_order` | Browse sort order: `"new"` (release date) or `"metascore"` (by critic score). | `"new"` |
177176
| `max_queue_days` | Days a game stays in the pending queue before expiring. `0` = indefinite pending (no expiry). | `30` |
178177
| `enabled` | Enable or disable the Metacritic browse step. Disabling skips game discovery entirely. | `true` |
@@ -301,7 +300,7 @@ flowchart TD
301300
are skipped. `max_cycle_pages` controls the per-cycle page limit
302301
(default `0` = unlimited). The scanner advances through the
303302
`max_pages` window progressively — each cycle resumes where the
304-
last one left off, draining the backlog page by page.
303+
last one left off, with auto-reset to page 1 when the `max_pages` budget is exhausted.
305304
**Note:** browse scores are on a different scale and always
306305
exceed the configured thresholds — score filtering effectively starts
307306
at the verification step (phase 4), not here.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "gamarr"
7-
version = "2.1.2"
7+
version = "3.0.0"
88
description = "Metadata game downloader - torrent metadata harvester"
99
readme = "README.md"
1010
requires-python = ">=3.12"

src/gamarr/config.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from collections.abc import Iterator
1414

1515

16-
_CONFIG_VERSION = "1.0.0"
16+
_CONFIG_VERSION = "1.58.0"
1717
_CONFIG_FILENAME = "gamarr.yml"
1818

1919

@@ -111,7 +111,6 @@ class MetacriticPlatformConfig(BaseModel):
111111
max_pages: int = Field(default=500, ge=1)
112112
max_cycle_pages: int | None = Field(default=0, ge=0)
113113
sort_order: Literal["new", "metascore"] = "new"
114-
search_mode: Literal["backlog", "latest"] = "latest"
115114
reject_genre: list[str] = Field(default_factory=list)
116115
reject_title: list[str] = Field(default_factory=list) # case-insensitive substrings
117116

@@ -800,6 +799,25 @@ def _upgrade_freegog_entry(fg: dict[str, Any], defaults: dict[str, Any]) -> bool
800799
return True
801800

802801

802+
def _migrate_remove_search_mode(raw: dict[str, Any]) -> bool:
803+
"""Remove deprecated search_mode from metacritic platform overrides.
804+
805+
search_mode is no longer needed — the browse loop is unified.
806+
Returns True if any search_mode keys were removed.
807+
"""
808+
changed = False
809+
overrides = raw.get("review_sites", {}).get("metacritic", {}).get("platform_overrides", {})
810+
for platform_key, platform_config in overrides.items():
811+
if isinstance(platform_config, dict) and "search_mode" in platform_config:
812+
del platform_config["search_mode"]
813+
logger.info(
814+
"Config: removed deprecated 'search_mode' from platform '{}' — browse loop is unified",
815+
platform_key,
816+
)
817+
changed = True
818+
return changed
819+
820+
803821
def _migrate_config(raw: dict[str, Any]) -> bool:
804822
"""Migrate renamed config keys in-place for all platforms.
805823
@@ -834,6 +852,7 @@ def _migrate_config(raw: dict[str, Any]) -> bool:
834852
_migrate_daemon_mode,
835853
_migrate_add_post_process_path_case,
836854
_migrate_add_freegog_to_download_sites,
855+
_migrate_remove_search_mode,
837856
]
838857
for fn in _migrations:
839858
if fn(raw):

0 commit comments

Comments
 (0)