diff --git a/src/ffx/cli.py b/src/ffx/cli.py index 9b380fc..7f4d9ca 100755 --- a/src/ffx/cli.py +++ b/src/ffx/cli.py @@ -958,7 +958,6 @@ def checkUniqueDispositions(context, mediaDescriptor: MediaDescriptor): metavar="DURATION|START,DURATION", is_flag=False, flag_value=DEFAULT_CUT_OPTION_VALUE, - default=None, callback=normalizeCutOption, help=CUT_OPTION_HELP, ) diff --git a/tests/support/ffx_bundle.py b/tests/support/ffx_bundle.py index 1fa5942..543c5ef 100644 --- a/tests/support/ffx_bundle.py +++ b/tests/support/ffx_bundle.py @@ -95,7 +95,25 @@ def write_vtt(path: Path, lines: tuple[str, ...]) -> Path: return path -def create_source_fixture(workdir: Path, filename: str, tracks: list[SourceTrackSpec], duration_seconds: int = 1) -> Path: +def create_source_fixture( + workdir: Path, + filename: str, + tracks: list[SourceTrackSpec], + duration_seconds: int = 1, + *, + video_encoder: str = "libx264", + video_encoder_options: tuple[str, ...] = ( + "-preset", + "ultrafast", + "-crf", + "35", + "-pix_fmt", + "yuv420p", + ), + audio_encoder: str = "aac", + audio_encoder_options: tuple[str, ...] = ("-b:a", "48k"), + subtitle_encoder: str = "webvtt", +) -> Path: output_path = workdir / filename has_video = any(track.track_type == TrackType.VIDEO for track in tracks) @@ -189,21 +207,16 @@ def create_source_fixture(workdir: Path, filename: str, tracks: list[SourceTrack command += map_tokens command += metadata_tokens command += disposition_tokens + if has_video: + command += ["-c:v", video_encoder] + list(video_encoder_options) + + if has_audio: + command += ["-c:a", audio_encoder] + list(audio_encoder_options) + + if subtitle_input_indices: + command += ["-c:s", subtitle_encoder] + command += [ - "-c:v", - "libx264", - "-preset", - "ultrafast", - "-crf", - "35", - "-pix_fmt", - "yuv420p", - "-c:a", - "aac", - "-b:a", - "48k", - "-c:s", - "webvtt", "-t", str(duration_seconds), "-shortest", diff --git a/tests/unit/test_cli_unmux_sequence.py b/tests/unit/test_cli_unmux_sequence.py index b858755..9d53b89 100644 --- a/tests/unit/test_cli_unmux_sequence.py +++ b/tests/unit/test_cli_unmux_sequence.py @@ -18,7 +18,7 @@ from ffx.track_type import TrackType # noqa: E402 class UnmuxSequenceTests(unittest.TestCase): - def test_h265_video_unmux_uses_annex_b_bitstream_filter(self): + def test_h265_video_unmux_uses_annex_b_bitstream_filter_without_forced_format(self): track_descriptor = TrackDescriptor( index=0, sub_index=0, @@ -46,8 +46,6 @@ class UnmuxSequenceTests(unittest.TestCase): "copy", "-bsf:v", "hevc_mp4toannexb", - "-f", - "h265", "episode_0_eng.h265", ], sequence, diff --git a/tests/unit/test_file_properties_asset_probe.py b/tests/unit/test_file_properties_asset_probe.py index 367d26d..83052d4 100644 --- a/tests/unit/test_file_properties_asset_probe.py +++ b/tests/unit/test_file_properties_asset_probe.py @@ -2,6 +2,7 @@ from __future__ import annotations from pathlib import Path import sys +import tempfile import unittest @@ -16,6 +17,7 @@ from ffx.i18n import set_current_language # noqa: E402 from ffx.logging_utils import get_ffx_logger # noqa: E402 from ffx.track_codec import TrackCodec # noqa: E402 from ffx.track_type import TrackType # noqa: E402 +from tests.support.ffx_bundle import SourceTrackSpec, create_source_fixture # noqa: E402 class StaticConfig: @@ -39,25 +41,41 @@ class FilePropertiesAssetProbeTests(unittest.TestCase): } set_current_language("de") - media_path = ( - Path(__file__).resolve().parents[1] - / "assets" - / "Boruto; Naruto Next Generations (2017) - 0069 Super-Chochos Liebestaumel - S01E0069.webm" - ) + with tempfile.TemporaryDirectory() as tmpdir: + media_path = create_source_fixture( + Path(tmpdir), + "fixture.webm", + [ + SourceTrackSpec(TrackType.VIDEO, identity="video-0"), + SourceTrackSpec(TrackType.AUDIO, identity="audio-1", language="eng"), + SourceTrackSpec( + TrackType.SUBTITLE, + identity="subtitle-2", + language="eng", + subtitle_lines=("Lorem ipsum dolor sit amet.",), + ), + ], + duration_seconds=3, + video_encoder="libvpx-vp9", + video_encoder_options=("-b:v", "0", "-crf", "45"), + audio_encoder="libopus", + audio_encoder_options=("-b:a", "48k"), + subtitle_encoder="webvtt", + ) - file_properties = FileProperties(context, str(media_path)) - tracks = file_properties.getMediaDescriptor().getTrackDescriptors() + file_properties = FileProperties(context, str(media_path)) + tracks = file_properties.getMediaDescriptor().getTrackDescriptors() - subtitle_codecs = [ - track.getCodec() - for track in tracks - if track.getType() == TrackType.SUBTITLE - ] + subtitle_codecs = [ + track.getCodec() + for track in tracks + if track.getType() == TrackType.SUBTITLE + ] - self.assertIn(TrackCodec.VP9, [track.getCodec() for track in tracks]) - self.assertIn(TrackCodec.OPUS, [track.getCodec() for track in tracks]) - self.assertTrue(subtitle_codecs) - self.assertTrue(all(codec == TrackCodec.WEBVTT for codec in subtitle_codecs)) + self.assertIn(TrackCodec.VP9, [track.getCodec() for track in tracks]) + self.assertIn(TrackCodec.OPUS, [track.getCodec() for track in tracks]) + self.assertTrue(subtitle_codecs) + self.assertTrue(all(codec == TrackCodec.WEBVTT for codec in subtitle_codecs)) if __name__ == "__main__": diff --git a/tests/unit/test_metadata_editor.py b/tests/unit/test_metadata_editor.py index 7b65a1a..4858d00 100644 --- a/tests/unit/test_metadata_editor.py +++ b/tests/unit/test_metadata_editor.py @@ -15,6 +15,7 @@ if str(SRC_ROOT) not in sys.path: from ffx.logging_utils import get_ffx_logger # noqa: E402 +from ffx.helper import LogLevel # noqa: E402 from ffx.media_descriptor import MediaDescriptor # noqa: E402 from ffx.metadata_editor import ( # noqa: E402 apply_metadata_edits, @@ -33,6 +34,16 @@ class StaticConfig: return {} +class NotificationCollector: + def __init__(self) -> None: + self.messages: list[str] = [] + self.levels: list[LogLevel | None] = [] + + def __call__(self, message: str, level: LogLevel | None = None) -> None: + self.messages.append(message) + self.levels.append(level) + + def make_context(*, dry_run: bool = False) -> dict: return { "logger": get_ffx_logger(), @@ -151,7 +162,7 @@ class MetadataEditorTests(unittest.TestCase): context = make_context(dry_run=True) baseline_descriptor = make_descriptor() draft_descriptor = baseline_descriptor.clone(context=context) - notifications = [] + notifications = NotificationCollector() expected_command = build_metadata_edit_command( build_metadata_edit_context(context), "/tmp/example.mkv", @@ -170,12 +181,13 @@ class MetadataEditorTests(unittest.TestCase): "/tmp/example.mkv", baseline_descriptor, draft_descriptor, - loggingHandler = notifications.append, + loggingHandler = notifications, ) mocked_execute.assert_not_called() mocked_replace.assert_not_called() - self.assertEqual(["ffmpeg dry-run prepared."], notifications) + self.assertEqual(["ffmpeg dry-run prepared."], notifications.messages) + self.assertEqual([None], notifications.levels) self.assertEqual( { "applied": False, @@ -204,7 +216,7 @@ class MetadataEditorTests(unittest.TestCase): context["verbosity"] = 1 baseline_descriptor = make_descriptor() draft_descriptor = baseline_descriptor.clone(context=context) - notifications = [] + notifications = NotificationCollector() with ( patch("ffx.metadata_editor.create_temporary_output_path", return_value="/tmp/.edit.mkv"), @@ -216,11 +228,12 @@ class MetadataEditorTests(unittest.TestCase): "/tmp/example.mkv", baseline_descriptor, draft_descriptor, - loggingHandler = notifications.append, + loggingHandler = notifications, ) - self.assertEqual(1, len(notifications)) - self.assertTrue(notifications[0].startswith("ffmpeg: ffmpeg ")) + self.assertEqual(1, len(notifications.messages)) + self.assertTrue(notifications.messages[0].startswith("ffmpeg: ffmpeg ")) + self.assertEqual([LogLevel.DEBUG], notifications.levels) if __name__ == "__main__":