Changeset 2a10445 in Klonkt for src/services


Ignore:
Timestamp:
07/30/2026 08:23:47 AM (6 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
094f7d0
Parents:
15f1cb5
Message:

De tegel leest zijn beeld uit de content, de cover-kopie is weg

Robins melding: de video stond dubbel op de postpagina, een keer afspeelbaar
in de content en een keer als cover erboven. Terecht; de cover-promotie van
vanmiddag was de verkeerde helft van de oplossing.

Nu doet de tegel wat de Cirkel-kaart al deed: zijn beeld AFLEIDEN uit de
content. post-tile en post-card pakken de eerste video (met zijn poster) of
de eerste afbeelding uit post.content als er geen echte cover is, en de
grid-tegel speelt de video muted-loopend als zijn eigen thumbnail. Het
post-model blijft single-source: c2sCreatePost zet geen covers meer.

En zelfherstel voor wat er al staat: covers die hun eigen content-media
dupliceren (het korte cover-promotie-venster) worden bij boot leeggemaakt;
idempotent en raakt alleen die gevallen.

Changed files:
src/services/ActivityPubService.js

  • c2sCreatePost zet geen covers meer; media leeft alleen in de content

src/views/partials/post-tile.ejs

  • content-afgeleide fallback: video (met poster) of afbeelding

src/views/partials/post-card.ejs

  • dezelfde fallback in de lijstweergave

src/config/database.js

  • zelfherstel: cover-kopieen van content-media leeggemaakt

test/c2s-compose.test.js

  • covers blijven null; de video federeert precies een keer

remarks: 338 tests groen, server start.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r15f1cb5 r2a10445  
    24102410    return `<p><video controls playsinline preload="metadata"${poster} src="${a.url}"></video></p>`;
    24112411  }).join('');
    2412   // The web tile (Robins aanwijzing, 30-7): a video post's first video
    2413   // becomes the cover video, so the grid plays it muted-looping as its own
    2414   // thumbnail, exactly like an animated cover. Deliberately NO cover image
    2415   // next to it: the tile's image branch would win and freeze the tile. A
    2416   // photo post gets its first image as cover, instead of the (untitled)
    2417   // gradient.
    2418   const coverVid = media.find((a) => a.mediaType.startsWith('video/'));
    2419   const coverImg = media.find((a) => a.mediaType.startsWith('image/'));
    24202412  const postId = crypto.randomUUID();
    24212413  const slug = 'n-' + postId.slice(0, 8);
     
    24282420  const vis = c2sVisibility(object);
    24292421  const fanOnly = (vis === 'friends' || vis === 'direct') ? 1 : 0;
    2430   db.prepare(`INSERT INTO posts (id, site_id, slug, author_id, title, content, excerpt, status, type, language, fan_only, ap_visibility, cover_image_url, cover_video_url, created_at, updated_at, published_at)
    2431               VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
    2432     .run(postId, site.id, slug, user.id, '', html + mediaHtml, '', 'published', 'post', object.language || 'nl', fanOnly, vis,
    2433       coverVid ? null : (coverImg ? coverImg.url : null), coverVid ? coverVid.url : null, now, now, now);
     2422  // Deliberately NO cover (Robins besluit, 30-7): the media lives in the
     2423  // content, and a cover next to it showed the same video twice on the post
     2424  // page. The tiles derive their picture from the content instead.
     2425  db.prepare(`INSERT INTO posts (id, site_id, slug, author_id, title, content, excerpt, status, type, language, fan_only, ap_visibility, created_at, updated_at, published_at)
     2426              VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
     2427    .run(postId, site.id, slug, user.id, '', html + mediaHtml, '', 'published', 'post', object.language || 'nl', fanOnly, vis, now, now, now);
    24342428  if (media.length) { try { db.prepare('UPDATE posts SET c2s_attachments = ? WHERE id = ?').run(JSON.stringify(media), postId); } catch { /* column exists via ensureColumn */ } }
    24352429  try { db.prepare('UPDATE posts SET content_rendered = ? WHERE id = ?').run(bakePostContent(html + mediaHtml), postId); } catch { /* render fallback covers it */ }
     
    24372431  try { db.prepare('INSERT INTO posts_fts(content, title, author, post_id) VALUES (?,?,?,?)').run(HtmlSanitizerService.toPlainText(html), '', user.username || '', postId); } catch { /* FTS non-fatal */ }
    24382432  if (vis !== 'direct') {
    2439     deliverCreate(site, { id: postId, slug, title: '', content: html + mediaHtml, published_at: now, created_at: now, fan_only: fanOnly, ap_visibility: vis, cover_image_url: coverVid ? null : (coverImg ? coverImg.url : null), cover_video_url: coverVid ? coverVid.url : null, c2s_attachments: media.length ? JSON.stringify(media) : null }).catch(() => { /* best-effort */ });
     2433    deliverCreate(site, { id: postId, slug, title: '', content: html + mediaHtml, published_at: now, created_at: now, fan_only: fanOnly, ap_visibility: vis, c2s_attachments: media.length ? JSON.stringify(media) : null }).catch(() => { /* best-effort */ });
    24402434  }
    24412435  return { status: 201, id: postId, url: `${base}/ap/notes/${postId}` };
Note: See TracChangeset for help on using the changeset viewer.