Changeset f3caf19 in Klonkt


Ignore:
Timestamp:
07/26/2026 09:02:17 AM (6 weeks ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
3654057
Parents:
a677616
Message:

shaer:booster.emojis: custom-emoji in de booster-naam (X boosted)

De 'X boosted'-regel toonde nog letterlijke shortcodes als de booster een
emoji-naam heeft. Klonkt geeft de booster-emoji's nu mee als shaer:booster.emojis.
Nieuwe boosts: direct uit de capture (booster.emojis). Bestaande boosts: de rij
bewaart geen booster-URI, dus self-heal (v13 -> v14) resolvet 'm via webfinger op
de reblog_handle, gescoped op id+slug (een note kan door verschillenden geboost
zijn).

Changed files:
src/config/database.js

  • ap_timeline.reblog_emoji_json kolom

src/services/ActivityPubService.js

  • boost-capture bewaart booster.emojis in reblog_emoji_json
  • self-heal v14: booster-emoji backfillen via webfinger (gated op shortcode-naam)

src/routes/activitypub.js

  • shaer:booster.emojis meegeserveerd

remarks: 180 tests groen.

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

Location:
src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/config/database.js

    ra677616 rf3caf19  
    551551  ensureColumn('ap_timeline', 'quote_json', 'TEXT');         // FEP-044f resolved quoted-post snapshot (author + content), for the embedded quote card
    552552  ensureColumn('ap_timeline', 'author_emoji_json', 'TEXT');  // FEP-9098 custom emojis in the author's display name (shaer:author.emojis)
     553  ensureColumn('ap_timeline', 'reblog_emoji_json', 'TEXT');  // FEP-9098 custom emojis in the booster's display name (shaer:booster.emojis)
    553554  ensureColumn('ap_timeline', 'reblog_name', 'TEXT');        // a followed account boosted this → "X boosted"
    554555  ensureColumn('ap_timeline', 'reblog_handle', 'TEXT');      //   the booster's @handle
  • src/routes/activitypub.js

    ra677616 rf3caf19  
    188188        name: t.reblog_name || undefined, handle: t.reblog_handle || undefined,
    189189        icon: t.reblog_icon || undefined,
     190        // FEP-9098: emojis in the booster's display name (":shortcode:"), if any.
     191        emojis: (() => { try { return t.reblog_emoji_json ? JSON.parse(t.reblog_emoji_json) : undefined; } catch { return undefined; } })(),
    190192      } : undefined,
    191193    },
  • src/services/ActivityPubService.js

    ra677616 rf3caf19  
    16901690            let inserted = false;
    16911691            try { const r = tlStmts().ins.run(bn.id, s.slug, origUri || '', oai.name, oai.handle, oai.icon, oai.url, html, bn.url || null, new Date().toISOString(), media, bn.sensitive ? 1 : 0, bn.summary || null); inserted = r.changes > 0; } catch { /* ignore */ }
    1692             if (inserted) { try { db.prepare('UPDATE ap_timeline SET reblog_name = ?, reblog_handle = ?, reblog_icon = ? WHERE slug = ? AND id = ?').run(booster.name, booster.handle, booster.icon, s.slug, bn.id); } catch { /* ignore */ } }
     1692            if (inserted) { try { db.prepare('UPDATE ap_timeline SET reblog_name = ?, reblog_handle = ?, reblog_icon = ?, reblog_emoji_json = ? WHERE slug = ? AND id = ?').run(booster.name, booster.handle, booster.icon, (booster.emojis && Object.keys(booster.emojis).length) ? JSON.stringify(booster.emojis) : null, s.slug, bn.id); } catch { /* ignore */ } }
    16931693            storeAuthorEmoji(bn.id, s.slug, oai);   // custom-emoji display name for the byline
    16941694          }
     
    27892789// during a flux window, e.g. a fleet-wide update), and drops notes that are gone
    27902790// (404/410). Bump SELFHEAL_VERSION only on a release that warrants a re-sync.
    2791 const SELFHEAL_VERSION = 13; // v13: capture custom-emoji display names (author_emoji_json) onto already-cached posts
     2791const SELFHEAL_VERSION = 14; // v14: capture custom-emoji booster names (reblog_emoji_json) onto already-cached boosts
    27922792async function fetchNoteAP(url) {
    27932793  try {
     
    30093009    if (cur >= SELFHEAL_VERSION) return; // already healed for this version — skip on normal boots
    30103010    let rows = [];
    3011     try { rows = db.prepare('SELECT id, content, media_json, nsfw, cw, url, emoji_json, link_json, quote_json, author_uri, author_name, author_emoji_json FROM ap_timeline ORDER BY rowid DESC LIMIT 200').all(); } catch { /* no table */ }
     3011    try { rows = db.prepare('SELECT id, slug, content, media_json, nsfw, cw, url, emoji_json, link_json, quote_json, author_uri, author_name, author_emoji_json, reblog_name, reblog_handle, reblog_emoji_json FROM ap_timeline ORDER BY rowid DESC LIMIT 200').all(); } catch { /* no table */ }
    30123012    let healed = 0, failed = 0;
    30133013    for (const r of rows) {
     
    30353035          const ai = actorInfo(await fetchActor(r.author_uri), r.author_uri);
    30363036          if (ai.emojis) { try { db.prepare('UPDATE ap_timeline SET author_emoji_json = ? WHERE id = ?').run(JSON.stringify(ai.emojis), r.id); } catch { /* ignore */ } }
     3037        }
     3038        // v14: same for the booster's display name ("X boosted"). The row stores
     3039        // no booster URI, so resolve it from the handle via webfinger. Scoped to
     3040        // this exact row (slug) since a note can be boosted by different people.
     3041        if (/:[A-Za-z0-9_+-]+:/.test(r.reblog_name || '') && !r.reblog_emoji_json && r.reblog_handle) {
     3042          const bUri = await webfingerResolve(r.reblog_handle);
     3043          const em = bUri ? actorNameEmojis(await fetchActor(bUri)) : undefined;
     3044          if (em) { try { db.prepare('UPDATE ap_timeline SET reblog_emoji_json = ? WHERE id = ? AND slug = ?').run(JSON.stringify(em), r.id, r.slug); } catch { /* ignore */ } }
    30373045        }
    30383046      } catch { failed++; /* per-note best-effort */ }
Note: See TracChangeset for help on using the changeset viewer.