mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-14 21:15:06 +00:00
fix(mux): address embedded audio by the file's real mkvmerge track IDs
A TS file can hold its audio first, which put the audio name on the video.
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from unshackle.core import binaries
|
||||
from unshackle.core.tracks import Tracks, Video
|
||||
from unshackle.core.tracks.tracks import file_track_ids
|
||||
|
||||
|
||||
def make_video(track_id: str, **data) -> Video:
|
||||
@@ -19,6 +23,12 @@ def make_video(track_id: str, **data) -> Video:
|
||||
return video
|
||||
|
||||
|
||||
def downloaded(video: Video, tmp_path) -> Video:
|
||||
video.path = tmp_path / "v.ts"
|
||||
video.path.write_bytes(b"\x00" * 16)
|
||||
return video
|
||||
|
||||
|
||||
def mux_until_mkvmerge_check(tracks: Tracks) -> None:
|
||||
# the embedded-audio metadata pass runs before the mkvmerge lookup, so a missing
|
||||
# binary stops the mux right after the state under test has been written
|
||||
@@ -35,7 +45,7 @@ def test_names_undeclared_video(monkeypatch):
|
||||
|
||||
assert video.needs_repack
|
||||
assert video.data["audio_language"] == "zh"
|
||||
assert video.data["audio_language_name"] == "Chinese"
|
||||
assert video.embedded_audio_name() == "Chinese"
|
||||
|
||||
|
||||
def test_service_declaration_is_preserved(monkeypatch):
|
||||
@@ -50,3 +60,36 @@ def test_service_declaration_is_preserved(monkeypatch):
|
||||
assert declared.data["audio_language_name"] == "Thai [Original]"
|
||||
assert not declared.needs_repack
|
||||
assert undeclared.data["audio_language"] == "zh"
|
||||
|
||||
|
||||
def test_embedded_audio_without_a_name_gets_the_language_name(tmp_path, mux_args):
|
||||
args = mux_args(Tracks(downloaded(make_video("v1", audio_language="pt-BR"), tmp_path)), {"video": 0, "audio": 1})
|
||||
assert args[args.index("--track-name") + 1] == "1:Portuguese"
|
||||
|
||||
|
||||
def test_embedded_audio_options_use_the_file_track_ids(tmp_path, mux_args):
|
||||
video = make_video("v1", audio_language="ko", audio_language_name="Korean")
|
||||
args = mux_args(Tracks(downloaded(video, tmp_path)), {"audio": 0, "video": 1})
|
||||
assert args[args.index("--track-name") + 1] == "0:Korean"
|
||||
original = f"{video.is_original_lang}"
|
||||
assert [args[i + 1] for i, arg in enumerate(args) if arg == "--original-flag"] == [f"1:{original}", f"0:{original}"]
|
||||
assert "0:ko" in args and "1:zh" in args
|
||||
|
||||
|
||||
def test_embedded_audio_options_are_left_out_when_the_file_has_no_audio(tmp_path, mux_args):
|
||||
args = mux_args(Tracks(downloaded(make_video("v1", audio_language="ko"), tmp_path)), {"video": 0})
|
||||
assert "--track-name" not in args
|
||||
|
||||
|
||||
def test_repack_and_mux_share_the_embedded_audio_name():
|
||||
assert make_video("v1", audio_language="zh").embedded_audio_name() == "Chinese"
|
||||
assert make_video("v1", audio_language="zh", audio_language_name="Mandarin").embedded_audio_name() == "Mandarin"
|
||||
|
||||
|
||||
def test_file_track_ids_reads_the_first_id_of_each_type(monkeypatch, tmp_path):
|
||||
tracks = [{"id": 0, "type": "audio"}, {"id": 1, "type": "video"}, {"id": 2, "type": "audio"}]
|
||||
reply = SimpleNamespace(stdout=json.dumps({"tracks": tracks}))
|
||||
monkeypatch.setattr("unshackle.core.tracks.tracks.subprocess.run", lambda *a, **k: reply)
|
||||
assert file_track_ids(tmp_path / "v.ts") == {"audio": 0, "video": 1}
|
||||
monkeypatch.setattr("unshackle.core.tracks.tracks.subprocess.run", lambda *a, **k: SimpleNamespace(stdout=""))
|
||||
assert file_track_ids(tmp_path / "v.ts") == {"video": 0, "audio": 1}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Callable, Optional
|
||||
|
||||
import pytest
|
||||
from langcodes import Language
|
||||
|
||||
from unshackle.core import binaries
|
||||
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
|
||||
@@ -130,18 +129,7 @@ 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, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
class Stop(Exception):
|
||||
pass
|
||||
|
||||
captured: list[list[str]] = []
|
||||
|
||||
def fake_popen(args: list[str], **kwargs: object) -> None:
|
||||
captured.append(args)
|
||||
raise Stop
|
||||
|
||||
monkeypatch.setattr("unshackle.core.tracks.tracks.subprocess.Popen", fake_popen)
|
||||
monkeypatch.setattr(binaries, "MKVToolNix", Path("mkvmerge"))
|
||||
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")
|
||||
@@ -149,12 +137,11 @@ def test_mkvmerge_gets_the_subtitle_script_and_name(tmp_path: Path, monkeypatch:
|
||||
track.path = tmp_path / file
|
||||
track.path.write_bytes(b"\x00" * 16)
|
||||
|
||||
with pytest.raises(Stop):
|
||||
Tracks([video, audio, subtitle]).mux("T", delete=False, output_path=tmp_path / "o.mkv")
|
||||
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 = captured[0][: captured[0].index(str(tmp_path / file))]
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user