mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 20:15:10 +00:00
Adds the label to audio, subtitle and embedded audio names unless the name already says it, and escapes track lines in the --list tree.
227 lines
8.7 KiB
Python
227 lines
8.7 KiB
Python
from pathlib import Path
|
|
from typing import Callable, Optional
|
|
|
|
import pytest
|
|
from langcodes import Language
|
|
from rich.text import Text
|
|
|
|
from unshackle.core.config import config
|
|
from unshackle.core.tracks import Audio, Subtitle, Tracks, Video
|
|
from unshackle.core.utilities import language_name, multi_script_languages, with_script
|
|
|
|
|
|
def sub(lang: str, name: Optional[str] = None, sdh: bool = False, original: bool = False) -> Subtitle:
|
|
return Subtitle(
|
|
id_="s",
|
|
url="https://x/s",
|
|
codec=Subtitle.Codec.WebVTT,
|
|
language=lang,
|
|
name=name,
|
|
sdh=sdh,
|
|
is_original_lang=original,
|
|
)
|
|
|
|
|
|
def test_multi_script_languages_come_from_cldr() -> None:
|
|
assert {"zh", "yue", "sr"} <= multi_script_languages()
|
|
assert not {"en", "pt", "ja"} & multi_script_languages()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("tag", "expected"),
|
|
[
|
|
("zh", "zh"),
|
|
("zh-TW", "zh-Hant-TW"),
|
|
("zh-CN", "zh-Hans-CN"),
|
|
("zh-HK", "zh-Hant-HK"),
|
|
("zh-SG", "zh-Hans-SG"),
|
|
("zh-Hant", "zh-Hant"),
|
|
("yue-HK", "yue-Hant-HK"),
|
|
("sr-ME", "sr-Latn-ME"),
|
|
("sr-RS", "sr-Cyrl-RS"),
|
|
("pa-PK", "pa-Arab-PK"),
|
|
("ms-MY", "ms-MY"),
|
|
("en-US", "en-US"),
|
|
("und-TW", "und-TW"),
|
|
("und", "und"),
|
|
],
|
|
)
|
|
def test_with_script(tag: str, expected: str) -> None:
|
|
assert str(with_script(Language.get(tag))) == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("tag", "expected"),
|
|
[
|
|
("zh-Hant-TW", "Chinese (Traditional)"),
|
|
("zh-Hans-CN", "Chinese (Simplified)"),
|
|
("zh-Hant-HK", "Chinese (Traditional, Hong Kong)"),
|
|
("zh-TW", "Chinese (Taiwan)"),
|
|
("pt-BR", "Portuguese"),
|
|
("pt-PT", "Portuguese (Portugal)"),
|
|
("en-US", "English"),
|
|
("en-GB", "English (United Kingdom)"),
|
|
("ja-JP", "Japanese"),
|
|
("fr-CA", "French (Canada)"),
|
|
("ar-001", "Arabic"),
|
|
("es-419", "Spanish (Latin America)"),
|
|
("en", "English"),
|
|
("de-DE", "German"),
|
|
("en-ZZ", "English"),
|
|
("en-XA", "English"),
|
|
("en-Zzzz", "English"),
|
|
("sq-XK", "Albanian (Kosovo)"),
|
|
("mn-Mong-CN", "Mongolian (China)"),
|
|
("und", None),
|
|
("qaa", None),
|
|
("x-foo", None),
|
|
],
|
|
)
|
|
def test_language_name(tag: str, expected: Optional[str]) -> None:
|
|
assert language_name(Language.get(tag)) == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("tag", "expected"),
|
|
[
|
|
("zh-Hant-TW", "中文(繁體)"),
|
|
("zh-Hans-CN", "中文(简体)"),
|
|
("zh-Hant-HK", "中文(繁體,香港)"),
|
|
("zh-Hans-MO", "中文(简体,澳门)"),
|
|
("zh-TW", "中文(台灣)"),
|
|
("zh-HK", "中文(香港)"),
|
|
("cmn-Hant", "中文(繁體)"),
|
|
("yue-Hant", "粵語(繁體)"),
|
|
("sr-ME", "Srpski (Crna Gora)"),
|
|
("ka", "ქართული"),
|
|
("hy", "Հայերեն"),
|
|
("pt-BR", "Português"),
|
|
("pt-PT", "Português (Portugal)"),
|
|
("es-419", "Español (Latinoamérica)"),
|
|
("sr-Latn-ME", "Srpski (latinica, Crna Gora)"),
|
|
("ja-JP", "日本語"),
|
|
("en-GB", "English (United Kingdom)"),
|
|
("en-HK", "English (Hong Kong)"),
|
|
("qaa", None),
|
|
],
|
|
)
|
|
def test_native_language_name(tag: str, expected: Optional[str], monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(config, "muxing", {"track_names": "native"})
|
|
assert language_name(Language.get(tag)) == expected
|
|
|
|
|
|
def test_native_subtitle_name_keeps_the_flag(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(config, "muxing", {"track_names": "native"})
|
|
assert sub("zh-TW", sdh=True).get_track_name() == "中文(繁體) (SDH)"
|
|
assert sub("zh", name="Mandarin").get_track_name() == "Mandarin"
|
|
|
|
|
|
def test_no_language_name_when_track_names_is_none(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(config, "muxing", {"track_names": "none"})
|
|
assert sub("en").get_track_name() is None
|
|
assert sub("en", sdh=True).get_track_name() == "SDH"
|
|
assert sub("en", name="English [Full]").get_track_name() == "English [Full]"
|
|
video = Video(id_="v", url="https://x/v", codec=Video.Codec.AVC, language="en")
|
|
video.data["audio_language"] = "en"
|
|
assert video.embedded_audio_name() == ""
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("muxing", "track", "expected"),
|
|
[
|
|
({"original_label": "[Original]"}, sub("ja", sdh=True, original=True), "Japanese [Original] (SDH)"),
|
|
({"original_label": "[Original]"}, sub("ko"), "Korean"),
|
|
({"original_label": "| Original", "track_names": "none"}, sub("ja", original=True), "| Original"),
|
|
],
|
|
)
|
|
def test_original_label_follows_the_name_of_an_original_language_track(
|
|
muxing: dict, track: Subtitle, expected: str, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
monkeypatch.setattr(config, "muxing", muxing)
|
|
assert track.get_track_name() == expected
|
|
|
|
|
|
@pytest.mark.parametrize("name", ["Original", "Japanese [Original]", "Japanese (original)"])
|
|
def test_original_label_is_not_added_twice(name: str, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(config, "muxing", {"original_label": "[Original]"})
|
|
assert sub("ja", name=name, original=True).get_track_name() == name
|
|
|
|
|
|
@pytest.mark.parametrize("label", [True, 1, ["Original"], " "])
|
|
def test_original_label_that_is_not_text_is_ignored(label: object, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(config, "muxing", {"original_label": label, "track_names": "none"})
|
|
assert sub("ja", sdh=True, original=True).get_track_name() == "SDH"
|
|
|
|
|
|
def test_embedded_audio_takes_the_original_label(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(config, "muxing", {"original_label": "[Original]"})
|
|
video = Video(id_="v", url="https://x/v", codec=Video.Codec.AVC, language="ja", is_original_lang=True)
|
|
video.data["audio_language"] = "ja"
|
|
assert video.embedded_audio_name() == "Japanese [Original]"
|
|
|
|
|
|
def test_track_list_shows_a_bracketed_label_as_text(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.setattr(config, "muxing", {"original_label": "[/]"})
|
|
tree = Tracks([sub("ja", original=True)]).tree()[0]
|
|
labels = [Text.from_markup(node.label).plain for node in tree.children[0].children]
|
|
assert labels == ["[VTT] | ja | Japanese [/]"]
|
|
|
|
|
|
def test_subtitle_names_and_tags_the_script_but_keeps_its_language() -> None:
|
|
track = sub("zh-TW")
|
|
assert track.name is None
|
|
assert track.get_track_name() == "Chinese (Traditional)"
|
|
assert str(track.mux_language) == "zh-Hant-TW"
|
|
assert str(track.language) == "zh-TW"
|
|
|
|
|
|
def test_subtitle_flag_follows_the_default_name() -> None:
|
|
assert sub("zh-CN", sdh=True).get_track_name() == "Chinese (Simplified) (SDH)"
|
|
|
|
|
|
def test_audio_gets_no_script() -> None:
|
|
track = Audio(id_="a", url="https://x/a", codec=Audio.Codec.AAC, language="zh-TW", bitrate=1)
|
|
assert track.get_track_name() == "Chinese (Taiwan)"
|
|
assert str(track.mux_language) == "zh-TW"
|
|
|
|
|
|
def test_a_service_name_wins() -> None:
|
|
assert sub("zh", name="简体中文").get_track_name() == "简体中文"
|
|
|
|
|
|
def test_mkvmerge_gets_the_subtitle_script_and_name(tmp_path: Path, mux_args: Callable[..., list[str]]) -> None:
|
|
video = Video(id_="v", url="https://x/v", codec=Video.Codec.AVC, language="zh-TW", width=1920, height=1080)
|
|
audio = Audio(id_="a", url="https://x/a", codec=Audio.Codec.AAC, language="zh-TW", bitrate=1)
|
|
subtitle = sub("zh-TW")
|
|
for track, file in ((video, "v.mp4"), (audio, "a.mp4"), (subtitle, "s.vtt")):
|
|
track.path = tmp_path / file
|
|
track.path.write_bytes(b"\x00" * 16)
|
|
|
|
args = mux_args(Tracks([video, audio, subtitle]), output_path=tmp_path / "o.mkv")
|
|
|
|
def last_option(file: str, flag: str) -> str:
|
|
"""Return the value of the last flag given before the file, which is the one mkvmerge applies to it."""
|
|
before = args[: args.index(str(tmp_path / file))]
|
|
return before[len(before) - before[::-1].index(flag)]
|
|
|
|
assert last_option("s.vtt", "--language") == "0:zh-Hant-TW"
|
|
assert last_option("s.vtt", "--track-name") == "0:Chinese (Traditional)"
|
|
assert last_option("a.mp4", "--language") == "0:zh-TW"
|
|
|
|
|
|
def test_the_default_name_follows_a_later_language_change() -> None:
|
|
track = sub("yue")
|
|
track.language = Language.get("zh-Hant")
|
|
assert track.get_track_name() == "Chinese (Traditional)"
|
|
|
|
|
|
def test_a_language_assigned_as_text_later_is_parsed() -> None:
|
|
track = sub("pt")
|
|
track.language = "pt-PT"
|
|
assert track.language == Language.get("pt-PT")
|
|
assert track.get_track_name() == "Portuguese (Portugal)"
|
|
assert str(track) == "SUB | [VTT] | pt-PT | Portuguese (Portugal)"
|
|
track.language = None
|
|
assert str(track.language) == "und"
|
|
assert track.get_track_name() is None
|