Adding pexels downloader and fixes

This commit is contained in:
2026-06-07 11:19:19 +02:00
parent 980bb84dac
commit b9b5a8e77d
12 changed files with 957 additions and 146 deletions
+65 -17
View File
@@ -4,7 +4,7 @@ from pathlib import Path
from .cache import resolve_with_cache
from .errors import ValidationError, ValidationIssue
from .parser import _read_json
from .parser import _read_json, resolve_missing_videos
from .models import (
ProjectConfig,
SlideDefinition,
@@ -38,6 +38,24 @@ def validate_project(
issues: list[ValidationIssue] = []
warnings: list[ValidationIssue] = []
# Collect video IDs actually referenced in the manuscript (for file-existence checks)
_VIDEO_PREFIXES = {
"video:": 6,
"vft:": 4, "vfb:": 4, "vfm:": 4,
"vf2t:": 5, "vf2b:": 5, "vf2m:": 5,
"vst:": 4, "vsb:": 4, "vsm:": 4,
"vftp:": 5, "vfbp:": 5, "vfmp:": 5,
"vf2tp:": 6, "vf2bp:": 6, "vf2mp:": 6,
"vstp:": 5, "vsbp:": 5, "vsmp:": 5,
}
referenced_video_ids: set[str] = set()
for marker in manuscript_markers:
prefix = next((p for p in _VIDEO_PREFIXES if marker.startswith(p)), None)
if prefix is not None:
referenced_video_ids.add(marker[_VIDEO_PREFIXES[prefix]:])
elif marker.startswith("narration:"):
referenced_video_ids.add(marker[10:])
# Check for malformed markers first (these are likely typos)
if malformed_markers:
for line_num, marker_text in malformed_markers:
@@ -62,21 +80,6 @@ def validate_project(
continue
# Validate video trigger markers — both legacy [video:xxx] and
# shorthand [vft:xxx] / [vfb:xxx] / [vst:xxx] / [vsb:xxx].
_VIDEO_PREFIXES = {
"video:": 6,
"vft:": 4,
"vfb:": 4,
"vf2t:": 5,
"vf2b:": 5,
"vst:": 4,
"vsb:": 4,
"vftp:": 5,
"vfbp:": 5,
"vf2tp:": 6,
"vf2bp:": 6,
"vstp:": 5,
"vsbp:": 5,
}
matched_prefix = next(
(p for p in _VIDEO_PREFIXES if marker.startswith(p)), None
)
@@ -94,6 +97,16 @@ def validate_project(
project_path / "manuscript.txt",
)
)
else:
vs = videos[video_id]
if not vs.cutout or vs.cutout not in config.cutouts:
warnings.append(
ValidationIssue(
f"[{marker}] video '{video_id}' has no valid cutout in videos.json — "
f"run 'gnommo import' to project values, or set cutout manually.",
project_path / "manuscript.txt",
)
)
continue
# Validate narration trigger markers (narration:xxx) - continuous videos
@@ -106,6 +119,16 @@ def validate_project(
project_path / "manuscript.txt",
)
)
else:
vs = videos[video_id]
if not vs.cutout or vs.cutout not in config.cutouts:
warnings.append(
ValidationIssue(
f"[{marker}] video '{video_id}' has no valid cutout in videos.json — "
f"run 'gnommo import' to project values, or set cutout manually.",
project_path / "manuscript.txt",
)
)
continue
# Segment markers are structural annotations, not slide references
@@ -168,6 +191,10 @@ def validate_project(
shared_assets_dir = project_path.parent / "shared_assets"
for video_id, video_source in videos.items():
# Only check files for videos actually used in this manuscript
if video_id not in referenced_video_ids:
continue
# Determine base directory based on is_shared flag
if video_source.is_shared:
if shared_assets_dir:
@@ -186,9 +213,15 @@ def validate_project(
video_path = base_dir / video_source.source_file
video_path, _ = resolve_with_cache(video_path, project_path)
if not video_path.exists():
sf = video_source.source_file
hint = (
" — run 'gnommo pexels' to download"
if sf.startswith("pexels/")
else " — falling back to PlaceholderVideo"
)
warnings.append(
ValidationIssue(
f"Video file not found: {video_source.source_file} — falling back to PlaceholderVideo",
f"Video file not found: {sf}{hint}",
videos_json_path,
)
)
@@ -229,6 +262,7 @@ def validate_project(
)
else:
bg_path = shared_assets_dir / bg_videos[bg_handle]["source_file"]
bg_path, _ = resolve_with_cache(bg_path, project_path)
if not bg_path.exists():
issues.append(
ValidationIssue(
@@ -272,6 +306,20 @@ def validate_project(
)
)
# Check outro videos exist in videos.json or shared_assets
if config.outro:
missing_outro = [vid_id for vid_id in config.outro if vid_id not in videos]
if missing_outro:
found = resolve_missing_videos(missing_outro, project_path, config)
still_missing = [vid_id for vid_id in missing_outro if vid_id not in found]
for vid_id in still_missing:
warnings.append(
ValidationIssue(
f"Outro video '{vid_id}' not found in videos.json or shared_assets — will be skipped at render",
project_path / "project.json",
)
)
# If any issues, raise ValidationError
if issues:
raise ValidationError(issues)