Update data file date handling

This commit is contained in:
hbrain 2026-05-24 22:35:40 +00:00
parent 630c7a0f74
commit 57aa88854b
2 changed files with 31 additions and 10 deletions

View file

@ -82,15 +82,21 @@ Simplest format:
```text ```text
Paris Trip Paris Trip
May 2024
Paris, France Paris, France
May 2024
``` ```
Those three lines mean: Those three lines mean:
1. title 1. title
2. date 2. location
3. place 3. date
If the date line is omitted, movmaker uses the date from the first picture/video and displays it like:
```text
May 14th 2026
```
Key/value format also works: Key/value format also works:
@ -100,7 +106,7 @@ date: May 2024
place: Paris, France place: Paris, France
``` ```
Optional per-file captions may be supported, but they are not required: Optional per-file captions are supported:
```text ```text
IMG_001.jpg: Eiffel Tower IMG_001.jpg: Eiffel Tower

View file

@ -223,6 +223,18 @@ def slugify(value: str) -> str:
return value or "movie" return value or "movie"
def ordinal_day(day: int) -> str:
if 10 <= day % 100 <= 20:
suffix = "th"
else:
suffix = {1: "st", 2: "nd", 3: "rd"}.get(day % 10, "th")
return f"{day}{suffix}"
def display_date(dt: datetime) -> str:
return f"{dt.strftime('%B')} {ordinal_day(dt.day)} {dt.year}"
def default_output_path(first_media: Path, data: MovieData, out_dir: Path) -> Path: def default_output_path(first_media: Path, data: MovieData, out_dir: Path) -> Path:
date = media_date(first_media).strftime("%Y%m%d") date = media_date(first_media).strftime("%Y%m%d")
title = slugify(data.title or first_media.parent.name or "movie") title = slugify(data.title or first_media.parent.name or "movie")
@ -292,13 +304,13 @@ def parse_data_file(path: Path | None) -> MovieData:
else: else:
plain.append(line) plain.append(line)
# Simple mode: first three non-key lines are title/date/place. # Simple mode: first three non-key lines are title/location/date.
if plain: if plain:
data.title = data.title or plain[0] data.title = data.title or plain[0]
if len(plain) > 1: if len(plain) > 1:
data.date = data.date or plain[1] data.place = data.place or plain[1]
if len(plain) > 2: if len(plain) > 2:
data.place = data.place or plain[2] data.date = data.date or plain[2]
return data return data
@ -400,6 +412,7 @@ def build_video(
title_label = "titled" title_label = "titled"
title_font = str(Path.home() / ".local/share/fonts/google/BebasNeue-Regular.ttf") title_font = str(Path.home() / ".local/share/fonts/google/BebasNeue-Regular.ttf")
stamp_font = str(Path.home() / ".local/share/fonts/google/Inter%5Bopsz,wght%5D.ttf") stamp_font = str(Path.home() / ".local/share/fonts/google/Inter%5Bopsz,wght%5D.ttf")
stamp_bold_font = str(Path.home() / ".local/share/fonts/google/Inter%5Bopsz,wght%5D.ttf")
if title_lines: if title_lines:
title_font_size = max(60, height // 10) title_font_size = max(60, height // 10)
subtitle_font_size = max(40, height // 18) subtitle_font_size = max(40, height // 18)
@ -438,7 +451,7 @@ def build_video(
filters.append(f"[{current}]copy[{title_label}]") filters.append(f"[{current}]copy[{title_label}]")
caption_label = title_label caption_label = title_label
caption_size = subtitle_font_size if title_lines else max(40, height // 18) caption_size = (subtitle_font_size if title_lines else max(40, height // 18)) + 2
for idx, caption in enumerate(captions): for idx, caption in enumerate(captions):
if not caption: if not caption:
continue continue
@ -463,13 +476,13 @@ def build_video(
) if caption_fade > 0 else "1" ) if caption_fade > 0 else "1"
next_label = f"caption{idx}" next_label = f"caption{idx}"
filters.append( filters.append(
f"[{caption_label}]drawtext=fontfile='{title_font}':text='{drawtext_escape(caption)}':x=(w-text_w)/2:y=h-text_h-62:" f"[{caption_label}]drawtext=fontfile='{stamp_bold_font}':text='{drawtext_escape(caption)}':x=(w-text_w)/2:y=h-text_h-62:"
f"fontsize={caption_size}:fontcolor=white:borderw=1:bordercolor=black:" f"fontsize={caption_size}:fontcolor=white:borderw=1:bordercolor=black:"
f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{next_label}]" f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{next_label}]"
) )
bold_label = f"caption{idx}b" bold_label = f"caption{idx}b"
filters.append( filters.append(
f"[{next_label}]drawtext=fontfile='{title_font}':text='{drawtext_escape(caption)}':x=(w-text_w)/2+1:y=h-text_h-62:" f"[{next_label}]drawtext=fontfile='{stamp_bold_font}':text='{drawtext_escape(caption)}':x=(w-text_w)/2+1:y=h-text_h-62:"
f"fontsize={caption_size}:fontcolor=white:borderw=1:bordercolor=black:" f"fontsize={caption_size}:fontcolor=white:borderw=1:bordercolor=black:"
f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{bold_label}]" f"alpha='{caption_alpha}':enable='between(t,{start:.3f},{end:.3f})'[{bold_label}]"
) )
@ -536,6 +549,8 @@ def main(argv: list[str] | None = None) -> int:
crf = 28 crf = 28
media, audio_files, data = scan_input(args.input, args.image_duration) media, audio_files, data = scan_input(args.input, args.image_duration)
if not data.date:
data.date = display_date(media_date(media[0].path))
fade = min(args.fade, max(0.0, args.image_duration - 0.1)) fade = min(args.fade, max(0.0, args.image_duration - 0.1))
audio_fade = max(0.0, args.audio_fade) audio_fade = max(0.0, args.audio_fade)