fix(deluge): send seeding ratio limit under Deluge's own keys (#1367)

Deluge's per-torrent options are `stop_at_ratio` (bool) and `stop_ratio`
(float), and `torrentmanager` checks `options['stop_at_ratio'] and
get_ratio() >= options['stop_ratio']`. We were putting the indexer's
float into `stop_at_ratio`, which only switched stopping on and left the
daemon's global ratio (default 2.0) as the one actually enforced. A
`ratio_limit` of 0 turned stopping off entirely. `stop_at_ratio_enabled`
is not a Deluge option at all.

Deluge has no per-torrent seeding time limit, `seed_time_limit` is a
global core preference, so the value is logged as unapplied instead of
sent as a key the daemon drops.

qBittorrent and Transmission already honour both indexer limits, so this
removes a silent difference between clients.

## Verification

- `tests/prowlarr/test_deluge_client.py`: the ratio arrives as
`stop_ratio` with `stop_at_ratio` set, and no key Deluge does not define
is sent. Both fail on current main and pass here.
- Full suite (3165), ruff, ruff format, basedpyright, vulture green.
This commit is contained in:
splitsec2
2026-09-20 23:06:14 -04:00
committed by GitHub
parent 7c8e89c567
commit 1a5b37d9d3
2 changed files with 82 additions and 3 deletions
+6 -3
View File
@@ -292,11 +292,14 @@ class DelugeClient(DownloadClient):
# Per-torrent seeding limits from indexer
seeding_time_limit = coerce_optional_int(kwargs.get("seeding_time_limit"))
if seeding_time_limit is not None:
options["seed_time_limit"] = seeding_time_limit
logger.debug(
"Deluge has no per-torrent seeding time limit, ignoring %s minutes",
seeding_time_limit,
)
ratio_limit = coerce_optional_float(kwargs.get("ratio_limit"))
if ratio_limit is not None:
options["stop_at_ratio"] = ratio_limit
options["stop_at_ratio_enabled"] = True
options["stop_ratio"] = ratio_limit
options["stop_at_ratio"] = True
if torrent_info.is_magnet:
magnet_url = torrent_info.magnet_url or url
+76
View File
@@ -114,6 +114,82 @@ class TestDelugeClientAddDownload:
{},
)
def test_add_download_sends_ratio_limit_as_stop_ratio(self, monkeypatch):
"""Ratio limits should use Deluge's stop_ratio float plus the stop_at_ratio switch."""
config_values = {
"DELUGE_HOST": "http://localhost",
"DELUGE_PORT": "8112",
"DELUGE_PASSWORD": "password",
"DELUGE_CATEGORY": "books",
}
monkeypatch.setattr(
"shelfmark.download.clients.deluge.config.get",
make_config_getter(config_values),
)
from shelfmark.download.clients.deluge import DelugeClient
client = DelugeClient()
monkeypatch.setattr(client, "_ensure_connected", lambda: None)
mock_rpc_call = MagicMock(return_value="abcdef1234567890abcdef1234567890abcdef12")
monkeypatch.setattr(client, "_rpc_call", mock_rpc_call)
monkeypatch.setattr(client, "_try_set_label", MagicMock())
magnet = "magnet:?xt=urn:btih:ABCDEF1234567890ABCDEF1234567890ABCDEF12&dn=test"
with patch(
"shelfmark.download.clients.deluge.extract_torrent_info", autospec=True
) as mock_extract:
mock_extract.return_value = TorrentInfo(
info_hash="abcdef1234567890abcdef1234567890abcdef12",
torrent_data=None,
is_magnet=True,
magnet_url=magnet,
)
client.add_download(magnet, "Test", ratio_limit=1.5)
mock_rpc_call.assert_called_once_with(
"core.add_torrent_magnet",
magnet,
{"stop_ratio": 1.5, "stop_at_ratio": True},
)
def test_add_download_skips_options_deluge_does_not_define(self, monkeypatch):
"""Deluge has no per-torrent seeding time limit, so no unknown keys are sent."""
config_values = {
"DELUGE_HOST": "http://localhost",
"DELUGE_PORT": "8112",
"DELUGE_PASSWORD": "password",
"DELUGE_CATEGORY": "books",
}
monkeypatch.setattr(
"shelfmark.download.clients.deluge.config.get",
make_config_getter(config_values),
)
from shelfmark.download.clients.deluge import DelugeClient
client = DelugeClient()
monkeypatch.setattr(client, "_ensure_connected", lambda: None)
mock_rpc_call = MagicMock(return_value="abcdef1234567890abcdef1234567890abcdef12")
monkeypatch.setattr(client, "_rpc_call", mock_rpc_call)
monkeypatch.setattr(client, "_try_set_label", MagicMock())
magnet = "magnet:?xt=urn:btih:ABCDEF1234567890ABCDEF1234567890ABCDEF12&dn=test"
with patch(
"shelfmark.download.clients.deluge.extract_torrent_info", autospec=True
) as mock_extract:
mock_extract.return_value = TorrentInfo(
info_hash="abcdef1234567890abcdef1234567890abcdef12",
torrent_data=None,
is_magnet=True,
magnet_url=magnet,
)
client.add_download(magnet, "Test", ratio_limit=1.5, seeding_time_limit=120)
options = mock_rpc_call.call_args.args[2]
assert "stop_at_ratio_enabled" not in options
assert "seed_time_limit" not in options
class TestDelugeClientErrors:
"""Tests for Deluge error handling fallbacks."""