feat(gif): migrate GIF picker to Giphy (Tenor API shutdown) [operator-action] (LC-505) #470

Merged
longjacksonle merged 2 commits from feat/LC-505-gif-giphy into main 2026-06-28 03:09:16 +02:00

What

Migrate the GIF picker (LC-488, merged in #469) off the Tenor API, which Google is shutting down (announced 2026-01-13: new API-key sign-ups halted immediately, full shutdown 2026-06-30 - a new operator can no longer get a Tenor key). Re-target to Giphy (Shutterstock-owned, still operational, free keys).

How

Only the provider adapter changes; the architecture (search -> server-side fetch -> uploads pipeline -> same-origin attachment, never hotlinked) is identical.

  • gif::GifConfig::from_env: LETS_CHAT_GIPHY_API_KEY (+ optional LETS_CHAT_GIPHY_RATING g/pg/pg-13/r, default pg-13). Replaces the Tenor key/client-key/content-filter trio.
  • gif::parse_search: Giphy data[].images shape - fixed_height_small for the grid preview, downsized (fallback original) for the posted GIF.
  • gif::is_giphy_media_url: allowlist *.giphy.com (was *.tenor.com).
  • Search route: api.giphy.com/v1/gifs/{trending|search} with api_key/rating/limit/q.
  • Attribution -> "Powered by GIPHY"; CLAUDE.md env row + comments updated.

Tests

gif.rs unit tests rewritten for the Giphy response shape + is_giphy_media_url (incl. look-alike host rejection). just check, just test, just test-saas green. (The outbound HTTP path remains non-mockable in-process, as before.)

Operator note

[operator-action]: set LETS_CHAT_GIPHY_API_KEY instead of the old LETS_CHAT_TENOR_* vars. The Tenor vars are now ignored; the picker stays hidden until a Giphy key is set.

Verify

just verify builds the release binary clean; boot fails only on the missing SSO env (environmental).

## What Migrate the GIF picker (LC-488, merged in #469) off the **Tenor** API, which Google is shutting down (announced 2026-01-13: new API-key sign-ups halted immediately, full shutdown 2026-06-30 - a new operator can no longer get a Tenor key). Re-target to **Giphy** (Shutterstock-owned, still operational, free keys). ## How Only the provider adapter changes; the architecture (search -> server-side fetch -> uploads pipeline -> same-origin attachment, never hotlinked) is identical. - `gif::GifConfig::from_env`: `LETS_CHAT_GIPHY_API_KEY` (+ optional `LETS_CHAT_GIPHY_RATING` g/pg/pg-13/r, default pg-13). Replaces the Tenor key/client-key/content-filter trio. - `gif::parse_search`: Giphy `data[].images` shape - `fixed_height_small` for the grid preview, `downsized` (fallback `original`) for the posted GIF. - `gif::is_giphy_media_url`: allowlist `*.giphy.com` (was `*.tenor.com`). - Search route: `api.giphy.com/v1/gifs/{trending|search}` with `api_key`/`rating`/`limit`/`q`. - Attribution -> "Powered by GIPHY"; CLAUDE.md env row + comments updated. ## Tests `gif.rs` unit tests rewritten for the Giphy response shape + `is_giphy_media_url` (incl. look-alike host rejection). `just check`, `just test`, `just test-saas` green. (The outbound HTTP path remains non-mockable in-process, as before.) ## Operator note `[operator-action]`: set `LETS_CHAT_GIPHY_API_KEY` instead of the old `LETS_CHAT_TENOR_*` vars. The Tenor vars are now ignored; the picker stays hidden until a Giphy key is set. ## Verify `just verify` builds the release binary clean; boot fails only on the missing SSO env (environmental).
Google is shutting down the public Tenor API (new keys halted 2026-01-13, full shutdown 2026-06-30), so the LC-488 picker targeted a dead provider. Re-point the adapter at Giphy: GifConfig now reads LETS_CHAT_GIPHY_API_KEY/_RATING, parse_search handles the Giphy data[].images shape (downsized preferred for the posted GIF), is_giphy_media_url allowlists *.giphy.com, and the search route hits api.giphy.com (/trending when empty, /search otherwise). Architecture (server-side fetch -> uploads pipeline -> same-origin attachment) unchanged. Unit tests updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(gif): Giphy env + GIPHY attribution after Tenor migration [operator-action] (LC-505)
All checks were successful
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 4s
check-secrets / TruffleHog (pull_request) Successful in 4s
check-secrets / Kingfisher (pull_request) Successful in 5s
check-secrets / Kingfisher (push) Successful in 5s
check-secrets / Nosey parker (pull_request) Successful in 6s
Check / clippy + fmt + tests (pull_request) Successful in 4m40s
Create release / Create release from merged PR (pull_request) Has been skipped
59a0db0236
Swap the CLAUDE.md env row to LETS_CHAT_GIPHY_API_KEY/_RATING, the picker attribution to "Powered by GIPHY", and the Tenor mentions in the composer/modal/results comments.

Operator-Action: The GIF picker now uses Giphy, not the (shut-down) Tenor API. Set LETS_CHAT_GIPHY_API_KEY (Giphy) instead of the old LETS_CHAT_TENOR_* vars; optional LETS_CHAT_GIPHY_RATING (g/pg/pg-13/r, default pg-13).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/LC-505-gif-giphy 2026-06-28 03:09:16 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!470
No description provided.