Changeset 919b82d in Klonkt
- Timestamp:
- 08/14/2026 12:29:06 AM (4 weeks ago)
- Branches:
- main
- Children:
- 19430fa, 2365630
- Parents:
- eb071a7
- Files:
-
- 2 edited
-
src/services/MigrationService.js (modified) (9 diffs)
-
test/fep1580-migration.test.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/services/MigrationService.js
reb071a7 r919b82d 226 226 for (let n = 2; n < 500; n++) if (!bestaat.get(siteId, `${schoon}-${n}`)) return `${schoon}-${n}`; 227 227 return `${schoon}-${crypto.randomBytes(4).toString('hex')}`; 228 } 229 230 /** Het kale id uit een track-URI: .../tracks/t-een -> t-een. */ 231 function ruwId(uri) { 232 try { return decodeURIComponent(String(uri).split('/').filter(Boolean).pop() || ''); } catch { return ''; } 228 233 } 229 234 … … 361 366 362 367 const rapport = { 363 bron: bronActor.id, posts: 0, overgeslagen: 0, media: 0, mediaMislukt: 0,368 bron: bronActor.id, posts: 0, overgeslagen: 0, opnieuw: 0, media: 0, mediaMislukt: 0, 364 369 blocks: 0, tracksBinnen: 0, tracksMislukt: 0, tracksBijgewerkt: 0, overgeslagenTracks: 0, 365 370 playlistsBinnen: 0, playlistsMislukt: 0, waarschuwingen: [], … … 412 417 if (auteur && auteur !== bronActor.id) continue; // alleen wat van HEM was 413 418 gezien++; 414 if (alGemigreerd(site.slug, o.id)) { rapport.overgeslagen++; continue; } 419 // Al binnen? Alleen overslaan als het bericht er OOK nog staat. Heb je 420 // het verwijderd, dan is opnieuw ophalen precies wat je bedoelt, en 421 // een mapping die dat blokkeert is een val: opruimen hielp dan niet, 422 // want de blokkade zat in ap_migration en niet in de posts. 423 const eerderPost = migrationTarget(site.slug, o.id); 424 if (eerderPost) { 425 const postId = String(eerderPost).split('/').pop(); 426 if (db.prepare('SELECT 1 FROM posts WHERE id = ? AND site_id = ?').get(decodeURIComponent(postId), site.id)) { 427 rapport.overgeslagen++; 428 continue; 429 } 430 rapport.opnieuw++; // weg hier, dus opnieuw binnenhalen 431 } 415 432 416 433 // Media eerst, want een post die naar een plaatje wijst dat we niet … … 487 504 // blijven. 488 505 const trackKaart = new Map(); // bron-URI van een nummer -> ons nieuwe id 506 // En het RUWE id zoals het in de posttekst staat. Klonkt schrijft 507 // [[track:<id>]] in de content, en die tekst reist letterlijk mee over AP. 508 // Krijgt het nummer hier een ander id, dan wijst die shorthand nergens meer 509 // heen en zie je de code zelf in je bericht staan. 510 const ruwKaart = new Map(); // ruw bron-id -> ons id 489 511 const streams = [].concat(bronActor.streams || []).filter((u) => typeof u === 'string'); 490 512 const tracksUrl = streams.find((u) => /\/tracks\/?$/.test(u)); … … 511 533 if (rij) { 512 534 trackKaart.set(String(a.id), rij.id); // MOET, anders vinden de playlists hem niet 535 ruwKaart.set(ruwId(a.id), rij.id); 513 536 const duur = rij.duration ? null : duurSeconden(a.duration); 514 537 const artiest = rij.artist ? null : (a.summary || a.artist || null); … … 571 594 recordMigrated(site.slug, { origin: a.id, target: `${me}/ap/tracks/${trackId}`, sourceActor: bronActor.id, isPublic: false }); 572 595 trackKaart.set(String(a.id), trackId); 596 ruwKaart.set(ruwId(a.id), trackId); 573 597 rapport.tracksBinnen++; 574 598 } catch (e) { … … 579 603 } else if (tracksUrl) { 580 604 rapport.waarschuwingen.push('muziekbibliotheek overgeslagen: geen audiomap meegegeven'); 605 } 606 607 // ── De verwijzingen in de tekst bijtrekken ──────────────────── 608 // 609 // Klonkt schrijft [[track:<id>]] in posts.content, en die tekst reist 610 // letterlijk mee. Krijgt het nummer hier een ander id, dan wijst de 611 // shorthand nergens heen en zie je de code zelf in je bericht staan in 612 // plaats van een speler. Precies wat Robin op TikTik zag. 613 // 614 // Pas NA de tracks, want daarvoor is de kaart nog leeg. En alleen waar het 615 // id echt veranderde: een gelijk id hoeft niet aangeraakt. 616 { 617 const paren = [...ruwKaart.entries()].filter(([oud, nieuwId]) => oud && oud !== nieuwId); 618 if (paren.length) { 619 const upd = db.prepare('UPDATE posts SET content = REPLACE(content, ?, ?) WHERE site_id = ? AND content LIKE ?'); 620 let n = 0; 621 for (const [oud, nieuwId] of paren) { 622 const r = upd.run(`[[track:${oud}]]`, `[[track:${nieuwId}]]`, site.id, `%[[track:${oud}]]%`); 623 if (r && r.changes) n += r.changes; 624 } 625 if (n) { rapport.tekstBijgewerkt = n; console.log('[FEP-1580] track-verwijzingen bijgetrokken in', n, 'bericht(en)'); } 626 } 581 627 } 582 628 … … 608 654 // elke tweede ronde een dubbele plaat op. 609 655 const eerderPl = migrationTarget(site.slug, uri); 656 // De hoes van de plaat, net als bij een nummer. 657 let plHoes = null; 658 const plHoesUrl = (plc.icon && (plc.icon.url || plc.icon)) || (plc.image && (plc.image.url || plc.image)) || null; 659 if (plHoesUrl && /^https?:\/\//i.test(String(plHoesUrl)) && safeFetch && fs && path && mediaRoot) { 660 const h = await haalBijlage(String(plHoesUrl), { 661 safeFetch, mediaRoot, fs, path, maxBytes, 662 headers: signHeaders ? signHeaders(site.slug, String(plHoesUrl), '*/*') : null, 663 }).catch(() => null); 664 if (h) { plHoes = h.url; rapport.media++; } 665 else rapport.waarschuwingen.push(`hoes van playlist niet opgehaald: ${plc.name || uri}`); 666 } 610 667 const plId = (() => { 611 668 if (!eerderPl) return crypto.randomUUID(); … … 615 672 })(); 616 673 try { 617 db.prepare(`INSERT INTO playlists (id, site_id, title, artist, year, kind) VALUES (?,?,?,?,?,?) 618 ON CONFLICT(id) DO UPDATE SET title = excluded.title, artist = COALESCE(playlists.artist, excluded.artist)`) 674 db.prepare(`INSERT INTO playlists (id, site_id, title, artist, year, kind, cover_url) VALUES (?,?,?,?,?,?,?) 675 ON CONFLICT(id) DO UPDATE SET 676 title = excluded.title, 677 artist = COALESCE(playlists.artist, excluded.artist), 678 cover_url = COALESCE(playlists.cover_url, excluded.cover_url)`) 619 679 .run(plId, site.id, plc.name || 'zonder titel', plc.artist || null, 620 plc.year || null, plc['shaer:kind'] || null );680 plc.year || null, plc['shaer:kind'] || null, plHoes); 621 681 // De volgorde opnieuw zetten: die IS de plaat, en een halve 622 682 // bijgewerkte volgorde is erger dan een verse. -
test/fep1580-migration.test.js
reb071a7 r919b82d 458 458 }); 459 459 460 test('een bericht dat je zelf hebt verwijderd komt bij een tweede ronde terug', async () => { 461 // Robin: "ik kan handmatig deze keer de posts verwijderen en opnieuw ophalen." 462 // Met de eerste opzet kon dat niet: de mapping in ap_migration zei "al gehad" 463 // en dan werd alles overgeslagen, hoe leeg je site ook was. Dezelfde val als 464 // bij de nummers, en juist deze zou hij als eerste tegenkomen. 465 const s = site({ aliases: [BRON] }); 466 const deps = bronnetje({ items: [note(`${BRON}/notes/1`), note(`${BRON}/notes/2`)] }); 467 468 const r1 = await stil(() => Mig.ingestFromSource(s, { deps })); 469 assert.equal(r1.posts, 2); 470 471 // Eentje weg, de mapping blijft staan. 472 const weg = db.prepare('SELECT id FROM posts LIMIT 1').get().id; 473 db.prepare('DELETE FROM posts WHERE id = ?').run(weg); 474 assert.equal(db.prepare('SELECT COUNT(*) n FROM posts').get().n, 1); 475 476 const r2 = await stil(() => Mig.ingestFromSource(s, { deps })); 477 assert.equal(r2.posts, 1, 'het verwijderde bericht hoort terug te komen'); 478 assert.equal(r2.opnieuw, 1, 'en het verslag zegt dat het opnieuw is opgehaald'); 479 assert.equal(r2.overgeslagen, 1, 'terwijl het bericht dat er nog stond met rust blijft'); 480 assert.equal(db.prepare('SELECT COUNT(*) n FROM posts').get().n, 2, 'geen dubbele'); 481 }); 482 483 test('de [[track:]]-verwijzing in een bericht wordt bijgetrokken', async () => { 484 // Wat Robin op TikTik zag: het bericht toonde de shorthand zelf in plaats van 485 // een speler. Zijn posts kwamen uit de ZIP (die bewaart posts.content 486 // letterlijk, inclusief [[track:<oud id>]]) en zijn nummers uit de PULL (die 487 // gaf ze een nieuw id). De tekst wees dus naar een nummer dat hier niet 488 // bestaat, en dan valt hij terug op de kale code. 489 const s = site({ aliases: [BRON] }); 490 db.prepare(`INSERT INTO posts (id, site_id, author_id, slug, title, content, status, published_at) 491 VALUES ('pz','s1','u1','tiktik','TikTik','<p>[[track:t-oud]]</p>','published','2026-08-13T10:00:00Z')`).run(); 492 493 const kaart = new Map([ 494 [BRON, { id: BRON, type: 'Person', movedTo: IK, outbox: `${BRON}/outbox`, streams: [`${BRON}/tracks`] }], 495 [`${BRON}/outbox`, { type: 'OrderedCollection', orderedItems: [] }], 496 [`${BRON}/tracks`, { 497 type: 'OrderedCollection', 498 orderedItems: [{ 499 id: `${BRON}/tracks/t-oud`, type: 'Audio', name: 'Nummer', 500 url: [{ type: 'Link', href: `${BRON}/audio/x.mp3`, mediaType: 'audio/mpeg' }], 501 }], 502 }], 503 ]); 504 await stil(() => Mig.ingestFromSource(s, { 505 deps: { 506 getJson: async (_slug, url) => kaart.get(url) || null, 507 noteId: (b, id) => `${b}/ap/notes/${id}`, 508 noteVisibility: AP.noteVisibility, 509 audioRoot: '/nep/audio', mediaRoot: '/nep/media', 510 signHeaders: () => ({ Signature: 'nep' }), 511 safeFetch: async () => ({ ok: true, arrayBuffer: async () => Buffer.from('x'), headers: { get: () => 'audio/mpeg' } }), 512 fs: { mkdirSync() {}, writeFileSync() {} }, 513 path, 514 }, 515 })); 516 517 const inhoud = db.prepare("SELECT content FROM posts WHERE id = 'pz'").get().content; 518 const m = /\[\[track:([^\]]+)\]\]/.exec(inhoud); 519 assert.ok(m, 'de shorthand blijft staan, alleen het id verandert'); 520 assert.notEqual(m[1], 't-oud', 'het oude id wijst hier nergens heen'); 521 const bestaat = db.prepare('SELECT 1 FROM audio_tracks WHERE id = ? AND site_id = ?').get(m[1], 's1'); 522 assert.ok(bestaat, 'en het nieuwe id hoort bij een nummer dat er echt is'); 523 }); 524 460 525 test('een niet-publiek bericht komt wel mee maar niet in de publieke tabel', async () => { 461 526 const s = site({ aliases: [BRON] });
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)