diff --git a/scenedetect/output/__init__.py b/scenedetect/output/__init__.py index b0d56b35..097f18de 100644 --- a/scenedetect/output/__init__.py +++ b/scenedetect/output/__init__.py @@ -172,9 +172,10 @@ def write_scene_list( # If required, output the cutting list as the first row (i.e. before the header row). if include_cut_list: csv_writer.writerow( - ["Timecode List:", *cut_list] - if cut_list - else [start.get_timecode() for start, _ in scene_list[1:]] + [ + "Timecode List:", + *(cut_list if cut_list else [start.get_timecode() for start, _ in scene_list[1:]]), + ] ) csv_writer.writerow( [ diff --git a/tests/test_output.py b/tests/test_output.py index d3769eb4..709a4310 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -399,6 +399,16 @@ def test_write_scene_list_rejects_invalid_output_target(): write_scene_list(ty.cast(ty.Any, object()), scenes) +def test_write_scene_list_cut_list_row_without_cut_list(): + """The cut list row is labelled whether the cut list is passed in or derived from the scenes.""" + scenes = _fake_scenes(_FPS_CFR, [(0, 30), (30, 60), (60, 90)]) + derived, explicit = StringIO(), StringIO() + write_scene_list(derived, scenes) + write_scene_list(explicit, scenes, cut_list=[scenes[1][0], scenes[2][0]]) + assert derived.getvalue().splitlines()[0] == "Timecode List:,00:00:01.000,00:00:02.000" + assert derived.getvalue() == explicit.getvalue() + + def test_write_scene_list_edl(tmp_path: Path): """EDL output has title header, FCM line, and one event per scene in CMX 3600 format.""" scenes = _fake_scenes(_FPS_CFR, [(0, 30), (30, 60)]) diff --git a/website/pages/changelog.md b/website/pages/changelog.md index 0a336e81..f674489a 100644 --- a/website/pages/changelog.md +++ b/website/pages/changelog.md @@ -825,4 +825,5 @@ Development - [feature] `VideoStream` has a new `close()` method to release the file handles and decoders a video holds, and can be used as a context manager (`with open_video(path) as video:`) to close it automatically. Calling `close()` more than once has no effect. Once an OpenCV, PyAV, MoviePy or concatenated stream is closed, `read()`, `seek()` and `reset()` raise `ValueError`, while properties describing the video (`path`, `name`, `frame_rate`, `duration`, `frame_size`, `aspect_ratio`) remain available. The default implementation does nothing, so existing `VideoStream` subclasses are unaffected, and `VideoCaptureAdapter` leaves the caller's `VideoCapture` open [#568](https://github.com/Breakthrough/PySceneDetect/issues/568) - [bugfix] `VideoStreamConcat` no longer keeps its input videos open when they can't be concatenated (e.g. mismatched resolutions), and now closes each input explicitly once it is no longer needed instead of relying on garbage collection [#568](https://github.com/Breakthrough/PySceneDetect/issues/568) - [bugfix] `split-video` with `-o` now logs the output folder instead of repeating the filename template [#595](https://github.com/Breakthrough/PySceneDetect/pull/595) + - [bugfix] `write_scene_list()` now starts the cut list row with `Timecode List:` when no `cut_list` is passed, as it does when one is passed and as `write_scene_list_html()` does - [bugfix] Allow `-d`/`--downscale` on the CLI and `downscale` in the config file to be set to `0` for automatic downscaling \ No newline at end of file