Changeset 9f9b45f in Klonkt
- Timestamp:
- 08/14/2026 01:36:52 AM (4 weeks ago)
- Branches:
- main
- Children:
- 861c228
- Parents:
- f894be5
- Files:
-
- 2 edited
-
src/services/MigrationService.js (modified) (3 diffs)
-
test/fep1580-migration.test.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/services/MigrationService.js
rf894be5 r9f9b45f 239 239 240 240 const AFBEELDING = /^image\//i; 241 242 /** 243 * Waar kan de omslag van een bericht zitten? 244 * 245 * Niet alleen in `attachment`. Klonkt onderdrukt de beeldbijlage met opzet 246 * zodra een post een speler of embed heeft (zie noImages in buildNote), en zet 247 * de cover dan in `image` zodat Mastodon zijn spelerkaart toont en een Klonkt 248 * hem alsnog vindt. Dat is precies wat er bij Robin misging: 18 van de 20 249 * berichten op pagina 1 hadden geen enkele bijlage, en toch een cover, en die 250 * viel er stil tussenuit. 251 * 252 * En een Audio-bijlage draagt zijn eigen hoes in `icon`; die telt ook mee. 253 */ 254 function coverKandidaten(o) { 255 const uit = []; 256 const pak = (v) => { 257 if (!v) return; 258 const u = typeof v === 'string' ? v : (v.url && (typeof v.url === 'string' ? v.url : v.url.href)) || v.href; 259 if (u && /^https?:\/\//i.test(String(u))) uit.push(String(u)); 260 }; 261 pak(o.image); 262 pak(o.icon); 263 for (const a of (Array.isArray(o.attachment) ? o.attachment : [])) pak(a && a.icon); 264 return [...new Set(uit)]; 265 } 241 266 242 267 /** … … 521 546 } 522 547 if (!bestaand.cover_image_url && safeFetch && fs && path && mediaRoot) { 523 // De cover alsnog: hij zit als bijlage op de Note. 524 for (const a of (Array.isArray(o.attachment) ? o.attachment : []).slice(0, 20)) { 525 const u = a && (typeof a === 'string' ? a : (a.url && (typeof a.url === 'string' ? a.url : a.url.href))); 526 if (!u || !AFBEELDING.test(String((a && a.mediaType) || ''))) continue; 548 // De omslag alsnog. Uit de beeldbijlage als die er is, anders uit 549 // image/icon: bij een post met een speler staat hij daar. 550 const uit = [ 551 ...(Array.isArray(o.attachment) ? o.attachment : []) 552 .filter((a) => AFBEELDING.test(String((a && a.mediaType) || ''))) 553 .map((a) => (typeof a.url === 'string' ? a.url : (a.url && a.url.href))) 554 .filter(Boolean), 555 ...coverKandidaten(o), 556 ]; 557 for (const u of uit) { 527 558 const doel = bronMediaPad(u, bronOrigin, { mediaRoot, path }); 528 559 const g = await haalBijlage(String(u), { safeFetch, mediaRoot, fs, path, maxBytes, doel }).catch(() => null); 529 if (g) { 530 db.prepare('UPDATE posts SET cover_image_url = ? WHERE id = ?').run(g.url, bestaand.id); 531 rapport.media++; 532 rapport.postsBijgewerkt++; 533 } 560 if (!g) continue; 561 db.prepare('UPDATE posts SET cover_image_url = ? WHERE id = ?').run(g.url, bestaand.id); 562 rapport.media++; 563 rapport.postsBijgewerkt++; 534 564 break; 535 565 } … … 569 599 const r2 = await inhoudMediaBinnen(inhoud, bronOrigin, site, rapport, { safeFetch, mediaRoot, fs, path, maxBytes }); 570 600 inhoud = r2.inhoud; 601 // De omslag zit lang niet altijd in attachment (zie coverKandidaten). 602 if (!binnen.some((b) => AFBEELDING.test(b.type || ''))) { 603 for (const u of coverKandidaten(o)) { 604 const doel = bronMediaPad(u, bronOrigin, { mediaRoot, path }); 605 const g = await haalBijlage(u, { safeFetch, mediaRoot, fs, path, maxBytes, doel }).catch(() => null); 606 if (!g) { rapport.mediaMislukt++; rapport.waarschuwingen.push(`omslag niet opgehaald: ${u}`); continue; } 607 binnen.unshift({ ...g, naam: null, type: g.mediaType }); 608 rapport.media++; 609 try { 610 db.prepare('INSERT INTO media (id, site_id, filename, mime_type, size, storage_path) VALUES (?, ?, ?, ?, ?, ?)') 611 .run(crypto.randomUUID(), site.id, g.filename, g.mediaType, g.size, g.storage_path); 612 } catch { /* administratie */ } 613 break; // een omslag is genoeg 614 } 615 } 571 616 } 572 617 -
test/fep1580-migration.test.js
rf894be5 r9f9b45f 536 536 }); 537 537 538 test('de omslag komt ook mee als hij in `image` zit in plaats van in attachment', async () => { 539 // Robins 9 covers van de 36. Klonkt onderdrukt de beeldbijlage met opzet 540 // zodra een post een speler of embed heeft (noImages in buildNote), en zet 541 // de omslag dan in `image` zodat Mastodon zijn spelerkaart toont. 18 van de 542 // 20 berichten op pagina 1 hadden daardoor geen enkele bijlage, en toch een 543 // cover. Mijn ingest keek alleen naar attachment. 544 const s = site({ aliases: [BRON] }); 545 const OMSLAG = 'https://oud.example/media/post-images/omslag.png'; 546 const HOES = 'https://oud.example/media/audio-covers/hoes.webp'; 547 const kaart = new Map([ 548 [BRON, { id: BRON, type: 'Person', movedTo: IK, outbox: `${BRON}/outbox` }], 549 [`${BRON}/outbox`, { type: 'OrderedCollection', totalItems: 2, first: `${BRON}/outbox?page=1` }], 550 [`${BRON}/outbox?page=1`, { type: 'OrderedCollectionPage', orderedItems: [ 551 // een speler-post: GEEN attachment, omslag in image 552 note(`${BRON}/notes/speler`, { content: '<p>muziek</p>', image: { type: 'Image', url: OMSLAG } }), 553 // een audio-bijlage draagt zijn eigen hoes in icon 554 note(`${BRON}/notes/audio`, { content: '<p>track</p>', attachment: [ 555 { type: 'Audio', mediaType: 'audio/mpeg', url: 'https://oud.example/audio/stream/x.mp3', 556 icon: { type: 'Image', mediaType: 'image/webp', url: HOES } }, 557 ] }), 558 ] }], 559 ]); 560 const opgehaald = []; 561 const r = await stil(() => Mig.ingestFromSource(s, { deps: { 562 getJson: async (_s, url) => kaart.get(url) || null, 563 noteId: (b, id) => `${b}/ap/notes/${id}`, 564 noteVisibility: AP.noteVisibility, 565 mediaRoot: '/nep/media', audioRoot: '/nep/audio', 566 signHeaders: () => ({ Signature: 'nep' }), 567 safeFetch: async (url) => { opgehaald.push(url); return { ok: true, arrayBuffer: async () => Buffer.from('x'), headers: { get: () => 'image/png' } }; }, 568 fs: { mkdirSync() {}, writeFileSync() {}, statSync() { throw new Error('ENOENT'); } }, 569 path, 570 } })); 571 assert.equal(r.posts, 2); 572 assert.ok(opgehaald.includes(OMSLAG), 'de omslag uit `image` hoort opgehaald te worden'); 573 assert.ok(opgehaald.includes(HOES), 'en de hoes uit de icon van een Audio-bijlage ook'); 574 const covers = db.prepare('SELECT cover_image_url c FROM posts WHERE site_id = ?').all('s1').map((x) => x.c); 575 assert.equal(covers.filter(Boolean).length, 2, 'beide berichten krijgen hun omslag'); 576 assert.ok(covers.includes('/media/post-images/omslag.png'), 'op het pad van de bron'); 577 }); 578 538 579 test('een bericht dat je zelf hebt verwijderd komt bij een tweede ronde terug', async () => { 539 580 // Robin: "ik kan handmatig deze keer de posts verwijderen en opnieuw ophalen."
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)