fix: keep polling queued Real-Debrid torrents (#1303)

Add `queued` to the existing set of non-terminal Real-Debrid torrent
states so `_handle_torrent_info` returns an in-progress `DownloadStatus`
and leaves the mutable download state eligible for subsequent polling.
Keep the change within the existing status-classification path rather
than introducing a new helper or changing the broader handling of
unknown statuses. The native Real-Debrid client currently treats the
documented `queued` torrent status as a terminal error because it is
absent from `_STATUS_DOWNLOADING`. This occurs after a torrent has been
added and its files selected, particularly for uncached torrents that
wait before downloading.

A torrent-info payload with `status: queued`, zero progress, and a
filename returns a non-complete `DownloadState.DOWNLOADING` result
rather than `DownloadState.ERROR`; After handling `queued`, the internal
download state remains non-terminal so a later status poll can be
processed instead of returning a cached error.

Fixes #1268

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
This commit is contained in:
Matt Van Horn
2026-09-03 23:19:50 -04:00
committed by GitHub
co-authored by Matt Van Horn
parent b98c2cb83e
commit 9f11e83e1f
2 changed files with 51 additions and 1 deletions
+1
View File
@@ -50,6 +50,7 @@ _STATUS_DOWNLOADING = frozenset(
{
"magnet_conversion",
"waiting_files_selection",
"queued",
"downloading",
"compressing",
"uploading",
+50 -1
View File
@@ -10,8 +10,9 @@ from unittest.mock import MagicMock
import pytest
from shelfmark.download.clients import DownloadState
from shelfmark.download.clients.alldebrid import AllDebridClient
from shelfmark.download.clients.realdebrid import RealDebridClient
from shelfmark.download.clients.realdebrid import RealDebridClient, _DownloadState
from shelfmark.download.clients.torrent_utils import (
DebridMagnet,
DebridTorrentFile,
@@ -149,6 +150,54 @@ class TestRealDebridAdd:
put.assert_not_called()
class TestRealDebridStatus:
@staticmethod
def _client():
return RealDebridClient.__new__(RealDebridClient)
@staticmethod
def _state(tmp_path):
return _DownloadState(
torrent_id="RD1",
name="Dune",
target_dir=tmp_path,
phase="waiting_rd",
)
def test_queued_remains_downloading_and_allows_later_status(self, tmp_path):
client = self._client()
state = self._state(tmp_path)
queued = client._handle_torrent_info(
{"status": "queued", "progress": 0, "filename": "Dune.epub"},
state,
)
assert queued.state == DownloadState.DOWNLOADING
assert queued.progress == 0
assert queued.complete is False
assert state.phase == "waiting_rd"
assert state.error_message is None
downloading = client._handle_torrent_info(
{"status": "downloading", "progress": 10, "filename": "Dune.epub"},
state,
)
assert downloading.state == DownloadState.DOWNLOADING
assert state.phase == "waiting_rd"
def test_dead_is_terminal_and_caches_error(self, tmp_path):
client = self._client()
state = self._state(tmp_path)
status = client._handle_torrent_info({"status": "dead"}, state)
assert status.state == DownloadState.ERROR
assert state.phase == "error"
assert state.error_message == "Real-Debrid status error: dead"
class TestAllDebridAdd:
@staticmethod
def _client(monkeypatch):