Skip to content

Commit 9a2a678

Browse files
authored
Fix Newznab/Torznab indexer bugs (#36)
* Set the minimum Buildarr Core version to v0.7.1 for multi-value enumeration support * Change `NabCategory` to a multi-value enumeration so the proper Newznab/Torznab category names can be used * Accept raw integer values in the Buildarr configuration so that new values added in Sonarr and Prowlarr do not cause errors to be raised in Buildarr * Fix configuration model that was subclassing `ConfigBase` instead of `SonarrConfigBase`
1 parent 97efb1c commit 9a2a678

File tree

6 files changed

+157
-85
lines changed

6 files changed

+157
-85
lines changed

buildarr_sonarr/config/indexers.py

Lines changed: 121 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,24 @@
2020
from __future__ import annotations
2121

2222
from logging import getLogger
23-
from typing import Any, Dict, List, Literal, Mapping, Optional, Set, Tuple, Type, Union
23+
from typing import (
24+
Any,
25+
Dict,
26+
Iterable,
27+
List,
28+
Literal,
29+
Mapping,
30+
Optional,
31+
Set,
32+
Tuple,
33+
Type,
34+
Union,
35+
cast,
36+
)
2437

2538
from buildarr.config import RemoteMapEntry
2639
from buildarr.types import BaseEnum, NonEmptyStr, Password, RssUrl
27-
from pydantic import AnyHttpUrl, Field, PositiveInt
40+
from pydantic import AnyHttpUrl, Field, PositiveInt, validator
2841
from typing_extensions import Annotated, Self
2942

3043
from ..api import api_delete, api_get, api_post, api_put
@@ -35,31 +48,29 @@
3548

3649

3750
class NabCategory(BaseEnum):
38-
"""
39-
Newznab/Torznab category enumeration.
40-
"""
51+
# https://github.com/Prowlarr/Prowlarr/blob/develop/src/NzbDrone.Core/Indexers/NewznabStandardCategory.cs
52+
TV = (5000, "TV")
53+
TV_WEBDL = (5010, "TV/WEB-DL")
54+
TV_FOREIGN = (5020, "TV/Foreign")
55+
TV_SD = (5030, "TV/SD")
56+
TV_HD = (5040, "TV/HD")
57+
TV_UHD = (5045, "TV/UHD")
58+
TV_OTHER = (5050, "TV/Other")
59+
TV_SPORT = (5060, "TV/Sport", "TV/Sports")
60+
TV_ANIME = (5070, "TV/Anime")
61+
TV_DOCUMENTARY = (5080, "TV/Documentary")
62+
TV_X265 = (5090, "TV/x265")
4163

42-
TV = 5000
43-
TV_WEBDL = 5010
44-
TV_FOREIGN = 5020
45-
TV_SD = 5030
46-
TV_HD = 5040
47-
TV_UHD = 5045
48-
TV_OTHER = 5050
49-
TV_SPORTS = 5060
50-
TV_ANIME = 5070
51-
TV_DOCUMENTARY = 5080
64+
@classmethod
65+
def decode(cls, value: int) -> Union[Self, int]:
66+
try:
67+
return cls(value)
68+
except ValueError:
69+
return value
5270

53-
# TODO: Make the enum also accept these values.
54-
# TV_WEBDL = "TV/WEB-DL"
55-
# TV_FOREIGN = "TV/Foreign"
56-
# TV_SD = "TV/SD"
57-
# TV_HD = "TV/HD"
58-
# TV_UHD = "TV/UHD"
59-
# TV_OTHER = "TV/Other"
60-
# TV_SPORTS = "TV/Sports"
61-
# TV_ANIME = "TV/Anime"
62-
# TV_DOCUMENTARY = "TV/Documentary"
71+
@classmethod
72+
def encode(cls, value: Union[Self, int]) -> int:
73+
return value if isinstance(value, int) else cast(int, value.value)
6374

6475

6576
class FilelistCategory(BaseEnum):
@@ -368,22 +379,28 @@ class NewznabIndexer(UsenetIndexer):
368379
API key for use with the Newznab API.
369380
"""
370381

371-
categories: Set[NabCategory] = {NabCategory.TV_SD, NabCategory.TV_HD}
382+
categories: Set[Union[NabCategory, int]] = {NabCategory.TV_SD, NabCategory.TV_HD}
372383
"""
373384
Categories to monitor for standard/daily shows.
374385
Define as empty to disable.
375386
376387
Values:
377388
378-
* `TV-WEBDL`
379-
* `TV-Foreign`
380-
* `TV-SD`
381-
* `TV-HD`
382-
* `TV-UHD`
383-
* `TV-Other`
384-
* `TV-Sports`
385-
* `TV-Anime`
386-
* `TV-Documentary`
389+
* `TV`
390+
* `TV/WEB-DL`
391+
* `TV/Foreign`
392+
* `TV/SD`
393+
* `TV/HD`
394+
* `TV/UHD`
395+
* `TV/Other`
396+
* `TV/Sport`
397+
* `TV/Anime`
398+
* `TV/Documentary`
399+
* `TV/x265`
400+
401+
*Changed in version 0.6.1*: The Sonarr-native values for Newznab/Torznab categories
402+
(e.g. `TV/WEB-DL`) can now be specified, instead of the Buildarr-native values
403+
(e.g. `TV-WEBDL`). The old values can still be used.
387404
"""
388405

389406
anime_categories: Set[NabCategory] = set()
@@ -393,15 +410,21 @@ class NewznabIndexer(UsenetIndexer):
393410
394411
Values:
395412
396-
* `TV-WEBDL`
397-
* `TV-Foreign`
398-
* `TV-SD`
399-
* `TV-HD`
400-
* `TV-UHD`
401-
* `TV-Other`
402-
* `TV-Sports`
403-
* `TV-Anime`
404-
* `TV-Documentary`
413+
* `TV`
414+
* `TV/WEB-DL`
415+
* `TV/Foreign`
416+
* `TV/SD`
417+
* `TV/HD`
418+
* `TV/UHD`
419+
* `TV/Other`
420+
* `TV/Sport`
421+
* `TV/Anime`
422+
* `TV/Documentary`
423+
* `TV/x265`
424+
425+
*Changed in version 0.6.1*: The Sonarr-native values for Newznab/Torznab categories
426+
(e.g. `TV/WEB-DL`) can now be specified, instead of the Buildarr-native values
427+
(e.g. `TV-WEBDL`). The old values can still be used.
405428
"""
406429

407430
anime_standard_format_search: bool = False
@@ -424,12 +447,12 @@ class NewznabIndexer(UsenetIndexer):
424447
(
425448
"categories",
426449
"categories",
427-
{"is_field": True, "encoder": lambda v: sorted(c.value for c in v)},
450+
{"is_field": True, "encoder": lambda v: sorted(NabCategory.encode(c) for c in v)},
428451
),
429452
(
430453
"anime_categories",
431454
"animeCategories",
432-
{"is_field": True, "encoder": lambda v: sorted(c.value for c in v)},
455+
{"is_field": True, "encoder": lambda v: sorted(NabCategory.encode(c) for c in v)},
433456
),
434457
("anime_standard_format_search", "animeStandardFormatSearch", {"is_field": True}),
435458
(
@@ -439,6 +462,16 @@ class NewznabIndexer(UsenetIndexer):
439462
),
440463
]
441464

465+
@validator("categories", "anime_categories")
466+
def validate_categories(
467+
cls,
468+
value: Iterable[Union[NabCategory, int]],
469+
) -> Set[Union[NabCategory, int]]:
470+
return set(
471+
NabCategory.decode(category) if isinstance(category, int) else category
472+
for category in value
473+
)
474+
442475

443476
class OmgwtfnzbsIndexer(UsenetIndexer):
444477
"""
@@ -860,15 +893,21 @@ class TorznabIndexer(TorrentIndexer):
860893
861894
Values:
862895
863-
* `TV-WEBDL`
864-
* `TV-Foreign`
865-
* `TV-SD`
866-
* `TV-HD`
867-
* `TV-UHD`
868-
* `TV-Other`
869-
* `TV-Sports`
870-
* `TV-Anime`
871-
* `TV-Documentary`
896+
* `TV`
897+
* `TV/WEB-DL`
898+
* `TV/Foreign`
899+
* `TV/SD`
900+
* `TV/HD`
901+
* `TV/UHD`
902+
* `TV/Other`
903+
* `TV/Sport`
904+
* `TV/Anime`
905+
* `TV/Documentary`
906+
* `TV/x265`
907+
908+
*Changed in version 0.6.1*: The Sonarr-native values for Newznab/Torznab categories
909+
(e.g. `TV/WEB-DL`) can now be specified, instead of the Buildarr-native values
910+
(e.g. `TV-WEBDL`). The old values can still be used.
872911
"""
873912

874913
anime_categories: Set[NabCategory] = set()
@@ -877,15 +916,21 @@ class TorznabIndexer(TorrentIndexer):
877916
878917
Values:
879918
880-
* `TV-WEBDL`
881-
* `TV-Foreign`
882-
* `TV-SD`
883-
* `TV-HD`
884-
* `TV-UHD`
885-
* `TV-Other`
886-
* `TV-Sports`
887-
* `TV-Anime`
888-
* `TV-Documentary`
919+
* `TV`
920+
* `TV/WEB-DL`
921+
* `TV/Foreign`
922+
* `TV/SD`
923+
* `TV/HD`
924+
* `TV/UHD`
925+
* `TV/Other`
926+
* `TV/Sport`
927+
* `TV/Anime`
928+
* `TV/Documentary`
929+
* `TV/x265`
930+
931+
*Changed in version 0.6.1*: The Sonarr-native values for Newznab/Torznab categories
932+
(e.g. `TV/WEB-DL`) can now be specified, instead of the Buildarr-native values
933+
(e.g. `TV-WEBDL`). The old values can still be used.
889934
"""
890935

891936
anime_standard_format_search: bool = False
@@ -908,12 +953,12 @@ class TorznabIndexer(TorrentIndexer):
908953
(
909954
"categories",
910955
"categories",
911-
{"is_field": True, "encoder": lambda v: sorted(c.value for c in v)},
956+
{"is_field": True, "encoder": lambda v: sorted(NabCategory.encode(c) for c in v)},
912957
),
913958
(
914959
"anime_categories",
915960
"animeCategories",
916-
{"is_field": True, "encoder": lambda v: sorted(c.value for c in v)},
961+
{"is_field": True, "encoder": lambda v: sorted(NabCategory.encode(c) for c in v)},
917962
),
918963
("anime_standard_format_search", "animeStandardFormatSearch", {"is_field": True}),
919964
(
@@ -923,6 +968,16 @@ class TorznabIndexer(TorrentIndexer):
923968
),
924969
]
925970

971+
@validator("categories", "anime_categories")
972+
def validate_categories(
973+
cls,
974+
value: Iterable[Union[NabCategory, int]],
975+
) -> Set[Union[NabCategory, int]]:
976+
return set(
977+
NabCategory.decode(category) if isinstance(category, int) else category
978+
for category in value
979+
)
980+
926981

927982
INDEXER_TYPES: Tuple[Type[Indexer], ...] = (
928983
FanzubIndexer,

buildarr_sonarr/config/metadata.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from typing import Any, Dict, List, Mapping, Optional, Tuple, Type
2323

24-
from buildarr.config import ConfigBase, RemoteMapEntry
24+
from buildarr.config import RemoteMapEntry
2525
from typing_extensions import Self
2626

2727
from ..api import api_get, api_put
@@ -247,7 +247,7 @@ class WdtvMetadata(Metadata):
247247
}
248248

249249

250-
class SonarrMetadataSettingsConfig(ConfigBase):
250+
class SonarrMetadataSettingsConfig(SonarrConfigBase):
251251
"""
252252
Sonarr metadata settings.
253253
Implementation wise each metadata is a unique object, updated using separate requests.

buildarr_sonarr/config/quality.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
from typing import Any, Dict, Mapping, Optional, cast
2525

26-
from buildarr.config import ConfigBase, ConfigTrashIDNotFoundError
26+
from buildarr.config import ConfigTrashIDNotFoundError
2727
from buildarr.state import state
2828
from buildarr.types import TrashID
2929
from pydantic import Field, validator
@@ -101,7 +101,7 @@ def validate_min_max(
101101
return quality_max
102102

103103

104-
class SonarrQualitySettingsConfig(ConfigBase):
104+
class SonarrQualitySettingsConfig(SonarrConfigBase):
105105
"""
106106
Quality definitions are used to set the permitted bit rates for each quality level.
107107

poetry.lock

Lines changed: 24 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)