Add generate-slides command for Keynote exports
Parses slide directories exported from Keynote and generates slides.json with proper [S1], [S2], etc. mappings. - Extracts slide numbers from filenames like Video1.001.png - Supports png, gif, pdf, jpg formats - Outputs slides.json in the same directory as images - --type flag to set slide layout (default: square) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
"""CLI entry point for GnommoEditor."""
|
"""CLI entry point for GnommoEditor."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -69,6 +71,22 @@ def main() -> int:
|
|||||||
help="Print FFmpeg command without executing",
|
help="Print FFmpeg command without executing",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# generate-slides command
|
||||||
|
gen_slides_parser = subparsers.add_parser(
|
||||||
|
"generate-slides",
|
||||||
|
help="Generate slides.json from Keynote export folder",
|
||||||
|
)
|
||||||
|
gen_slides_parser.add_argument(
|
||||||
|
"directory",
|
||||||
|
type=Path,
|
||||||
|
help="Path to slides directory (e.g., media/slides/Video1)",
|
||||||
|
)
|
||||||
|
gen_slides_parser.add_argument(
|
||||||
|
"--type",
|
||||||
|
default="square",
|
||||||
|
help="Slide type for all slides (default: square)",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -77,6 +95,8 @@ def main() -> int:
|
|||||||
elif args.command == "render":
|
elif args.command == "render":
|
||||||
output = args.output or (args.project / "out" / "final.mp4")
|
output = args.output or (args.project / "out" / "final.mp4")
|
||||||
return cmd_render(args.project, output, args.verbose, args.dry_run)
|
return cmd_render(args.project, output, args.verbose, args.dry_run)
|
||||||
|
elif args.command == "generate-slides":
|
||||||
|
return cmd_generate_slides(args.directory, args.type)
|
||||||
except GnommoError as e:
|
except GnommoError as e:
|
||||||
print(f"Error: {e}", file=sys.stderr)
|
print(f"Error: {e}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
@@ -154,5 +174,62 @@ def cmd_render(project_path: Path, output_path: Path, verbose: bool, dry_run: bo
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_generate_slides(directory: Path, slide_type: str) -> int:
|
||||||
|
"""Generate slides.json from Keynote export folder."""
|
||||||
|
directory = directory.resolve()
|
||||||
|
|
||||||
|
if not directory.exists():
|
||||||
|
print(f"Error: Directory not found: {directory}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if not directory.is_dir():
|
||||||
|
print(f"Error: Not a directory: {directory}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Find all image files (png, gif, pdf)
|
||||||
|
extensions = {".png", ".gif", ".pdf", ".jpg", ".jpeg"}
|
||||||
|
files = [f for f in directory.iterdir() if f.suffix.lower() in extensions]
|
||||||
|
|
||||||
|
if not files:
|
||||||
|
print(f"Error: No image files found in {directory}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Extract numeric suffix from filenames like "Video1.001.png"
|
||||||
|
# Pattern: anything followed by .NNN. followed by extension
|
||||||
|
pattern = re.compile(r"\.(\d+)\.[^.]+$")
|
||||||
|
|
||||||
|
slides = {}
|
||||||
|
for file in files:
|
||||||
|
match = pattern.search(file.name)
|
||||||
|
if match:
|
||||||
|
num = int(match.group(1)) # "001" -> 1
|
||||||
|
slide_id = f"S{num}"
|
||||||
|
slides[slide_id] = {
|
||||||
|
"image": file.name,
|
||||||
|
"type": slide_type,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
print(f" Warning: Could not parse slide number from: {file.name}")
|
||||||
|
|
||||||
|
if not slides:
|
||||||
|
print("Error: No valid slide files found", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Sort by slide number
|
||||||
|
sorted_slides = dict(sorted(slides.items(), key=lambda x: int(x[0][1:])))
|
||||||
|
|
||||||
|
# Write slides.json in the same directory
|
||||||
|
output_path = directory / "slides.json"
|
||||||
|
with open(output_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(sorted_slides, f, indent=2)
|
||||||
|
|
||||||
|
print(f"Generated {output_path}")
|
||||||
|
print(f" - Found {len(sorted_slides)} slides")
|
||||||
|
for slide_id, slide_def in sorted_slides.items():
|
||||||
|
print(f" [{slide_id}] {slide_def['image']}")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
|||||||
Reference in New Issue
Block a user