<feed xmlns='http://www.w3.org/2005/Atom'>
<title>albumen.git/public, branch main</title>
<subtitle>Ruby/Sinatra photo album</subtitle>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/'/>
<entry>
<title>Add per-photo rotate-left/right widget to admin edit page</title>
<updated>2026-06-18T23:00:17+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-18T23:00:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=6f975533f075cc761184b5a7392522264eca6fc1'/>
<id>6f975533f075cc761184b5a7392522264eca6fc1</id>
<content type='text'>
Many older photos (especially pre-EXIF-orientation cameras) are off
by a multiple of 90 degrees with no metadata to auto-correct. Each
image row in the admin file table now has rotate buttons that
physically rotate the file (auto-orienting first to normalize any
existing EXIF tag), swap the stored width/height, and clear the
cached thumbnail so it regenerates from the corrected image.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Many older photos (especially pre-EXIF-orientation cameras) are off
by a multiple of 90 degrees with no metadata to auto-correct. Each
image row in the admin file table now has rotate buttons that
physically rotate the file (auto-orienting first to normalize any
existing EXIF tag), swap the stored width/height, and clear the
cached thumbnail so it regenerates from the corrected image.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Rename global search to "Album Search" and group results by album</title>
<updated>2026-06-18T21:58:04+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-18T21:58:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=c5ec42b2f42e285a95610f1b9b9efba4beef3d7e'/>
<id>c5ec42b2f42e285a95610f1b9b9efba4beef3d7e</id>
<content type='text'>
Photo search was returning every individual matching photo, which
was overkill for what's meant to be a quick way to find an album.
/search now groups matches by album (cover thumbnail + match count)
instead of listing each photo, and is relabeled "Album Search"
throughout the UI.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Photo search was returning every individual matching photo, which
was overkill for what's meant to be a quick way to find an album.
/search now groups matches by album (cover thumbnail + match count)
instead of listing each photo, and is relabeled "Album Search"
throughout the UI.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix transcoded video playback in lightbox and slideshow</title>
<updated>2026-06-18T21:57:44+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-18T21:57:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=462e0081cc9062beb29530e84d15edf2003802db'/>
<id>462e0081cc9062beb29530e84d15edf2003802db</id>
<content type='text'>
The HEVC-to-H.264 transcode kept the original file as a hidden
(non-admin) entry with transcoded_to set, but the lightbox &lt;video&gt;
element and the slideshow always pointed at the original file's URL.
Opening a transcoded video (e.g. via a direct ?photo= link) tried to
play the unsupported original codec instead of the browser-compatible
copy.

- album.erb/album.js: lightbox video now plays the transcoded file
  when present, while the "Download Original" link still serves the
  true original.
- all_media_entries: slideshow skips transcoded originals entirely
  since it has no separate download path.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The HEVC-to-H.264 transcode kept the original file as a hidden
(non-admin) entry with transcoded_to set, but the lightbox &lt;video&gt;
element and the slideshow always pointed at the original file's URL.
Opening a transcoded video (e.g. via a direct ?photo= link) tried to
play the unsupported original codec instead of the browser-compatible
copy.

- album.erb/album.js: lightbox video now plays the transcoded file
  when present, while the "Download Original" link still serves the
  true original.
- all_media_entries: slideshow skips transcoded originals entirely
  since it has no separate download path.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Split album count into separate photo and video counts</title>
<updated>2026-06-16T19:18:45+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-16T19:18:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=7eff38478b64cb67de9599f4239705a3afbb183a'/>
<id>7eff38478b64cb67de9599f4239705a3afbb183a</id>
<content type='text'>
Replace media_count helper with media_counts returning {photos, videos}.
Album overview shows photo count as before, plus a coloured ▶ N badge
only when an album (or its sub-albums) contains videos.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Replace media_count helper with media_counts returning {photos, videos}.
Album overview shows photo count as before, plus a coloured ▶ N badge
only when an album (or its sub-albums) contains videos.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix WhatsApp/OG link previews: https URLs and correct image dimensions</title>
<updated>2026-06-16T18:43:26+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-16T18:43:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=a0803c8e87f375b1f138c7d1650ba21108f1cc62'/>
<id>a0803c8e87f375b1f138c7d1650ba21108f1cc62</id>
<content type='text'>
nginx was sending X-Forwarded-Proto: http (its own scheme) rather than
https (the edge scheme), so og:url and og:image were http:// URLs.
Fixed by hardcoding https in the nginx proxy_set_header since HTTPS is
always terminated at the upstream Apache router.

Added a 1200x630 landscape og-default.png (WhatsApp requires ~1.91:1
ratio) and explicit og:image:width/height meta tags. Also tracks the
nginx site config in the repo.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
nginx was sending X-Forwarded-Proto: http (its own scheme) rather than
https (the edge scheme), so og:url and og:image were http:// URLs.
Fixed by hardcoding https in the nginx proxy_set_header since HTTPS is
always terminated at the upstream Apache router.

Added a 1200x630 landscape og-default.png (WhatsApp requires ~1.91:1
ratio) and explicit og:image:width/height meta tags. Also tracks the
nginx site config in the repo.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix face selection: move checkbox below thumbnail, remove pointer-events hack</title>
<updated>2026-06-12T14:05:57+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-12T14:05:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=997a8e86d90132bc424c55d5be670b45571471ae'/>
<id>997a8e86d90132bc424c55d5be670b45571471ae</id>
<content type='text'>
The overlaid checkbox had pointer-events:none so clicks fell through to
the photo link. Replaced with a real &lt;input type=checkbox&gt; rendered
below each face crop. Checkbox change events drive selection state;
clicking anywhere on the card except the photo link also toggles it.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The overlaid checkbox had pointer-events:none so clicks fell through to
the photo link. Replaced with a real &lt;input type=checkbox&gt; rendered
below each face crop. Checkbox change events drive selection state;
clicking anywhere on the card except the photo link also toggles it.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Move bulk selection to admin cluster detail page (correct page)</title>
<updated>2026-06-12T14:01:48+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-12T14:01:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=cfb814470864785565f33e4bebd2aca7e67c16ae'/>
<id>cfb814470864785565f33e4bebd2aca7e67c16ae</id>
<content type='text'>
The bulk selection panel now lives on /admin/people/:uuid — the face
crop grid page — which is what was actually requested. A sticky left
panel shows the cluster name, the name form, a selection counter, and
bulk action controls. Clicking a face crop toggles selection; clicking
the photo link still opens the album. Bulk actions: move selected faces
to a named person, move to pool, or blacklist. The per-face individual
dropdowns are replaced by the panel. Merge-entire-cluster and
Blacklist-cluster moved to collapsible/button in the panel too.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The bulk selection panel now lives on /admin/people/:uuid — the face
crop grid page — which is what was actually requested. A sticky left
panel shows the cluster name, the name form, a selection counter, and
bulk action controls. Clicking a face crop toggles selection; clicking
the photo link still opens the album. Bulk actions: move selected faces
to a named person, move to pool, or blacklist. The per-face individual
dropdowns are replaced by the panel. Merge-entire-cluster and
Blacklist-cluster moved to collapsible/button in the panel too.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Add bulk photo selection panel to person page (admin)</title>
<updated>2026-06-12T13:57:11+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-12T13:57:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=b9a3ce6942e917c8e5046d652b7742cfe5f960ec'/>
<id>b9a3ce6942e917c8e5046d652b7742cfe5f960ec</id>
<content type='text'>
On /people/:slug, admins see a sticky left panel and selectable photo
tiles. Clicking a tile (or its checkbox overlay) toggles selection;
clicking without modifier still opens the photo in a new tab. The panel
shows the selection count and two actions:

- Reassign to person: moves the selected photos' face entries from the
  current person's cluster to the chosen person.
- Move to album: moves the photo files on disk and updates album.json,
  faces.json, and people.json rel paths accordingly. Album paths are
  offered via a datalist autocomplete.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
On /people/:slug, admins see a sticky left panel and selectable photo
tiles. Clicking a tile (or its checkbox overlay) toggles selection;
clicking without modifier still opens the photo in a new tab. The panel
shows the selection count and two actions:

- Reassign to person: moves the selected photos' face entries from the
  current person's cluster to the chosen person.
- Move to album: moves the photo files on disk and updates album.json,
  faces.json, and people.json rel paths accordingly. Album paths are
  offered via a datalist autocomplete.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix New Person flow: redirect to new cluster, show hero face, detect duplicate names</title>
<updated>2026-06-09T14:09:19+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-09T14:09:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=a942b4e83d8c3c71020fdc6ae93954ddfa2ea338'/>
<id>a942b4e83d8c3c71020fdc6ae93954ddfa2ea338</id>
<content type='text'>
After moving a face to "New Person", the user is now taken directly to
that cluster's detail page. If it's a single unnamed cluster, the face
is shown prominently at the top. Typing an existing name on the name
form triggers a confirm dialog: OK merges into the existing person's
cluster, Cancel saves as a new separate person with the same name.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
After moving a face to "New Person", the user is now taken directly to
that cluster's detail page. If it's a single unnamed cluster, the face
is shown prominently at the top. Typing an existing name on the name
form triggers a confirm dialog: OK merges into the existing person's
cluster, Cancel saves as a new separate person with the same name.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Add face pool, blacklisting, and action explanations to people admin</title>
<updated>2026-06-09T13:09:23+00:00</updated>
<author>
<name>Ken D'Ambrosio</name>
<email>ken@jots.org</email>
</author>
<published>2026-06-09T13:09:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.jots.org/albumen.git/commit/?id=c13a40a970be156a231200c20362636b198d32ec'/>
<id>c13a40a970be156a231200c20362636b198d32ec</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
