Skip to content

v1.2.0

Choose a tag to compare

@chr1shaefn3r chr1shaefn3r released this 11 Aug 20:11
· 3 commits to main since this release
97dd4f3

The timelapse can now caption itself: the capture date and the subject's age, drawn from the birth date Immich already stores.

Why

A face timelapse spans years. Without a caption a viewer cannot tell whether two frames are a week apart or a decade — and the faces themselves are the one thing you cannot date by eye, because that is the whole point of the video.

Immich already knows the answer. It stores a person's birth date when you supply one, and shows their age in the web UI. This release puts it on the frames.

The footer

Opt-in. Capture date bottom left, age bottom right.

[encode.annotate]
enabled = true
age = "year_months"         # days | months | year_months | off
language = "de"             # en | de | fr | es | it
date_format = "DD.MM.YYYY"
27.08.2023                                          3 Jahre, 5 Monate

Both videos are written when it is on — the plain timelapse.mp4 and timelapse-annotated.mp4. A date format you end up disliking should never cost you the clean render.

Readable by construction, not by luck. A translucent band darkens the bottom strip and the text carries an outline, so white snow and a night shot both work. Nothing above the band is touched.

Details that are deliberate

  • year_months reads the way a person speaks. 3 years, 5 months, dropping a zero part — and under one month old it falls back to days, because 0 months is wrong on exactly the frames where a baby changes fastest.
  • Month arithmetic uses a day-of-month correction. Someone born on the 31st is not a month old on the 28th of February; the obvious implementation says they are.
  • Translations are built in, not taken from the system locale. That module depends on which locales a machine has generated, so the same config would render a different video on a Mac and on a Linux desktop. It also gets French wrong: mois is invariable, so "plural = add an s" produces 3 moiss. Plurals, month names and thousands separators (1,261 / 1.261 / 1 261) all come from a table.
  • Date patterns are tokens, not strftime: YYYY MM DD, plus MMMM and MMM for month names. D MMMM YYYY gives 5 August 2026 or 5 août 2026 depending on language.

Birth dates

Read during index into a new people table and cached, so encode never touches the network. With two accounts configured, whichever one filled the field in wins — they describe the same person.

If age is enabled and Immich has no birth date, the run says so and draws the date alone rather than failing:

  ! encode.annotate.age is set but Immich has no birth date for this person;
    annotating with the date only.

Nothing about an existing setup changes

  • A config.toml with no [encode.annotate] block produces exactly the video it did before — one file, no footer, nothing read.
  • Databases from 1.1.0 upgrade in place. The people table arrives through CREATE TABLE IF NOT EXISTS, so there is no migration to run and none to get wrong.
  • Pillow is imported only to draw, so the age arithmetic and the language tables stay testable in a bare environment.

586 tests, up from 514 — and 572 with 14 skipped where Pillow is absent, which is the shape CI runs.

Notes

This project was written entirely by Claude (Anthropic's AI assistant, running as Claude Code) and supervised by the repository owner. The model has never had access to the Immich instance or its API keys; all verification against real photographs was done by the owner.