From af22aee37b25ba086f886f1caab40e3f0a9862a3 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Thu, 18 Dec 2025 20:54:25 +0000 Subject: [PATCH] ADD save video functionality between markers --- rewind/cli.py | 32 ++++++++++++++++++++++++++------ rewind/core.py | 34 ++++++++++++++++++++++++++++++++-- rewind/daemon.py | 1 - 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/rewind/cli.py b/rewind/cli.py index ab71a46..b791098 100755 --- a/rewind/cli.py +++ b/rewind/cli.py @@ -1,17 +1,34 @@ #!/usr/bin/env python3 import sys import argparse -from rewind.core import clip, mark, print_markers -def build_save_parser(subparsers: argparse._SubParsersAction) -> None: - save_parser = subparsers.add_parser("save", help="Save a section from the current recording") - save_parser.add_argument( +from rewind.core import clip, mark, save, print_markers + +def build_clip_parser(subparsers: argparse._SubParsersAction) -> None: + clip_parser = subparsers.add_parser("clip", help="Clips the last 'x' seconds") + clip_parser.add_argument( "-s", "--seconds", type=int, default=30, help="Number of seconds to include in the clip (default: 30)" ) +def build_save_parser(subparsers: argparse._SubParsersAction) -> None: + save_parser = subparsers.add_parser("save", help="Saves a segment between any two markers") + save_parser.add_argument( + "-s", "--start", + type=str, + required=True, + help="Marker to begin the recording from" + ) + + save_parser.add_argument( + "-e", "--end", + type=str, + required=True, + help="Marker to end the recording from" + ) + def build_mark_parser(subparsers: argparse._SubParsersAction) -> None: mark_parser = subparsers.add_parser("mark", help="Mark the current time in the recording for later reference") mark_parser.add_argument( @@ -32,9 +49,10 @@ def build_parser() -> argparse.ArgumentParser: sub = parser.add_subparsers(dest="command", required=True) - build_save_parser(sub) + build_clip_parser(sub) build_mark_parser(sub) build_list_parser(sub) + build_save_parser(sub) return parser @@ -42,12 +60,14 @@ def main(argv=None) -> int: parser = build_parser() args = parser.parse_args(argv) - if args.command == "save": + if args.command == "clip": clip(args.seconds) elif args.command == "mark": mark(args.name) elif args.command == "list": print_markers() + elif args.command == "save": + save(args.start, args.end) else: parser.error("Unknown command") diff --git a/rewind/core.py b/rewind/core.py index 702bbc4..3324595 100644 --- a/rewind/core.py +++ b/rewind/core.py @@ -44,9 +44,9 @@ def concat_ts_files(file_list: list[str], start_offset: float, end_offset: float cmd = ["ffmpeg", "-y"] if start_offset > 0: cmd += ["-ss", str(start_offset)] - cmd += ["-f", "concat", "-safe", "0", "-i", "file_list.txt", "-c", "copy"] if end_offset > 0: - cmd += ["-t", str(get_duration(file_list[-1]) - end_offset - (start_offset if len(file_list) == 1 else 0))] + cmd += ["-sseof", str(end_offset)] + cmd += ["-f", "concat", "-safe", "0", "-i", "file_list.txt", "-c", "copy"] cmd.append(output_file) subprocess.run(cmd) @@ -64,6 +64,21 @@ def clip(seconds_from_end: float) -> None: print(f"Created clip: {output_file_name}") +def save(first_marker: str, second_marker: str): + output_file_name = f"{first_marker}-{second_marker}-{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}.mp4" + first_timestamp = get_marker_timestamp(first_marker) + second_timestamp = get_marker_timestamp(second_marker) + + files, start_offset, end_offset = get_ts_files( + first_timestamp, + second_timestamp + ) + + print(f"{files} -> {start_offset} -> {end_offset}") + + concat_ts_files(files, start_offset, end_offset, output_file_name) + print(f"Created file: {output_file_name}") + def mark(name: str) -> None: if not name: raise ValueError("Marker name cannot be empty") @@ -85,6 +100,21 @@ def mark(name: str) -> None: json.dump(markers, f, indent=4) print(f"Added marker: {name}") +def get_marker_timestamp(name: str) -> float: + markers_file = os.path.join(os.path.dirname(__file__), "markers.json") + if not os.path.exists(markers_file): + print("No markers found.") + return + + with open(markers_file, "r") as f: + markers = json.load(f) + + for marker in markers: + if marker["name"] == name: + return marker["timestamp"] + + raise ValueError("Marker name does not exist") + def print_markers() -> None: clean_old_markers(load_config()["record"]["max_record_time"]) diff --git a/rewind/daemon.py b/rewind/daemon.py index 1f60e79..3c21256 100755 --- a/rewind/daemon.py +++ b/rewind/daemon.py @@ -6,7 +6,6 @@ import time import obsws_python as obs import subprocess -from rewind.core import get_duration from rewind.paths import load_state, write_state, load_config from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler