No description
  • TypeScript 64.3%
  • JavaScript 16.6%
  • CSS 9.6%
  • Twig 9.3%
  • Dockerfile 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-01 12:07:37 +00:00
docs Add Immich adapter design 2026-06-08 23:37:01 +00:00
invoice-templates adds timesheet templates 2026-07-01 12:07:37 +00:00
packages Add reusable Immich adapter package 2026-06-08 23:39:37 +00:00
server Show Immich face thumbnails for linked people 2026-06-08 00:52:06 +00:00
src Store composer recipient as a person 2026-06-08 03:18:46 +00:00
.dockerignore Initial dappyBirthday app 2026-05-15 09:37:52 +00:00
.gitignore Initial dappyBirthday app 2026-05-15 09:37:52 +00:00
20260611-kimai-export(1).csv add timesheets 2026-06-29 13:54:13 +00:00
compose.yaml Initial dappyBirthday app 2026-05-15 09:37:52 +00:00
Dockerfile Add reusable person selector package 2026-06-08 02:05:17 +00:00
index.html Initial dappyBirthday app 2026-05-15 09:37:52 +00:00
package-lock.json Add reusable Immich adapter package 2026-06-08 23:39:37 +00:00
package.json Add reusable Immich adapter package 2026-06-08 23:39:37 +00:00
README.md Add reusable Immich adapter package 2026-06-08 23:39:37 +00:00
tsconfig.app.json Initial dappyBirthday app 2026-05-15 09:37:52 +00:00
tsconfig.json Initial dappyBirthday app 2026-05-15 09:37:52 +00:00
tsconfig.node.json Initial dappyBirthday app 2026-05-15 09:37:52 +00:00
vite.config.ts Initial dappyBirthday app 2026-05-15 09:37:52 +00:00

dappyBirthday

A small web app and local server for building custom happy birthday videos from family song clips.

What it does

  • Keeps uploaded source videos on the server and indexes reusable song-line ranges in a local SQLite database.
  • Converts selected source videos into very small 480px trim proxies, so large phone videos are easier to trim in the browser.
  • Saves tiny fixed-format preview snippets for each song-line range and stitches them into cached temporary composer preview videos.
  • Extracts selected song-line ranges on demand at a reasonable 1280px maximum long edge for final export.
  • Sends every new source video through a dedicated Upload Video page before opening the editor to mark start/end points, preview marked sections, and save the line metadata against that source video.
  • Imports birthday videos directly from an Immich album through a dedicated Immich page, with server-side API-key storage, thumbnail previews, playback, imported Immich metadata, Imported status, and DO NOT IMPORT markers.
  • Opens source-video trimming and saved-clip editing in the main Clips workspace instead of a side inspect drawer.
  • Stores one common metadata and singer set for all lines marked from the same source video.
  • Stores per-line tags, such as funny, extra info, or stuff up, so characterful takes are visible while composing.
  • Shows synchronized full-width timelines with a shared playhead, colored song-line highlights, and per-line start/end handles.
  • Tags clips by language, song line, structured singer objects, and per-section metadata.
  • Saves metadata on individual clip sections: occasion, recorded date, location, tags, and notes.
  • Supports English, French, and Bislama birthday-song clip libraries.
  • Uses numbered song-line ranges: Happy birthday to you (1), Happy birthday to you (2), Happy birthday, Dear <name>, Happy birthday to you (3), and Hip hip hooray (n).
  • Supports one Dear <name> line and repeated Hip hip hooray takes, numbered 1, 2, 3, 4, and so on.
  • Randomly generates a full birthday song sequence from the selected language or lets you pick each part manually.
  • Plays an in-browser preview.
  • Exports a stitched .webm video at landscape or portrait resolutions.
  • Saves reusable video configurations in local history.

Run with Docker

docker compose up --build

The app is served at:

  • Web app and API: http://localhost:3001
  • Coder workspace URL: https://3001--dev--food-safety-training--leighvandermerwe.coder.codex.fortescue.com/

Video and line metadata is stored in the Docker volume dappybirthday-data:

  • SQLite database: /data/snippets.sqlite
  • Source videos: /data/source-videos/originals/
  • Browser trim proxies: /data/source-videos/proxies/
  • Immich connection settings and per-asset import state: /data/snippets.sqlite
  • Tiny composer preview snippets: /data/preview-snippets/
  • Cached stitched composer previews: /data/tmp/previews/
  • Temporary extracted preview/export segments: /data/tmp/
  • Legacy saved snippet files, if any: /data/snippets/

Local development

npm install
npm run dev:all

This starts:

  • API server: http://localhost:3001
  • Web app: http://localhost:5174 or the next available Vite port

Video and line metadata is stored locally under data/:

  • SQLite database: data/snippets.sqlite
  • Source videos: data/source-videos/originals/
  • Browser trim proxies: data/source-videos/proxies/
  • Immich connection settings and per-asset import state: data/snippets.sqlite
  • Tiny composer preview snippets: data/preview-snippets/
  • Cached stitched composer previews: data/tmp/previews/
  • Temporary extracted preview/export segments: data/tmp/
  • Legacy saved snippet files, if any: data/snippets/

The app uploads source videos only to the local server you run for this project. Song-line clips are saved as source-video time ranges, then extracted and stitched when you preview or export a birthday video.

Design documents

Shared packages

  • packages/person-selector is the reusable React person selector package used by dappyBirthday.
  • It is wired as the workspace package @dappybirthday/person-selector.
  • dappyBirthday adapts its local Singer objects into the package Person type in src/App.tsx, while the package stays independent from Immich, CardDAV, and app storage APIs.
  • packages/immich-adapter is the reusable Immich API adapter package for people, albums, assets, media fetches, and search.
  • It is wired as the workspace package @dappybirthday/immich-adapter.