Grill: enclosure promotion and dedupe rules #34

Closed
opened 2026-08-03 15:00:36 +00:00 by TheAnachronism · 1 comment

Part of #30

Question

Which attachments/enclosures should be promoted into inline Reader media, and how do we dedupe them against media already present in the HTML?

Decide at least:

  • Allowlist (e.g. image/*, video/*, URL extension heuristics when MIME is image/generic as in the Reddit example)
  • When promotion yields an inline <img>-like image vs tap-to-play video
  • Dedupe key (URL equality, basename, content-hash — what is good enough?)
  • Whether a promoted enclosure suppresses its attachment chip
  • Explicit non-goals (audio stays chip-only / out of scope)
Part of #30 ## Question Which attachments/enclosures should be **promoted into inline Reader media**, and how do we **dedupe** them against media already present in the HTML? Decide at least: - Allowlist (e.g. `image/*`, `video/*`, URL extension heuristics when MIME is `image/generic` as in the Reddit example) - When promotion yields an inline `<img>`-like image vs tap-to-play video - Dedupe key (URL equality, basename, content-hash — what is good enough?) - Whether a promoted enclosure suppresses its attachment chip - Explicit non-goals (audio stays chip-only / out of scope)
Author
Owner

Resolution

Enclosure promotion + dedupe (runs after image/GIF preference):

  1. Allowlist: image/* and video/* (including image/generic). When MIME is missing or generic, apply URL extension heuristics (e.g. .gif / .jpg / .jpeg / .png / .webp / .mp4 / .webm). Audio and other types stay chip-only (audio remains out of scope for in-app play).
  2. Promoted shape: image-looking enclosures → inline image; video-looking enclosures → tap-to-play video with controls (same UX as HTML <video>).
  3. Order: preference on existing <img>s first (Grill: full-resolution image/GIF preference rules). Enclosures already consumed as an upgrade are not promoted again.
  4. Dedupe: treat as already represented when canonicalized URL matches (strip fragment; ignore common resize query keys such as width, crop, s) or basename matches an existing/preferred <img> / <video> URL. No content-hash.
  5. Chips: suppress the attachment chip when that enclosure was promoted or consumed as a preference upgrade. Remaining attachments keep chips.
  6. Placement: append promoted media after the HTML body, before any remaining attachment chips.

Reddit fixture: preview enclosure shares basename / resize-variant with the (possibly upgraded) inline GIF → no second inline copy, no chip.

## Resolution **Enclosure promotion + dedupe** (runs after image/GIF preference): 1. **Allowlist:** `image/*` and `video/*` (including `image/generic`). When MIME is missing or generic, apply URL extension heuristics (e.g. `.gif` / `.jpg` / `.jpeg` / `.png` / `.webp` / `.mp4` / `.webm`). **Audio and other types stay chip-only** (audio remains out of scope for in-app play). 2. **Promoted shape:** image-looking enclosures → inline image; video-looking enclosures → tap-to-play video with controls (same UX as HTML `<video>`). 3. **Order:** preference on existing `<img>`s first ([Grill: full-resolution image/GIF preference rules](https://git.anachronis.dev/TheAnachronism/tt-rss-viewer/issues/33)). Enclosures already consumed as an upgrade are not promoted again. 4. **Dedupe:** treat as already represented when canonicalized URL matches (strip fragment; ignore common resize query keys such as `width`, `crop`, `s`) **or** basename matches an existing/preferred `<img>` / `<video>` URL. No content-hash. 5. **Chips:** suppress the attachment chip when that enclosure was promoted **or** consumed as a preference upgrade. Remaining attachments keep chips. 6. **Placement:** append promoted media after the HTML body, before any remaining attachment chips. **Reddit fixture:** preview enclosure shares basename / resize-variant with the (possibly upgraded) inline GIF → no second inline copy, no chip.
Sign in to join this conversation.
No description provided.