summaryrefslogtreecommitdiffstats
path: root/scripts
AgeCommit message (Collapse)AuthorFilesLines
4 daysAdd face pool, blacklisting, and action explanations to people adminKen D'Ambrosio1-1/+20
Removed faces now go to an "Unidentified pool" cluster rather than disappearing. Deleting a cluster blacklists all its members so they are skipped by future re-clustering runs. Pool faces can be assigned to a named person or individually blacklisted. A plain-English info box on the detail page explains what each action does and that no photo files are ever modified. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 daysAdd people/face clustering featureKen D'Ambrosio1-0/+223
- scripts/cluster_faces.py: greedy centroid clustering (numpy) with 3 refinement passes; preserves existing UUID/name mappings across re-runs; writes MEDIA_ROOT/people.json atomically. - app.rb: GET /face/* serves cropped+padded face thumbnails (100x100, cached under cache/faces/); GET|POST /admin/people for cluster management; POST /admin/people/recluster runs cluster_faces.py as a background job; POST /admin/people/:uuid saves names+slugs; GET /people public grid of named people; GET /people/:slug photos for one person. - views/admin/people.erb: lists all clusters (named first, then by size), face crop samples, inline name form, re-cluster button with live log. - views/people.erb: public grid of named people. - views/person.erb: photo grid for one person, linking back to album lightbox for each photo. - views/layout.erb: People link in nav (conditional on FACES_ENABLED). - public/css/style.css: styles for people admin list and public tiles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 daysSeparate face detection into standalone daemonKen D'Ambrosio2-74/+177
- Strip all face code from update.rb; add shared log helper writing to /opt/albumen/log/albumen.log with [update] prefix. update.rb now owns only album.json; face_daemon.rb owns faces.json. - New scripts/face_daemon.rb: polls MEDIA_ROOT for unprocessed images, calls faces.py in batches, writes per-directory faces.json sidecars atomically. Graceful SIGTERM/SIGINT shutdown between directories. - New config/face_daemon.service: systemd unit running as albumen user, Restart=on-failure, logs via SyslogIdentifier=albumen-faces. - app.rb: add FACES_ENABLED constant; load_faces() helper reads faces.json; album_files() merges face data into each entry as :faces field. - Update README.md and DESIGN.md to document the new daemon architecture, faces.json schema, and service management commands. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 daysAdd progress counter and faces-pending sentinel bypass to update.rbKen D'Ambrosio1-3/+18
- process_dir() takes idx/total args and prints [N/total] prefix on every Scanning/Skipping line so long runs are easy to monitor via tail -f - faces_pending?() checks album.json for any image with faces: null when faces.enabled is true; if found, the sentinel skip is bypassed so those images get processed even though the directory mtime hasn't changed - This handles the case where face detection is newly enabled on a library that was previously indexed without it — no --force needed on subsequent runs after the initial catch-up Resume after abort: sentinel is only touched after atomic_write_json, so an aborted directory reruns cleanly. Already-completed directories skip normally; partially-detected batches rerun from scratch (safe/idempotent). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 daysSwitch face detection to CNN model with parallel batch processingKen D'Ambrosio2-49/+93
- faces.py: use model="cnn" (more accurate, better at angles/small faces/poor lighting) instead of HOG; model comment explains the trade-off clearly - faces.py: accept multiple image paths; process with ThreadPoolExecutor (dlib releases GIL during C++ inference → genuine thread parallelism); output JSON dict {path: [faces]} for batch calls - update.rb: batch_detect_faces() collects all unprocessed images per directory and calls faces.py once per directory rather than once per image, avoiding repeated model load overhead - update.rb: FACES_WORKERS read from config.yml faces.workers (default 4; set to 20 in this install's config.yml on a 64-core Xeon) - update.rb: process_dir() now takes idx/total and prints [N/total] prefix on every Scanning/Skipping line for progress monitoring To monitor a long run: nohup ruby /opt/albumen/scripts/update.rb > /tmp/faces_update.log 2>&1 & tail -f /tmp/faces_update.log Resume/restart is fully safe: sentinel files are only written after atomic_write_json, so an aborted directory reruns cleanly from scratch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 daysAdd opt-in facial recognition: detection and embedding storageKen D'Ambrosio2-3/+79
- scripts/faces.py: Python helper using face_recognition (dlib/HOG) to detect faces and return 128-D encodings as JSON; called by update.rb - scripts/update.rb: enrich_faces() stores face boxes and encodings in album.json per image (null = not yet processed, [] = processed/none found); skips files already processed; gated on faces.enabled in config.yml - Reads CONFIG_PATH (same env var as app.rb) to check faces.enabled flag - Feature is off by default; enabled in this install via config.yml - README.md, DESIGN.md: document installation, opt-in config, data model, and planned clustering/people-management pipeline People management UI and clustering script are the next milestone. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22Speed up update.rb and fix UI always forcing full rescanKen D'Ambrosio1-5/+31
- update.rb: skip exiftool on images marked exif_absent (set after first failed attempt); prevents repeated slow scans of old photos with no EXIF - update.rb: explicit directory argument now implies force — passing a path always rescans that subtree regardless of sentinel mtime - app.rb: /admin/update no longer hardcodes --force; sentinel-based skipping is used by default, making UI updates finish in seconds instead of minutes - admin/album.erb: add "Force rescan all" checkbox to Run Update button; checked state passes force=1 to the server and restores --force behavior - README.md, DESIGN.md: document sentinel skipping, exif_absent flag, and explicit-directory force behavior Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14Hide transcoded originals from non-admins; mark them visually for adminsKen D'Ambrosio1-4/+9
update.rb records transcoded_to in album.json (even on re-runs where the MP4 already exists) so the marker survives across scans. app.rb filters files with transcoded_to from non-admin views. album.erb renders them greyed-out with an amber "⚠ original" badge in admin mode. admin/album.erb marks the edit-table row and shows the target filename under the original. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14Auto-transcode non-browser-playable videos to MP4 in update.rbKen D'Ambrosio1-4/+39
On each run, any .avi, .mkv, or .mov file without a same-named .mp4 sibling is transcoded with ffmpeg (H.264/AAC, CRF 23, faststart). The original is kept on disk and hidden in album.json so only the playable MP4 appears in the UI; admins can un-hide the original if needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12Add organize_by_day.rb script for GPS-based day/location splittingKen D'Ambrosio1-0/+135
Groups media files in an album directory by EXIF date, reverse-geocodes the first GPS fix of each day via Nominatim, and moves files into "Day N - Location" subdirectories. Dry-run by default; pass --go to execute. Supports a LOCATION_OVERRIDES map for cleaning up Nominatim names that are overly granular. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12Add photo counts, EXIF details, video duration badges, slideshow launcher UIKen D'Ambrosio1-6/+20
- Album cards show recursive photo count (bubbles up through sub-albums). - Lightbox info panel shows camera, aperture, shutter speed, and ISO; update.rb now extracts and stores these EXIF fields. - Video thumbnail cards show a duration badge (e.g. "1:23"). - Slideshow launcher redesigned: button on its own line, with Shuffle / Full screen / Interval options on a second line, all inside a rounded border to make the grouping clear. - Fixed album-actions alignment so Interval sits level with the checkboxes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12Prune orphaned thumbnails when update.rb removes deleted filesKen D'Ambrosio1-4/+10
When a media file is deleted from disk, also delete its cached thumbnail from cache/thumbs/ so stale .th.jpg files don't accumulate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11v1.01: replace bcrypt with PBKDF2-SHA256; update README and DESIGN docsv1.01Ken D'Ambrosio1-3/+7
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11Fix set_password.rb to chown config.yml to albumen user when run as rootKen D'Ambrosio1-0/+9
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09Fix taken_at timezone: store and display as camera local timeKen D'Ambrosio1-1/+1
EXIF DateTimeOriginal has no timezone — it's the camera's wall clock. Storing it via .iso8601 attached +00:00 (server TZ), causing browsers to shift the time to their local zone when parsing. Switch to strftime('%Y-%m-%dT%H:%M:%S') so no offset is written. JS strips any existing +00:00 suffix from already-stored values so old data is also displayed correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09Initial commit — Albumen photo albumKen2-0/+247
Ruby/Sinatra self-hosted photo album with directory hierarchy, per-photo captions and visibility, lightbox, slideshow, admin UI, and Let's Encrypt HTTPS via Apache reverse proxy on prouter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>