Skip to content

Commit 9be43ba

Browse files
committed
[cli] Add ability to customize delimiters for CSV output (#423)
1 parent 85d69f7 commit 9be43ba

File tree

7 files changed

+33
-3
lines changed

7 files changed

+33
-3
lines changed

scenedetect.cfg

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@
266266
# Display list of cut points generated from scene boundaries (yes/no).
267267
#display-cuts = yes
268268

269+
# Separator to use between columns in output file. Must be single (escaped)
270+
# ASCII character.
271+
#col-separator = ,
272+
273+
# Separator to use between rows in output file. Must be (escaped) ASCII
274+
# characters.
275+
#row-separator = \n
276+
269277
# Format to use for list of cut points (frames, seconds, timecode).
270278
#cut-format = timecode
271279

scenedetect/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ def main():
4848
logger.info("Stopped.")
4949
if __debug__:
5050
raise
51-
except BaseException as ex:
51+
except Exception as ex:
5252
if __debug__:
5353
raise
5454
else:
55-
logger.critical("Unhandled exception:", exc_info=ex)
55+
logger.critical("ERROR: Unhandled exception:", exc_info=ex)
5656
raise SystemExit(1) from None
5757

5858

scenedetect/_cli/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,14 +1064,17 @@ def list_scenes_command(
10641064
scene_list_name_format = ctx.config.get_value("list-scenes", "filename", filename)
10651065
list_scenes_args = {
10661066
"cut_format": TimecodeFormat[ctx.config.get_value("list-scenes", "cut-format").upper()],
1067+
"col_separator": ctx.config.get_value("list-scenes", "col-separator"),
10671068
"display_scenes": ctx.config.get_value("list-scenes", "display-scenes"),
10681069
"display_cuts": ctx.config.get_value("list-scenes", "display-cuts"),
1070+
"row_separator": ctx.config.get_value("list-scenes", "row-separator"),
10691071
"scene_list_output": not no_output_file,
10701072
"scene_list_name_format": scene_list_name_format,
10711073
"skip_cuts": skip_cuts or ctx.config.get_value("list-scenes", "skip-cuts"),
10721074
"output_dir": scene_list_dir,
10731075
"quiet": quiet or ctx.config.get_value("list-scenes", "quiet") or ctx.quiet_mode,
10741076
}
1077+
# TODO(#423): Need to validate that col_separator is a 1-character string after decoding.
10751078
ctx.add_command(cli_commands.list_scenes, list_scenes_args)
10761079

10771080

scenedetect/_cli/commands.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ def list_scenes(
7676
display_scenes: bool,
7777
display_cuts: bool,
7878
cut_format: str,
79+
col_separator: str,
80+
row_separator: str,
7981
):
8082
"""Handles the `list-scenes` command."""
8183
# Write scene list CSV to if required.
@@ -96,6 +98,8 @@ def list_scenes(
9698
scene_list=scenes,
9799
include_cut_list=not skip_cuts,
98100
cut_list=cuts,
101+
col_separator=col_separator.encode("utf-8").decode("unicode_escape"),
102+
row_separator=row_separator.encode("utf-8").decode("unicode_escape"),
99103
)
100104
# Suppress output if requested.
101105
if quiet:

scenedetect/_cli/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,12 @@ def format(self, timecode: FrameTimecode) -> str:
303303
},
304304
"list-scenes": {
305305
"cut-format": "timecode",
306+
"col-separator": ",",
306307
"display-cuts": True,
307308
"display-scenes": True,
308309
"filename": "$VIDEO_NAME-Scenes.csv",
309310
"output": None,
311+
"row-separator": "\n",
310312
"no-output-file": False,
311313
"quiet": False,
312314
"skip-cuts": False,

scenedetect/scene_manager.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ def write_scene_list(
216216
scene_list: SceneList,
217217
include_cut_list: bool = True,
218218
cut_list: Optional[CutList] = None,
219+
col_separator: str = ",",
220+
row_separator: str = "\n",
219221
) -> None:
220222
"""Writes the given list of scenes to an output file handle in CSV format.
221223
@@ -227,8 +229,13 @@ def write_scene_list(
227229
cut_list: Optional list of FrameTimecode objects denoting the cut list (i.e. the frames
228230
in the video that need to be split to generate individual scenes). If not specified,
229231
the cut list is generated using the start times of each scene following the first one.
232+
delimiter: Delimiter to use between values. Must be single character.
233+
lineterminator: Line terminator to use between rows.
234+
235+
Raises:
236+
TypeError: "delimiter" must be a 1-character string
230237
"""
231-
csv_writer = csv.writer(output_csv_file, lineterminator="\n")
238+
csv_writer = csv.writer(output_csv_file, delimiter=col_separator, lineterminator=row_separator)
232239
# If required, output the cutting list as the first row (i.e. before the header row).
233240
if include_cut_list:
234241
csv_writer.writerow(

website/pages/changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ Releases
44

55
## PySceneDetect 0.6
66

7+
### 0.6.5 (TBD)
8+
9+
- [api] Add `col_separator` and `row_separator` args to `write_scene_list` function in `scenedetect.scene_manager`
10+
- [cli] Add ability to configure CSV separators for rows/columns in config file [#423](https://github.com/Breakthrough/PySceneDetect/issues/423)
11+
12+
713
### 0.6.4 (June 10, 2024)
814

915
#### Release Notes

0 commit comments

Comments
 (0)