Changeset 919b82d in Klonkt


Ignore:
Timestamp:
08/14/2026 12:29:06 AM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
19430fa, 2365630
Parents:
eb071a7
Message:

De shortcode in een bericht wees nergens meer heen

Robin stuurde een schermafbeelding van TikTik: het bericht toonde
[[track:8df2d8a4-...]] als kale tekst in plaats van een speler. Plus: playlists
hadden nog geen hoes.

WAAROM DIE SHORTHAND BREEKT. Zijn berichten kwamen uit de ZIP, die posts.content
letterlijk bewaart inclusief [[track:<oud id>]]. Zijn nummers kwamen uit de
PULL, en die gaf ze een nieuw id. De tekst wees dus naar een nummer dat hier
niet bestaat, en dan valt de weergave terug op de code zelf. Twee wegen die
allebei werken en samen niet.

Na de tracks worden die verwijzingen nu bijgetrokken, met een kaart van het
RUWE bron-id naar het onze. Alleen waar het id echt veranderde.

Onderweg bleek de outbox de shorthand overigens al gebakken door te geven, als
een link terug naar de oude site. Dus via de pull alleen zag je dit niet, en
via de zip alleen ook niet. Alleen de combinatie.

EN DEZELFDE VAL BIJ POSTS. Robin schreef dat hij de berichten handmatig zou
verwijderen om opnieuw op te halen. Dat had niet gewerkt: de mapping in
ap_migration zei "al gehad" en dan werd alles overgeslagen, hoe leeg de site
ook was. Nu telt de mapping alleen als het bericht er OOK nog staat; is het weg,
dan is opnieuw ophalen precies wat je bedoelt.

Gemeten door de combinatie na te spelen: post via de zip met [[track:t-a]],
daarna ophalen. De inhoud werd [[track:3bc1f5d9-...]] en dat nummer bestaat.

Changed files:
src/services/MigrationService.js

  • ruwId() en ruwKaart: het id zoals het in de posttekst staat
  • na de tracks worden [[track:]]-verwijzingen bijgetrokken
  • een verwijderd bericht wordt opnieuw opgehaald in plaats van overgeslagen
  • de hoes van een playlist wordt opgehaald uit icon/image
  • nieuw rapportveld opnieuw

test/fep1580-migration.test.js

  • de shorthand-herschrijving, en een verwijderd bericht dat terugkomt

remarks: over AP komen posts binnen met een gebakken link naar de OUDE site in
plaats van de shorthand. Dat werkt, maar het verwijst wel naar een domein dat je
gaat opzeggen. Aparte kwestie, nog niet aangepakt. Suite 990 groen; tegenproef
op beide fixes.

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

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/services/MigrationService.js

    reb071a7 r919b82d  
    226226  for (let n = 2; n < 500; n++) if (!bestaat.get(siteId, `${schoon}-${n}`)) return `${schoon}-${n}`;
    227227  return `${schoon}-${crypto.randomBytes(4).toString('hex')}`;
     228}
     229
     230/** Het kale id uit een track-URI: .../tracks/t-een -> t-een. */
     231function ruwId(uri) {
     232  try { return decodeURIComponent(String(uri).split('/').filter(Boolean).pop() || ''); } catch { return ''; }
    228233}
    229234
     
    361366
    362367  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,
    364369    blocks: 0, tracksBinnen: 0, tracksMislukt: 0, tracksBijgewerkt: 0, overgeslagenTracks: 0,
    365370    playlistsBinnen: 0, playlistsMislukt: 0, waarschuwingen: [],
     
    412417        if (auteur && auteur !== bronActor.id) continue;              // alleen wat van HEM was
    413418        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        }
    415432
    416433        // Media eerst, want een post die naar een plaatje wijst dat we niet
     
    487504    // blijven.
    488505    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
    489511    const streams = [].concat(bronActor.streams || []).filter((u) => typeof u === 'string');
    490512    const tracksUrl = streams.find((u) => /\/tracks\/?$/.test(u));
     
    511533          if (rij) {
    512534            trackKaart.set(String(a.id), rij.id);   // MOET, anders vinden de playlists hem niet
     535            ruwKaart.set(ruwId(a.id), rij.id);
    513536            const duur = rij.duration ? null : duurSeconden(a.duration);
    514537            const artiest = rij.artist ? null : (a.summary || a.artist || null);
     
    571594          recordMigrated(site.slug, { origin: a.id, target: `${me}/ap/tracks/${trackId}`, sourceActor: bronActor.id, isPublic: false });
    572595          trackKaart.set(String(a.id), trackId);
     596          ruwKaart.set(ruwId(a.id), trackId);
    573597          rapport.tracksBinnen++;
    574598        } catch (e) {
     
    579603    } else if (tracksUrl) {
    580604      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      }
    581627    }
    582628
     
    608654        // elke tweede ronde een dubbele plaat op.
    609655        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        }
    610667        const plId = (() => {
    611668          if (!eerderPl) return crypto.randomUUID();
     
    615672        })();
    616673        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)`)
    619679            .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);
    621681          // De volgorde opnieuw zetten: die IS de plaat, en een halve
    622682          // bijgewerkte volgorde is erger dan een verse.
  • test/fep1580-migration.test.js

    reb071a7 r919b82d  
    458458});
    459459
     460test('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
     483test('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
    460525test('een niet-publiek bericht komt wel mee maar niet in de publieke tabel', async () => {
    461526  const s = site({ aliases: [BRON] });
Note: See TracChangeset for help on using the changeset viewer.