mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-09-24 21:20:31 +01:00
Ship Prowlarr per-entry rows as opt-in, not the default (#1145)
#1140 fixed the guid-only dedup that hid results from filter-specific indexer entries, but shipped the new behaviour on by default: PROWLARR_COLLAPSE_DUPLICATES defaulted off, so every existing Prowlarr user got extra rows for any release that two indexer entries both returned, and the setting only let them opt back into what they already had. Default it on. The dedup key stays indexer-qualified, so the entries are still distinct internally; collapse then merges them back to one row, resolved by the Prowlarr priority rather than by query order as before. The visible result set matches what users had prior to #1140, and anyone who wants the per-entry rows (freeleech and the like) turns the setting off. Beyond the noisier list, the default mattered because split rows differ only by indexer name while sharing a title, size and peer count. Two of them have distinct source_ids, so the queue's duplicate guard does not fire, and the second grab's find_existing() matches the first by infohash and runs post-processing over the same download again, delivering the book twice. The search-side fallback in config.get(..., True) is flipped to agree with the field default. In production the field default governs, since the config cache is seeded from the registry and the fallback only applies to an unregistered key. The source tests monkeypatch config.get with a plain dict lookup, though, so the fallback is what they exercise: leaving it False would have kept every default-behaviour test asserting the opposite of what ships. A new test pins the two together. The deduplication tests now opt out explicitly, since they assert the split itself. test_collapse_off_by_default_keeps_both_rows becomes a pair, one for the untouched setting collapsing to a single row and one for opting out. docs/environment-variables.md is regenerated rather than hand-edited. It was already stale on main, so it also picks up RTORRENT_AUDIOBOOK_LABEL, DIRECT_DOWNLOAD_LANGUAGE_FROM_PATH, and reworded IRC_SEARCH_BOT and RTORRENT_LABEL text from earlier merges. The rest is fallout from the ruff 0.16.0 bump in #1139, which enabled a much larger default rule set and started formatting Python code blocks in Markdown: _find_existing_alias_user() uses min() instead of sorted()[0] (FURB192, currently failing Python Quality on main), and the two READMEs get their code blocks reformatted.
This commit is contained in:
@@ -169,6 +169,7 @@ uv run pytest tests/ --cov=shelfmark -m "not integration"
|
||||
```python
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
class TestMyFeature:
|
||||
def test_something(self, monkeypatch):
|
||||
# Mock config values
|
||||
@@ -188,6 +189,7 @@ class TestMyFeature:
|
||||
import pytest
|
||||
from .conftest import APIClient, DownloadTracker
|
||||
|
||||
|
||||
@pytest.mark.e2e
|
||||
class TestMyEndpoint:
|
||||
def test_endpoint_works(self, protected_api_client: APIClient):
|
||||
|
||||
@@ -796,7 +796,14 @@ def _mam_result(indexer_id: int, indexer: str, guid: str, *, freeleech: bool = F
|
||||
|
||||
|
||||
class TestIndexerAwareDeduplication:
|
||||
"""One tracker as several Prowlarr entries must not collapse to one row (#1137)."""
|
||||
"""One tracker as several Prowlarr entries must not collapse to one row (#1137).
|
||||
|
||||
These assert the split itself, so they turn PROWLARR_COLLAPSE_DUPLICATES off:
|
||||
it ships on, which keeps the release list as it was before #1137 for everyone
|
||||
who has not asked for the per-entry rows.
|
||||
"""
|
||||
|
||||
SPLIT = {"PROWLARR_COLLAPSE_DUPLICATES": False}
|
||||
|
||||
ONLY_ACTIVE = 10
|
||||
FREELEECH = 25
|
||||
@@ -834,6 +841,7 @@ class TestIndexerAwareDeduplication:
|
||||
)
|
||||
],
|
||||
},
|
||||
config_values=self.SPLIT,
|
||||
)
|
||||
|
||||
assert len(releases) == 2
|
||||
@@ -850,6 +858,7 @@ class TestIndexerAwareDeduplication:
|
||||
_mam_result(self.FREELEECH, "MyAnonamouse - Freeleech", shared_guid)
|
||||
],
|
||||
},
|
||||
config_values=self.SPLIT,
|
||||
)
|
||||
|
||||
source_ids = [r.source_id for r in releases]
|
||||
@@ -868,6 +877,7 @@ class TestIndexerAwareDeduplication:
|
||||
_mam_result(self.FREELEECH, "MyAnonamouse - Freeleech", shared_guid)
|
||||
],
|
||||
},
|
||||
config_values=self.SPLIT,
|
||||
)
|
||||
|
||||
assert len(releases) == 2
|
||||
@@ -914,7 +924,7 @@ class TestBuildSourceId:
|
||||
|
||||
|
||||
class TestCollapseDuplicatesSetting:
|
||||
"""Opt-in one-row-per-release collapse, resolved by Prowlarr's priority."""
|
||||
"""One-row-per-release collapse, on by default, resolved by Prowlarr's priority."""
|
||||
|
||||
ONLY_ACTIVE = 10
|
||||
FREELEECH = 25
|
||||
@@ -951,8 +961,8 @@ class TestCollapseDuplicatesSetting:
|
||||
assert len(releases) == 1
|
||||
assert releases[0].indexer == "MyAnonamouse"
|
||||
|
||||
def test_collapse_off_by_default_keeps_both_rows(self, monkeypatch):
|
||||
releases = TestIndexerAwareDeduplication()._search(
|
||||
def _search_shared_guid(self, monkeypatch, config_values):
|
||||
return TestIndexerAwareDeduplication()._search(
|
||||
monkeypatch,
|
||||
{
|
||||
self.ONLY_ACTIVE: [
|
||||
@@ -962,11 +972,34 @@ class TestCollapseDuplicatesSetting:
|
||||
_mam_result(self.FREELEECH, "MAM - Freeleech", "https://tracker.example/t/9")
|
||||
],
|
||||
},
|
||||
config_values=config_values,
|
||||
priorities={self.FREELEECH: 20, self.ONLY_ACTIVE: 24},
|
||||
)
|
||||
|
||||
def test_collapse_is_on_when_the_setting_is_untouched(self, monkeypatch):
|
||||
"""An upgrading user who sets nothing keeps the single row they had before #1137."""
|
||||
releases = self._search_shared_guid(monkeypatch, None)
|
||||
|
||||
assert len(releases) == 1
|
||||
assert releases[0].indexer == "MAM - Freeleech"
|
||||
|
||||
def test_opting_out_keeps_every_indexer_entry(self, monkeypatch):
|
||||
releases = self._search_shared_guid(monkeypatch, {"PROWLARR_COLLAPSE_DUPLICATES": False})
|
||||
|
||||
assert len(releases) == 2
|
||||
|
||||
def test_the_settings_field_and_the_search_fallback_agree(self):
|
||||
"""The field default is what governs in production; the search fallback only
|
||||
applies to an unregistered key. They have to say the same thing.
|
||||
"""
|
||||
from shelfmark.release_sources.prowlarr.settings import prowlarr_config_settings
|
||||
|
||||
field = next(
|
||||
f for f in prowlarr_config_settings() if f.key == "PROWLARR_COLLAPSE_DUPLICATES"
|
||||
)
|
||||
|
||||
assert field.default is True
|
||||
|
||||
|
||||
class TestBuildIndexerPriority:
|
||||
"""The priority NUMBER from Prowlarr is the rank; the id is only the key."""
|
||||
|
||||
Reference in New Issue
Block a user