diff --git a/.idea/.idea.Abyss/.idea/workspace.xml b/.idea/.idea.Abyss/.idea/workspace.xml
index 339cdcf..bc7eacb 100644
--- a/.idea/.idea.Abyss/.idea/workspace.xml
+++ b/.idea/.idea.Abyss/.idea/workspace.xml
@@ -9,10 +9,7 @@
-
-
-
-
+
@@ -248,7 +245,7 @@
-
+
diff --git a/Abyss/Toolkits/update-video.py b/Abyss/Toolkits/update-video.py
index b112aa6..cf99d18 100644
--- a/Abyss/Toolkits/update-video.py
+++ b/Abyss/Toolkits/update-video.py
@@ -133,7 +133,7 @@ def find_video_in_dir(base_path):
def update_summary(base_path, name_input=None, author_input=None, group_input=None):
"""
Updates the summary.json file for a given path.
- name_input, author_input, group_input are optional, used for the '-a' mode.
+ name_input, author_input, group_input are optional, used for the '-a' and merging modes.
If group_input is provided, the written summary.json will include the "group" key.
If summary.json already contains a "group" and group_input is None, existing group is preserved.
"""
@@ -211,6 +211,56 @@ def find_next_directory(base_path):
next_num += 1
return str(next_num)
+def merge_projects(src_path, dst_path, group_override=None):
+ """
+ Merge (copy) all video projects from src_path into dst_path, resolving ID conflicts by
+ allocating the next available integer directory names in dst_path.
+
+ If group_override is provided, it will be written into each merged project's summary.json
+ (overwriting any existing group value).
+ """
+ src = Path(src_path)
+ dst = Path(dst_path)
+
+ if not src.exists() or not src.is_dir():
+ print(f"Error: Source path not found or is not a directory: {src}")
+ return
+
+ dst.mkdir(parents=True, exist_ok=True)
+
+ merged_count = 0
+ skipped_count = 0
+
+ # Iterate in sorted order for predictability
+ for child in sorted(src.iterdir(), key=lambda p: p.name):
+ if not child.is_dir():
+ continue
+
+ # Heuristic: treat as a project if it contains a video or a summary.json
+ has_video = find_video_in_dir(child) is not None
+ has_summary = (child / 'summary.json').exists()
+ if not has_video and not has_summary:
+ print(f"Skipping '{child.name}': not a project (no video or summary.json).")
+ skipped_count += 1
+ continue
+
+ # Allocate next ID in dst
+ new_dir_name = find_next_directory(dst)
+ dst_project = dst / new_dir_name
+
+ try:
+ shutil.copytree(child, dst_project)
+ print(f"Copied project '{child.name}' -> '{dst_project.name}'")
+
+ # Rebuild/adjust summary in destination project and optionally override group
+ update_summary(dst_project, group_input=group_override)
+
+ merged_count += 1
+ except Exception as e:
+ print(f"Failed to copy '{child}': {e}")
+
+ print(f"Merge complete: {merged_count} projects merged, {skipped_count} skipped.")
+
def main():
if len(sys.argv) < 2:
print("Usage: python script.py [arguments]")
@@ -219,6 +269,7 @@ def main():
print(" -a Add a new video project in a new directory under the specified path.")
print(" Optional flags for -a: -y (accept defaults anywhere), -g (set group in summary.json).")
print(" -c