refactor(subtitles): RuleScope.level → RuleScopeLevel enum
Six niveaux possibles (global, release_group, movie, show, season, episode) étaient passés en str libre, le commentaire docstring servant de seule documentation. Introduit RuleScopeLevel(str, Enum) — toujours sérialisable en YAML, mais le set fixe est désormais imposé par le typage. to_dict() sort explicitement .value pour rester safe côté écrivains YAML.
This commit is contained in:
@@ -6,6 +6,7 @@ from .exceptions import SubtitleNotFound
|
|||||||
from .services import PatternDetector, SubtitleIdentifier, SubtitleMatcher
|
from .services import PatternDetector, SubtitleIdentifier, SubtitleMatcher
|
||||||
from .value_objects import (
|
from .value_objects import (
|
||||||
RuleScope,
|
RuleScope,
|
||||||
|
RuleScopeLevel,
|
||||||
ScanStrategy,
|
ScanStrategy,
|
||||||
SubtitleFormat,
|
SubtitleFormat,
|
||||||
SubtitleLanguage,
|
SubtitleLanguage,
|
||||||
@@ -30,5 +31,6 @@ __all__ = [
|
|||||||
"TypeDetectionMethod",
|
"TypeDetectionMethod",
|
||||||
"SubtitleMatchingRules",
|
"SubtitleMatchingRules",
|
||||||
"RuleScope",
|
"RuleScope",
|
||||||
|
"RuleScopeLevel",
|
||||||
"SubtitleNotFound",
|
"SubtitleNotFound",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from dataclasses import dataclass, field
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from ..shared.value_objects import ImdbId
|
from ..shared.value_objects import ImdbId
|
||||||
from .value_objects import RuleScope, SubtitleMatchingRules
|
from .value_objects import RuleScope, RuleScopeLevel, SubtitleMatchingRules
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -86,10 +86,13 @@ class SubtitleRuleSet:
|
|||||||
if self._min_confidence is not None:
|
if self._min_confidence is not None:
|
||||||
delta["min_confidence"] = self._min_confidence
|
delta["min_confidence"] = self._min_confidence
|
||||||
return {
|
return {
|
||||||
"scope": {"level": self.scope.level, "identifier": self.scope.identifier},
|
"scope": {
|
||||||
|
"level": self.scope.level.value,
|
||||||
|
"identifier": self.scope.identifier,
|
||||||
|
},
|
||||||
"override": delta,
|
"override": delta,
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def global_default(cls) -> SubtitleRuleSet:
|
def global_default(cls) -> SubtitleRuleSet:
|
||||||
return cls(scope=RuleScope(level="global"))
|
return cls(scope=RuleScope(level=RuleScopeLevel.GLOBAL))
|
||||||
|
|||||||
@@ -83,9 +83,20 @@ class SubtitleMatchingRules:
|
|||||||
min_confidence: float = 0.7
|
min_confidence: float = 0.7
|
||||||
|
|
||||||
|
|
||||||
|
class RuleScopeLevel(str, Enum):
|
||||||
|
"""At which level a subtitle rule set applies."""
|
||||||
|
|
||||||
|
GLOBAL = "global"
|
||||||
|
RELEASE_GROUP = "release_group"
|
||||||
|
MOVIE = "movie"
|
||||||
|
SHOW = "show"
|
||||||
|
SEASON = "season"
|
||||||
|
EPISODE = "episode"
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class RuleScope:
|
class RuleScope:
|
||||||
"""At which level a rule set applies."""
|
"""At which level a rule set applies."""
|
||||||
|
|
||||||
level: str # "global" | "release_group" | "movie" | "show" | "season" | "episode"
|
level: RuleScopeLevel
|
||||||
identifier: str | None = None # imdb_id, group name, "S01", "S01E03"…
|
identifier: str | None = None # imdb_id, group name, "S01", "S01E03"…
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
|
|||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from alfred.domain.subtitles.aggregates import SubtitleRuleSet
|
from alfred.domain.subtitles.aggregates import SubtitleRuleSet
|
||||||
from alfred.domain.subtitles.value_objects import RuleScope
|
from alfred.domain.subtitles.value_objects import RuleScope, RuleScopeLevel
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from alfred.infrastructure.persistence.memory.ltm.components.subtitle_preferences import (
|
from alfred.infrastructure.persistence.memory.ltm.components.subtitle_preferences import (
|
||||||
@@ -72,7 +72,9 @@ class RuleSetRepository:
|
|||||||
rg_data = _load_yaml(rg_path).get("override", {})
|
rg_data = _load_yaml(rg_path).get("override", {})
|
||||||
if rg_data:
|
if rg_data:
|
||||||
rg_ruleset = SubtitleRuleSet(
|
rg_ruleset = SubtitleRuleSet(
|
||||||
scope=RuleScope(level="release_group", identifier=release_group),
|
scope=RuleScope(
|
||||||
|
level=RuleScopeLevel.RELEASE_GROUP, identifier=release_group
|
||||||
|
),
|
||||||
parent=current,
|
parent=current,
|
||||||
)
|
)
|
||||||
rg_ruleset.override(**_filter_override(rg_data))
|
rg_ruleset.override(**_filter_override(rg_data))
|
||||||
@@ -85,7 +87,7 @@ class RuleSetRepository:
|
|||||||
local_data = _load_yaml(self._alfred_dir / "rules.yaml").get("override", {})
|
local_data = _load_yaml(self._alfred_dir / "rules.yaml").get("override", {})
|
||||||
if local_data:
|
if local_data:
|
||||||
local_ruleset = SubtitleRuleSet(
|
local_ruleset = SubtitleRuleSet(
|
||||||
scope=RuleScope(level="show"),
|
scope=RuleScope(level=RuleScopeLevel.SHOW),
|
||||||
parent=current,
|
parent=current,
|
||||||
)
|
)
|
||||||
local_ruleset.override(**_filter_override(local_data))
|
local_ruleset.override(**_filter_override(local_data))
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from alfred.domain.subtitles.entities import MediaSubtitleMetadata, SubtitleCand
|
|||||||
from alfred.domain.subtitles.services.utils import available_subtitles
|
from alfred.domain.subtitles.services.utils import available_subtitles
|
||||||
from alfred.domain.subtitles.value_objects import (
|
from alfred.domain.subtitles.value_objects import (
|
||||||
RuleScope,
|
RuleScope,
|
||||||
|
RuleScopeLevel,
|
||||||
SubtitleFormat,
|
SubtitleFormat,
|
||||||
SubtitleLanguage,
|
SubtitleLanguage,
|
||||||
SubtitleMatchingRules,
|
SubtitleMatchingRules,
|
||||||
@@ -257,7 +258,7 @@ class TestSubtitleRuleSet:
|
|||||||
def test_override_partial_keeps_parent_for_unset_fields(self):
|
def test_override_partial_keeps_parent_for_unset_fields(self):
|
||||||
parent = SubtitleRuleSet.global_default()
|
parent = SubtitleRuleSet.global_default()
|
||||||
child = SubtitleRuleSet(
|
child = SubtitleRuleSet(
|
||||||
scope=RuleScope(level="show", identifier="tt1"),
|
scope=RuleScope(level=RuleScopeLevel.SHOW, identifier="tt1"),
|
||||||
parent=parent,
|
parent=parent,
|
||||||
)
|
)
|
||||||
child.override(languages=["jpn"])
|
child.override(languages=["jpn"])
|
||||||
@@ -267,14 +268,14 @@ class TestSubtitleRuleSet:
|
|||||||
assert rules.min_confidence == parent.resolve(_DEFAULT_RULES).min_confidence
|
assert rules.min_confidence == parent.resolve(_DEFAULT_RULES).min_confidence
|
||||||
|
|
||||||
def test_to_dict_only_emits_set_deltas(self):
|
def test_to_dict_only_emits_set_deltas(self):
|
||||||
rs = SubtitleRuleSet(scope=RuleScope(level="show", identifier="tt1"))
|
rs = SubtitleRuleSet(scope=RuleScope(level=RuleScopeLevel.SHOW, identifier="tt1"))
|
||||||
rs.override(languages=["fra"])
|
rs.override(languages=["fra"])
|
||||||
out = rs.to_dict()
|
out = rs.to_dict()
|
||||||
assert out["scope"] == {"level": "show", "identifier": "tt1"}
|
assert out["scope"] == {"level": "show", "identifier": "tt1"}
|
||||||
assert out["override"] == {"languages": ["fra"]}
|
assert out["override"] == {"languages": ["fra"]}
|
||||||
|
|
||||||
def test_to_dict_full_override(self):
|
def test_to_dict_full_override(self):
|
||||||
rs = SubtitleRuleSet(scope=RuleScope(level="global"))
|
rs = SubtitleRuleSet(scope=RuleScope(level=RuleScopeLevel.GLOBAL))
|
||||||
rs.override(
|
rs.override(
|
||||||
languages=["fra"],
|
languages=["fra"],
|
||||||
formats=["srt"],
|
formats=["srt"],
|
||||||
|
|||||||
Reference in New Issue
Block a user