diff --git a/tests/core/test_click_types.py b/tests/core/test_click_types.py new file mode 100644 index 0000000..b50dac1 --- /dev/null +++ b/tests/core/test_click_types.py @@ -0,0 +1,33 @@ +"""Tests for SubtitleCodecChoice — notably the ``original`` keep-source sentinel that +services set via the ``sub_format`` override (must not be rejected as an invalid codec).""" + +from __future__ import annotations + +import pytest + +from unshackle.core.tracks.subtitle import Subtitle +from unshackle.core.utils.click_types import SubtitleCodecChoice + +choice = SubtitleCodecChoice(Subtitle.Codec) + + +@pytest.mark.parametrize("value", ["original", "ORIGINAL", "Original"]) +def test_original_is_kept_as_sentinel(value): + assert choice.convert(value) == "original" + + +@pytest.mark.parametrize( + "value,expected", + [ + ("srt", Subtitle.Codec.SubRip), + ("ass", Subtitle.Codec.SubStationAlphav4), + ("vtt", Subtitle.Codec.WebVTT), + ("WVTT", Subtitle.Codec.fVTT), + ], +) +def test_codecs_still_map(value, expected): + assert choice.convert(value) == expected + + +def test_empty_is_none(): + assert choice.convert(None) is None diff --git a/unshackle/commands/dl.py b/unshackle/commands/dl.py index 231065d..7dc1e98 100644 --- a/unshackle/commands/dl.py +++ b/unshackle/commands/dl.py @@ -20,7 +20,7 @@ from http.cookiejar import CookieJar, MozillaCookieJar from itertools import product from pathlib import Path from threading import Lock -from typing import Any, Callable, Optional, TypedDict +from typing import Any, Callable, Optional, TypedDict, Union from uuid import UUID import click @@ -521,7 +521,7 @@ class dl: "--sub-format", type=SubtitleCodecChoice(Subtitle.Codec), default=None, - help="Set Output Subtitle Format, only converting if necessary.", + help="Set Output Subtitle Format, only converting if necessary. Use 'original' to keep source format.", ) @click.option("-V", "--video-only", is_flag=True, default=False, help="Only download video tracks.") @click.option("-A", "--audio-only", is_flag=True, default=False, help="Only download audio tracks.") @@ -1110,7 +1110,7 @@ class dl: require_subs: list[str], forced_subs: bool, exact_lang: bool, - sub_format: Optional[Subtitle.Codec], + sub_format: Optional[Union[Subtitle.Codec, str]], video_only: bool, audio_only: bool, subs_only: bool, @@ -2369,6 +2369,8 @@ class dl: with console.status("Converting Subtitles..."): for subtitle in title.tracks.subtitles: + if sub_format == "original": + continue if sub_format: if subtitle.codec != sub_format: subtitle.convert(sub_format, forced=True) diff --git a/unshackle/core/utils/click_types.py b/unshackle/core/utils/click_types.py index 3ccd5a9..542c380 100644 --- a/unshackle/core/utils/click_types.py +++ b/unshackle/core/utils/click_types.py @@ -131,6 +131,8 @@ class SubtitleCodecChoice(click.Choice): if value_lower not in choices: choices.append(value_lower) + choices.append("original") + self.aliases = aliases super().__init__(choices, case_sensitive=False) @@ -138,6 +140,9 @@ class SubtitleCodecChoice(click.Choice): if not value: return None + if str(value).lower() == "original": + return "original" + # First try to convert using the parent class converted_value = super().convert(value, param, ctx)