Changeset 096f099 in Klonkt for src/services/ArchiveExportService.js
- Timestamp:
- 08/13/2026 06:01:50 PM (4 weeks ago)
- Branches:
- main
- Children:
- e9ec5e4
- Parents:
- 0824351
- File:
-
- 1 edited
-
src/services/ArchiveExportService.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ArchiveExportService.js
r0824351 r096f099 238 238 } 239 239 240 // ── Wie je volgt, als CSV ───────────────────────────────────────── 241 // 242 // Kolomvorm van Mastodon, zodat deze lijst ook DAAR te importeren is en die van 243 // daar hier. Dat is het hele punt van een verhuisformaat: het moet ook werken 244 // als je naar iets anders vertrekt dan waar je vandaan kwam. 245 // 246 // Account address,Show boosts,Notify on new posts,Languages,Featured 247 // 248 // De vijfde kolom is van ons. Mastodon leest de eerste vier en negeert de rest, 249 // dus dit blijft daar gewoon importeerbaar. `Featured` is de kolom voor 250 // `highlighted`: accounts die je op je profiel uitlicht. `Show boosts` is onze 251 // `auto_boost`. `Notify` en `Languages` kent Klonkt niet en blijven leeg; ze 252 // staan er alleen omdat Mastodon de posities telt. 253 const CSV_KOP = 'Account address,Show boosts,Notify on new posts,Languages,Featured'; 254 255 /** Een veld dat een komma, aanhalingsteken of nieuwe regel bevat moet geciteerd. */ 256 function csvVeld(v) { 257 const s = String(v == null ? '' : v); 258 return /[",\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s; 259 } 260 261 /** 262 * De volglijst van een site als CSV, of null als er niets te melden valt. 263 * 264 * Alleen `accepted`: een openstaand verzoek is geen relatie, en het opnieuw 265 * versturen ervan op de nieuwe plek zou een tweede verzoek zijn bij iemand die 266 * de eerste misschien bewust liet liggen. 267 * 268 * Het adres is de handle zonder de leidende @, want zo schrijft Mastodon hem. 269 * Ontbreekt de handle, dan valt hij terug op de actor-URI: die is altijd te 270 * herleiden, ook als de webfinger-naam ooit verloren ging. 271 */ 272 export function followingCsv(slug) { 273 let rijen = []; 274 try { 275 rijen = db.prepare(`SELECT actor_uri, handle, auto_boost, highlighted FROM ap_following 276 WHERE slug = ? AND status = 'accepted' 277 ORDER BY handle IS NULL, handle, actor_uri`).all(slug); 278 } catch { return null; } // oude database zonder de kolom 279 if (!rijen.length) return null; 280 const regels = rijen.map((r) => [ 281 csvVeld((r.handle || r.actor_uri || '').replace(/^@/, '')), 282 r.auto_boost ? 'true' : 'false', 283 'false', 284 '', 285 r.highlighted ? 'true' : 'false', 286 ].join(',')); 287 return `${CSV_KOP}\n${regels.join('\n')}\n`; 288 } 289 290 /** 291 * Lees zo'n CSV terug. Puur, zodat de vorm te toetsen is zonder database. 292 * 293 * Vergeeflijk met opzet: een bestand uit Mastodon heeft vier kolommen en geen 294 * `Featured`, een handgemaakt bestand heeft misschien alleen adressen. Beide 295 * moeten werken, want anders is het geen uitwisselformaat maar een eigen 296 * bestandje dat toevallig op een CSV lijkt. 297 */ 298 export function parseFollowingCsv(text) { 299 const uit = []; 300 const regels = String(text || '').split(/\r?\n/).filter((r) => r.trim()); 301 if (!regels.length) return uit; 302 // Een kopregel herkennen we aan het eerste veld; anders is regel 1 al data. 303 const start = /^\s*"?account address"?\s*,/i.test(regels[0]) || /^\s*"?account address"?\s*$/i.test(regels[0]) ? 1 : 0; 304 for (const regel of regels.slice(start)) { 305 const velden = splitsCsvRegel(regel); 306 const adres = (velden[0] || '').trim().replace(/^@/, ''); 307 if (!adres) continue; 308 uit.push({ 309 address: adres, 310 autoBoost: /^(true|1|yes)$/i.test((velden[1] || '').trim()), 311 highlighted: /^(true|1|yes)$/i.test((velden[4] || '').trim()), 312 }); 313 } 314 return uit; 315 } 316 317 /** Eén CSV-regel, met respect voor geciteerde velden en verdubbelde aanhalingstekens. */ 318 function splitsCsvRegel(regel) { 319 const velden = []; 320 let veld = ''; 321 let inCitaat = false; 322 for (let i = 0; i < regel.length; i++) { 323 const c = regel[i]; 324 if (inCitaat) { 325 if (c === '"') { 326 if (regel[i + 1] === '"') { veld += '"'; i++; } else inCitaat = false; 327 } else veld += c; 328 } else if (c === '"') inCitaat = true; 329 else if (c === ',') { velden.push(veld); veld = ''; } 330 else veld += c; 331 } 332 velden.push(veld); 333 return velden; 334 } 335 240 336 /** 241 337 * Bouw het archief als een lijst bestanden: pad -> inhoud (Buffer). … … 336 432 } 337 433 434 // Wie je volgt. Dit ontbrak, en daarmee was een "verhuizing" halfslachtig: de 435 // Move vertelt je VOLGERS waar je heen ging, maar niets vertelde JOU wie jij 436 // volgde. Die lijst stond alleen in de oude database, en die laat je achter. 437 const volgCsv = followingCsv(slug); 438 if (volgCsv) { bestanden.set('following.csv', Buffer.from(volgCsv, 'utf8')); tellingen.following = volgCsv.trim().split('\n').length - 1; } 439 338 440 const files = {}; 339 441 for (const pad of [...bestanden.keys()].sort()) files[pad] = sha256(bestanden.get(pad));
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)