Changeset 812fea9 in Klonkt for src/services
- Timestamp:
- 08/06/2026 02:20:19 PM (5 weeks ago)
- Branches:
- main
- Children:
- 7aa3140
- Parents:
- 58cfe5f
- git-author:
- Robin <roboburr@…> (08/06/2026 02:20:09 PM)
- git-committer:
- roboburr <roboburr@…> (08/06/2026 02:20:19 PM)
- Location:
- src/services
- Files:
-
- 2 edited
-
ArchiveExportService.js (modified) (4 diffs)
-
ArchiveImportService.js (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ArchiveExportService.js
r58cfe5f r812fea9 81 81 const uit = []; 82 82 const zie = new Set(); 83 const voegToe = (url, name ) => {83 const voegToe = (url, name, rol, extra = {}) => { 84 84 const u = String(url || '').trim(); 85 85 if (!u || zie.has(u)) return; 86 86 zie.add(u); 87 uit.push({ url: u, name: name || null });87 uit.push({ url: u, name: name || null, rol, ...extra }); 88 88 }; 89 voegToe(post.cover_image_url, post.cover_alt); 90 voegToe(post.cover_video_url, post.cover_alt); 91 for (const m of String(post.content || '').matchAll(/<img[^>]+src=["']([^"']+)["'][^>]*>/gi)) voegToe(m[1]); 89 // De ROL is niet decoratief. Zonder rol staat er in het archief wel een 90 // bestand, maar niet dat het de cover was of bij de speler hoorde -- en dan 91 // komt de post na een herstel zonder cover en zonder speler terug. Gevonden 92 // door bij de oefenherstel ALLE kolommen te vergelijken in plaats van een 93 // handjevol. 94 voegToe(post.cover_image_url, post.cover_alt, 'cover'); 95 voegToe(post.cover_video_url, post.cover_alt, 'coverVideo'); 96 for (const m of String(post.content || '').matchAll(/<img[^>]+src=["']([^"']+)["'][^>]*>/gi)) voegToe(m[1], null, 'inline'); 92 97 try { 93 98 for (const a of JSON.parse(post.c2s_attachments || '[]')) { 94 voegToe(a && a.url, a && a.name );99 voegToe(a && a.url, a && a.name, 'c2s'); 95 100 // Een audio-bijlage draagt een poster (de omslag die de speler toont). Die 96 101 // staat in een eigen veld en zou anders stil wegvallen -- op beta viel dat 97 102 // pas op bij de export van echte data. 98 voegToe(a && a.poster, a && a.name ? `${a.name} (poster)` : null );103 voegToe(a && a.poster, a && a.name ? `${a.name} (poster)` : null, 'poster', { posterFor: a && a.url }); 99 104 } 100 105 } catch { /* kapotte kolom blokkeert de export niet */ } … … 103 108 try { 104 109 const t = db.prepare('SELECT t.title, m.storage_path FROM audio_tracks t LEFT JOIN media m ON m.id = t.media_id WHERE t.id = ?').get(m[1]); 105 if (t && t.storage_path) voegToe(`/media/${path.relative(path.resolve(MEDIA_ROOT), path.resolve(t.storage_path))}`, t.title );110 if (t && t.storage_path) voegToe(`/media/${path.relative(path.resolve(MEDIA_ROOT), path.resolve(t.storage_path))}`, t.title, 'track'); 106 111 } catch { /* geen audio-tabellen: niets te doen */ } 107 112 } … … 251 256 'shaer:originalUrl': /^https?:/i.test(ref.url) ? ref.url : `${origin}${ref.url}`, 252 257 'shaer:sha256': hash, 258 'shaer:role': ref.rol, 259 'shaer:posterFor': ref.posterFor || undefined, 253 260 }); 254 261 } else { … … 261 268 type: as2TypeOf(mime), mediaType: mime, name: ref.name || undefined, 262 269 url: orig, 'shaer:availability': 'missing', 'shaer:originalUrl': orig, 270 'shaer:role': ref.rol, 271 'shaer:posterFor': ref.posterFor || undefined, 263 272 }); 264 273 } -
src/services/ArchiveImportService.js
r58cfe5f r812fea9 28 28 29 29 const sha256 = (buf) => crypto.createHash('sha256').update(buf).digest('hex'); 30 const sqlTijd = (iso) => { const t = Date.parse(iso); return isNaN(t) ? null : new Date(t).toISOString().replace('T', ' ').replace(/\.\d+Z$/, ''); }; 30 // De tijdstempel gaat er ONGEWIJZIGD in. Omzetten naar SQL-notatie kostte de 31 // sub-seconde, en twee posts in dezelfde seconde staan dan in willekeurige 32 // volgorde. Klonkt schrijft zelf ook ISO in deze kolommen. 33 const tijd = (iso) => (iso && !isNaN(Date.parse(iso)) ? String(iso) : null); 31 34 32 35 // ── Inlezen ─────────────────────────────────────────────────────── … … 220 223 (id, site_id, slug, author_id, title, content, excerpt, status, cover_image_url, cover_alt, cover_video_url, 221 224 pinned, type, tags, published_at, created_at, updated_at, noindex, publish_at, fan_only, nsfw, language, 222 content_warning, poll_json, quote_uri, quote_actor, ap_visibility, paid, paid_min_cents, view_count, origin_server)225 content_warning, poll_json, quote_uri, quote_actor, ap_visibility, paid, paid_min_cents, view_count, c2s_attachments, origin_server) 223 226 VALUES (@id, @site_id, @slug, @author_id, @title, @content, @excerpt, @status, @cover_image_url, @cover_alt, @cover_video_url, 224 227 @pinned, @type, @tags, @published_at, @created_at, @updated_at, @noindex, @publish_at, @fan_only, @nsfw, @language, 225 @content_warning, @poll_json, @quote_uri, @quote_actor, @ap_visibility, @paid, @paid_min_cents, @view_count, 'import')`);228 @content_warning, @poll_json, @quote_uri, @quote_actor, @ap_visibility, @paid, @paid_min_cents, @view_count, @c2s_attachments, 'import')`); 226 229 const insReply = db.prepare(`INSERT OR IGNORE INTO ap_interactions 227 230 (kind, post_id, object_uri, actor_uri, actor_name, actor_handle, content, published, parent_uri, created_at) … … 242 245 const o = s.obj; 243 246 const opties = (Array.isArray(o.oneOf) ? o.oneOf : (Array.isArray(o.anyOf) ? o.anyOf : null)); 247 // De rollen uit het archief terug naar de kolommen. Zonder dit staat het 248 // bestand er wel, maar komt de post zonder cover en zonder speler terug -- 249 // en dat zie je pas als je alle kolommen vergelijkt. 250 const bijlagen = Array.isArray(o.attachment) ? o.attachment : []; 251 const padVan = (a) => (a ? padVanOrigineel(a['shaer:originalUrl']) : null); 252 const metRol = (r) => bijlagen.find((a) => a['shaer:role'] === r); 253 const c2s = bijlagen.filter((a) => a['shaer:role'] === 'c2s').map((a) => { 254 const poster = bijlagen.find((x) => x['shaer:role'] === 'poster' && x['shaer:posterFor'] === padVan(a)); 255 return { 256 url: padVan(a), mediaType: a.mediaType, name: a.name || undefined, 257 poster: poster ? padVan(poster) : undefined, 258 }; 259 }).filter((a) => a.url); 244 260 insPost.run({ 245 261 id: s.id, site_id: site.id, slug: o['shaer:slug'] || s.id, author_id: site.owner_id, 246 262 title: o.name || null, content: o.content || '', excerpt: o['shaer:excerpt'] || null, 247 263 status: o['shaer:status'] || 'draft', 248 cover_image_url: null, cover_alt: o['shaer:coverAlt'] || null, cover_video_url: null, 264 cover_image_url: padVan(metRol('cover')), cover_alt: o['shaer:coverAlt'] || null, 265 cover_video_url: padVan(metRol('coverVideo')), 266 c2s_attachments: c2s.length ? JSON.stringify(c2s) : null, 249 267 pinned: o['shaer:pinned'] ? 1 : 0, type: o['shaer:type'] || 'post', 250 268 tags: Array.isArray(o.tag) ? o.tag.filter((t) => t && t.type === 'Hashtag').map((t) => String(t.name).replace(/^#/, '')).join(', ') : null, 251 published_at: sqlTijd(o.published), created_at: sqlTijd(o.published), updated_at: sqlTijd(o.updated || o.published),252 noindex: o['shaer:noindex'] ? 1 : 0, publish_at: sqlTijd(o['shaer:publishAt']),269 published_at: tijd(o.published), created_at: tijd(o.published), updated_at: tijd(o.updated || o.published), 270 noindex: o['shaer:noindex'] ? 1 : 0, publish_at: tijd(o['shaer:publishAt']), 253 271 fan_only: o['shaer:fanOnly'] ? 1 : 0, nsfw: o.sensitive ? 1 : 0, 254 272 language: (o.contentMap && Object.keys(o.contentMap)[0]) || null,
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)