Changeset 0677bac in Klonkt
- Timestamp:
- 08/09/2026 08:24:16 AM (4 weeks ago)
- Branches:
- main
- Children:
- d60c498
- Parents:
- a5d14c7
- Files:
-
- 4 edited
-
src/services/ActivityPubService.js (modified) (2 diffs)
-
src/services/ap-core.js (modified) (1 diff)
-
src/services/music/index.js (modified) (3 diffs)
-
test/music-uitgave.test.js (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
ra5d14c7 r0677bac 29 29 import Blocklist from './BlocklistService.js'; 30 30 import * as Guardianship from './guardianship/index.js'; 31 import { PUBLIC, AP_CONTEXT, safeUrl, actorId, noteId, guessMediaType } from './ap-core.js';31 import { PUBLIC, AP_CONTEXT, safeUrl, actorId, noteId, guessMediaType, normalizeTags, tagParts } from './ap-core.js'; 32 32 // Doorgeven wat hier altijd vandaan kwam, zodat elke bestaande aanroep blijft werken. 33 33 export { AP_CONTEXT, actorId, noteId, guessMediaType }; … … 2973 2973 2974 2974 // Normalise a post's tags field (array, JSON-string, or comma-string) to an array. 2975 function normalizeTags(t) { 2976 if (Array.isArray(t)) return t; 2977 if (typeof t === 'string') { 2978 const s = t.trim(); if (!s) return []; 2979 if (s[0] === '[') { try { const a = JSON.parse(s); return Array.isArray(a) ? a : []; } catch { /* fall through */ } } 2980 return s.split(',').map((x) => x.trim()).filter(Boolean); 2981 } 2982 return []; 2983 } 2975 // normalizeTags en tagParts staan sinds shaer-38y in ap-core: music/ heeft ze 2976 // ook nodig en mag hier niet uit importeren. 2984 2977 // A tag → { label, slug }. Multi-word tags become CamelCase (#LiveMusic) for the display 2985 2978 // name (Mastodon hashtags can't contain spaces; CamelCase is the accessibility norm); the 2986 2979 // slug/href stays lowercase ("livemusic"). 2987 function tagParts(raw) {2988 const words = String(raw || '').trim().split(/[\s_]+/).map((w) => w.replace(/[^\p{L}\p{M}\p{N}]/gu, '')).filter(Boolean);2989 if (!words.length) return null;2990 const slug = words.join('').toLowerCase();2991 if (!slug) return null;2992 const label = words.length > 1 ? words.map((w) => w[0].toUpperCase() + w.slice(1)).join('') : words[0];2993 return { label, slug };2994 }2995 2980 // Merge a post's tags field + the #hashtags linked inline in its body into one deduped 2996 2981 // Hashtag tag list (with hrefs to our /tag page). -
src/services/ap-core.js
ra5d14c7 r0677bac 93 93 })[(e || '').toLowerCase()] || 'image/jpeg'; 94 94 } 95 96 /** 97 * Het tagveld van een post als lijst. Het staat in de database als JSON-ARRAY 98 * en niet als kommalijst -- op komma's splitsen levert `#["Doen we Niet"` op, 99 * en dat faalt niet, het liegt. Vandaar een echte parser, met de kommavorm als 100 * terugval voor wat er handmatig is ingevuld. 101 */ 102 export function normalizeTags(t) { 103 if (Array.isArray(t)) return t; 104 if (typeof t === 'string') { 105 const s = t.trim(); if (!s) return []; 106 if (s[0] === '[') { try { const a = JSON.parse(s); return Array.isArray(a) ? a : []; } catch { /* dan toch als kommalijst */ } } 107 return s.split(',').map((x) => x.trim()).filter(Boolean); 108 } 109 return []; 110 } 111 112 /** 113 * Een tag -> { label, slug }. Tags van meerdere woorden worden CamelCase 114 * (#LiveMusic) voor de weergavenaam -- een Mastodon-hashtag mag geen spaties 115 * bevatten en CamelCase is daar de toegankelijkheidsnorm; de slug en de href 116 * blijven kleingeschreven ("livemusic"). 117 */ 118 export function tagParts(raw) { 119 const words = String(raw || '').trim().split(/[\s_]+/).map((w) => w.replace(/[^\p{L}\p{M}\p{N}]/gu, '')).filter(Boolean); 120 if (!words.length) return null; 121 const slug = words.join('').toLowerCase(); 122 if (!slug) return null; 123 const label = words.length > 1 ? words.map((w) => w[0].toUpperCase() + w.slice(1)).join('') : words[0]; 124 return { label, slug }; 125 } -
src/services/music/index.js
ra5d14c7 r0677bac 14 14 15 15 import db from '../../config/database.js'; 16 import { AP_CONTEXT, PUBLIC, actorId, noteId, safeUrl, guessMediaType } from '../ap-core.js';16 import { AP_CONTEXT, PUBLIC, actorId, noteId, safeUrl, guessMediaType, normalizeTags, tagParts } from '../ap-core.js'; 17 17 import { afleidenUitInsluitingen, ingeslotenPlaylists } from '../../assets/js/shared/post-music-type.js'; 18 18 … … 368 368 // samenvatting en content het lijf. Artiest en jaar blijven dus in summary 369 369 // staan -- dat is een samenvatting, en de posttekst is dat niet. 370 const tekst = (post.excerpt || '').trim();370 const tekst = tekstVanPost(post); 371 371 if (tekst) obj.content = tekst; 372 372 … … 388 388 } 389 389 390 /** De tags van een post als AS2 Hashtags. Zelfde vorm als buildHashtagList. */ 390 /** 391 * De tags van een post als AS2 Hashtags -- zelfde vorm als buildHashtagList. 392 * 393 * Met normalizeTags en niet met een eigen split: het veld staat als JSON-array 394 * in de database, en op komma's splitsen leverde live `#["Doen we Niet"` op. 395 * Dat is het soort fout dat niet omvalt maar onzin uitlevert. 396 */ 391 397 function hashtagsVanPost(base, tagsField) { 392 const ruw = Array.isArray(tagsField)393 ? tagsField394 : String(tagsField || '').split(',');395 398 const uit = [], gezien = new Set(); 396 for (const t of ruw) { 397 const label = String(t || '').trim().replace(/^#/, ''); 398 if (!label) continue; 399 const slug = label.toLowerCase().replace(/\s+/g, '-'); 400 if (gezien.has(slug)) continue; 401 gezien.add(slug); 402 uit.push({ type: 'Hashtag', href: `${base}/tag/${encodeURIComponent(slug)}`, name: '#' + label }); 399 for (const t of normalizeTags(tagsField)) { 400 const p = tagParts(t); 401 if (!p || gezien.has(p.slug)) continue; 402 gezien.add(p.slug); 403 uit.push({ type: 'Hashtag', href: `${base}/tag/${encodeURIComponent(p.slug)}`, name: '#' + p.label }); 403 404 } 404 405 return uit; 406 } 407 408 /** 409 * De tekst van een post, als er een is. De excerpt heeft voorrang -- die is 410 * geschreven om samen te vatten. Staat die leeg, dan het lijf zelf: zonder 411 * shortcodes (die zijn de muziek, niet het verhaal erover) en zonder opmaak. 412 * Levert null als er niets overblijft, want een leeg veld is slechter dan geen. 413 */ 414 function tekstVanPost(post) { 415 const excerpt = String(post.excerpt || '').trim(); 416 if (excerpt) return excerpt; 417 const kaal = String(post.content || '') 418 .replace(/\[\[[a-z]+:[^\]]*\]\]/gi, ' ') 419 .replace(/<[^>]+>/g, ' ') 420 .replace(/ /gi, ' ') 421 .replace(/&[a-z#0-9]+;/gi, ' ') 422 .replace(/\s+/g, ' ') 423 .trim(); 424 return kaal || null; 405 425 } 406 426 -
test/music-uitgave.test.js
ra5d14c7 r0677bac 51 51 excerpt: 'Opgenomen op zolder, in een week.', 52 52 cover: '/media/hoes.jpg', 53 tags: ' lofi, zolder',53 tags: '["lofi","zolder tapes"]', 54 54 }); 55 55 … … 74 74 assert.equal(col.image.type, 'Image'); 75 75 assert.equal(col.image.url, `${BASE}/media/hoes.jpg`); 76 assert.deepEqual(col.tag.map((t) => t.name), ['#lofi', '#zolder']); 76 // Het tagveld is JSON in de database, en een tag van twee woorden wordt 77 // CamelCase -- zelfde regel als elders, want het is nu dezelfde parser. 78 assert.deepEqual(col.tag.map((t) => t.name), ['#lofi', '#ZolderTapes']); 79 assert.equal(col.tag[1].href, `${BASE}/tag/zoldertapes`); 77 80 assert.equal(col.url, `${BASE}/drie-nieuwe`); 78 81 assert.equal(col.context, `${BASE}/ap/notes/p-los`); … … 153 156 assert.equal(M.uitgavePost(SITE, 'tweede'), null); 154 157 }); 158 159 test('zonder excerpt leent hij de tekst uit het lijf van de post', () => { 160 // Live bleek de excerpt vaak leeg; dan is `content` weglaten slechter dan de 161 // tekst zelf pakken. Shortcodes gaan eruit -- die zijn de muziek, niet het 162 // verhaal erover. 163 const p = maakPost({ 164 id: 'p-tekst', slug: 'zonder-excerpt', titel: 'Zonder excerpt', 165 content: '<p>Drie schetsen van vorige week.</p>[[track:t-een]]<div> </div>', 166 }); 167 const col = M.buildPostTrackCollection(BASE, site, p); 168 assert.equal(col.content, 'Drie schetsen van vorige week.'); 169 }); 170 171 test('en een post die alleen uit shortcodes bestaat leent geen lege tekst', () => { 172 const p = maakPost({ 173 id: 'p-kaal', slug: 'alleen-muziek', titel: 'Alleen muziek', 174 content: '[[track:t-twee]]<div> </div>', 175 }); 176 const col = M.buildPostTrackCollection(BASE, site, p); 177 assert.equal(col.content, undefined, 'een leeg veld is slechter dan geen veld'); 178 });
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)