Changeset f50a84b in Klonkt
- Timestamp:
- 08/13/2026 01:09:55 PM (4 weeks ago)
- Branches:
- main
- Children:
- c3e736c
- Parents:
- 013e16c
- Files:
-
- 6 edited
-
src/assets/js/mod/admin-seo.js (modified) (1 diff)
-
src/routes/admin-seo.js (modified) (1 diff)
-
src/services/MusicBrainzService.js (modified) (2 diffs)
-
src/services/i18n.js (modified) (3 diffs)
-
src/views/pages/admin-seo.ejs (modified) (1 diff)
-
test/musicbrainz.test.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/assets/js/mod/admin-seo.js
r013e16c rf50a84b 64 64 uit.hidden = true; 65 65 uit.replaceChildren(); 66 checkTerugweg(mbid); 66 67 } 67 68 68 69 const wis = document.getElementById('mb-wis'); 69 70 if (wis) wis.addEventListener('click', () => zet('', '')); 71 72 // DE TERUG-WEG. Wij zetten hem niet -- dat kan niet via hun API en hoort ook 73 // niet -- we kijken alleen of de artiestenpagina ons domein noemt. Zolang dat 74 // niet zo is staat er "nog eenzijdig", want een halve koppeling die als 75 // bevestigd leest is het soort stilte waar we vandaag al genoeg van zagen. 76 const terugweg = document.getElementById('mb-terugweg'); 77 async function checkTerugweg(mbid) { 78 if (!terugweg) return; 79 if (!mbid) { terugweg.hidden = true; terugweg.textContent = ''; return; } 80 terugweg.hidden = false; 81 terugweg.className = 'mb-terugweg'; 82 terugweg.textContent = T.aseo_mb_checking || 'Terug-weg controleren…'; 83 try { 84 const r = await fetch(`/admin/seo/api/musicbrainz/terugweg?mbid=${encodeURIComponent(mbid)}`, { credentials: 'same-origin' }); 85 const j = await r.json(); 86 terugweg.className = 'mb-terugweg ' + (j.verified ? 'is-ok' : 'is-eenzijdig'); 87 terugweg.textContent = j.verified 88 ? (T.aseo_mb_verified || 'Wederzijds.') 89 : (T.aseo_mb_unverified || 'Nog eenzijdig.'); 90 } catch { 91 terugweg.hidden = true; 92 } 93 } 94 // Meteen bij het openen, want de artiest kan hem intussen op MusicBrainz 95 // hebben gezet en hoort dat hier te zien zonder opnieuw te koppelen. 96 if (idVeld.value) checkTerugweg(idVeld.value); 70 97 71 98 async function zoek() { -
src/routes/admin-seo.js
r013e16c rf50a84b 62 62 const q = String(req.query.q || (site && (site.publisher_name || site.title)) || '').trim(); 63 63 if (!q) return res.json({ ok: true, q: '', kandidaten: [] }); 64 // Wie zijn id al kent plakt het hier. Een zoekopdracht op een UUID levert bij 65 // MusicBrainz niets op, dus zonder deze tak geeft plakken juist het slechtste 66 // resultaat. 67 if (isMbid(q)) { 68 const een = await MusicBrainz.haalArtiest(q); 69 return res.json({ ok: true, q, kandidaten: een ? [een] : [] }); 70 } 64 71 res.json({ ok: true, q, kandidaten: await MusicBrainz.zoekArtiesten(q) }); 72 }); 73 74 /** 75 * De terug-weg: noemt de MusicBrainz-pagina ons domein? (shaer-mbz) 76 * 77 * Een koppeling van onze kant is een bewering -- iedereen kan een id typen. 78 * Pas als de artiestenpagina TERUGWIJST is het een paar. Wij zetten die 79 * verwijzing niet zelf: dat kan niet via hun API en hoort ook niet, de artiest 80 * doet dat op musicbrainz.org onder "social networking". 81 */ 82 router.get('/api/musicbrainz/terugweg', requireGod, async (req, res) => { 83 const mbid = String(req.query.mbid || '').trim().toLowerCase(); 84 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''); 85 if (!isMbid(mbid) || !base) return res.json({ ok: true, verified: false, urls: [] }); 86 res.json({ ok: true, ...(await MusicBrainz.controleerTerugweg(mbid, base)) }); 65 87 }); 66 88 -
src/services/MusicBrainzService.js
r013e16c rf50a84b 80 80 } 81 81 82 /** 83 * Een MBID rechtstreeks opzoeken. Wie zijn id al kent hoeft niet te zoeken -- 84 * en een zoekopdracht op een UUID levert bij MusicBrainz niets op, dus zonder 85 * deze tak zou plakken juist het slechtste resultaat geven. 86 */ 87 export async function haalArtiest(mbid) { 88 if (!isMbid(mbid)) return null; 89 const url = `${BASIS}/artist/${encodeURIComponent(mbid)}?inc=url-rels&fmt=json`; 90 try { 91 await opDeBeurt(); 92 const r = await safeFetch(url, { headers: { Accept: 'application/json', 'User-Agent': userAgent() } }); 93 if (!r || !r.ok) return null; 94 return kandidaat(await r.json()); 95 } catch { 96 return null; 97 } 98 } 99 100 /** 101 * DE TERUG-WEG. Noemt de MusicBrainz-pagina van deze artiest ons domein? 102 * 103 * Een koppeling van onze kant is een bewering: iedereen kan een MBID in een 104 * veld typen. Pas als de artiestenpagina TERUGWIJST is het een paar, en dan 105 * weet een lezer dat dezelfde persoon aan allebei de kanten stond. Dat is 106 * dezelfde gedachte als rel="me" bij Mastodon. 107 * 108 * Wij zetten die terugwijzing NIET zelf: via hun API kan het niet, en het hoort 109 * ook niet -- de artiest doet dat op musicbrainz.org onder "social networking". 110 * Wij kijken alleen of hij er staat. 111 * 112 * Geeft { verified, urls } -- bij een storing verified:false en een lege lijst, 113 * want niet kunnen kijken is niet hetzelfde als niet gevonden. 114 */ 115 export async function controleerTerugweg(mbid, domein) { 116 const leeg = { verified: false, urls: [] }; 117 if (!isMbid(mbid) || !domein) return leeg; 118 let host; 119 try { host = new URL(domein).host.toLowerCase(); } catch { return leeg; } 120 const url = `${BASIS}/artist/${encodeURIComponent(mbid)}?inc=url-rels&fmt=json`; 121 try { 122 await opDeBeurt(); 123 const r = await safeFetch(url, { headers: { Accept: 'application/json', 'User-Agent': userAgent() } }); 124 if (!r || !r.ok) return leeg; 125 const doc = await r.json(); 126 const urls = (doc.relations || []) 127 .map((rel) => rel && rel.url && rel.url.resource) 128 .filter((u) => typeof u === 'string'); 129 const wijst = urls.some((u) => { try { return new URL(u).host.toLowerCase() === host; } catch { return false; } }); 130 return { verified: wijst, urls }; 131 } catch { 132 return leeg; 133 } 134 } 135 82 136 /** Een kandidaat, teruggebracht tot wat een mens nodig heeft om te kiezen. */ 83 137 function kandidaat(a) { … … 104 158 // ze precies wonen. 105 159 export { isMbid, artiestUrl }; 106 export default { zoekArtiesten, isMbid, artiestUrl };160 export default { zoekArtiesten, haalArtiest, controleerTerugweg, isMbid, artiestUrl }; -
src/services/i18n.js
r013e16c rf50a84b 360 360 'aaud.fedi_off': 'Niet op de fediverse gedeeld (alleen webspeler, bestand verborgen) — klik om te delen', 361 361 'aaud.embed_player': 'Embedbare speler', 362 'aseo.mb_legend': 'MusicBrainz (dezelfde artiest elders)', 363 'aseo.mb_search_label': 'Zoek jezelf op', 364 'aseo.mb_search_hint': 'de naam waaronder je muziek uitbrengt', 365 'aseo.mb_hint': 'MusicBrainz is het open register van de muziekwereld. Koppel je eigen pagina en je komt als sameAs in de JSON-LD van deze site én in je fediverse-profiel te staan — zo weten zoekmachines en muziekdiensten dat jouw muziek van jou is. Je verandert er niets mee bij MusicBrainz zelf; we verwijzen er alleen naar.', 366 'aseo.mb_search': 'Zoeken', 367 'aseo.mb_placeholder': 'Je artiestennaam', 368 'aseo.mb_none': 'Niets gevonden. Sta je er nog niet in? Dan kun je jezelf aanmelden op musicbrainz.org — dat kan alleen daar, niet vanuit Klonkt.', 369 'aseo.mb_pick': 'Dit ben ik', 362 'aseo.mb_legend': 'MusicBrainz Koppeling', 370 363 'aseo.mb_linked': 'Gekoppeld aan', 371 364 'aseo.mb_unlink': 'Ontkoppelen', 372 365 'aseo.mb_open': 'Bekijk op MusicBrainz', 366 'aseo.mb_pick': 'Dit ben ik', 367 'aseo.mb_none': 'Niets gevonden. Sta je er nog niet in? Dan kun je jezelf aanmelden op musicbrainz.org — dat kan alleen daar, niet vanuit Klonkt.', 373 368 'aseo.mb_busy': 'Zoeken…', 374 369 'aseo.mb_fail': 'MusicBrainz is even niet bereikbaar.', 370 'aseo.mb_hint': 'Hier koppel je je MusicBrainz artiest id aan je domein, met terug-weg validatie van je "social networking" profiel pagina.', 371 'aseo.mb_search_label': 'Zoek op je naam', 372 'aseo.mb_search_hint': 'je artiestennaam of je MusicBrainz id als je die kent', 373 'aseo.mb_placeholder': 'Ozzy Osbourne', 374 'aseo.mb_search': 'Opzoeken', 375 'aseo.mb_verified': 'Wederzijds: de MusicBrainz-pagina wijst terug naar dit domein.', 376 'aseo.mb_unverified': 'Nog eenzijdig. Zet dit domein op je MusicBrainz-pagina onder "social networking", dan is de koppeling van twee kanten bevestigd.', 377 'aseo.mb_checking': 'Terug-weg controleren…', 375 378 'aaud.embed_hint': 'Plak deze code op je eigen website/blog om je muziek met deze speler in te sluiten:', 376 379 'aaud.preview_player': 'Speler-voorbeeld openen', … … 1320 1323 'aaud.fedi_off': 'Not shared on the fediverse (web player only, file hidden) — click to share', 1321 1324 'aaud.embed_player': 'Embeddable player', 1322 'aseo.mb_legend': 'MusicBrainz (the same artist elsewhere)', 1323 'aseo.mb_search_label': 'Look yourself up', 1324 'aseo.mb_search_hint': 'the name you release music under', 1325 'aseo.mb_hint': 'MusicBrainz is the music world\u2019s open register. Link your own page and it appears as sameAs in this site\u2019s JSON-LD and in your fediverse profile — so search engines and music services know your music is yours. It changes nothing at MusicBrainz itself; we only point at it.', 1326 'aseo.mb_search': 'Search', 1327 'aseo.mb_placeholder': 'Your artist name', 1328 'aseo.mb_none': 'Nothing found. Not in there yet? You can add yourself on musicbrainz.org — that can only be done there, not from Klonkt.', 1329 'aseo.mb_pick': 'This is me', 1325 'aseo.mb_legend': 'MusicBrainz link', 1330 1326 'aseo.mb_linked': 'Linked to', 1331 1327 'aseo.mb_unlink': 'Unlink', 1332 1328 'aseo.mb_open': 'View on MusicBrainz', 1329 'aseo.mb_pick': 'This is me', 1330 'aseo.mb_none': 'Nothing found. Not in there yet? You can add yourself on musicbrainz.org — that can only be done there, not from Klonkt.', 1333 1331 'aseo.mb_busy': 'Searching…', 1334 1332 'aseo.mb_fail': 'MusicBrainz is unreachable right now.', 1333 'aseo.mb_hint': 'Link your MusicBrainz artist id to your domain here, with back-way validation from your "social networking" profile page.', 1334 'aseo.mb_search_label': 'Search for your name', 1335 'aseo.mb_search_hint': 'your artist name, or your MusicBrainz id if you know it', 1336 'aseo.mb_placeholder': 'Ozzy Osbourne', 1337 'aseo.mb_search': 'Look up', 1338 'aseo.mb_verified': 'Mutual: the MusicBrainz page points back at this domain.', 1339 'aseo.mb_unverified': 'Still one-sided. Add this domain to your MusicBrainz page under "social networking" and the link is confirmed from both ends.', 1340 'aseo.mb_checking': 'Checking the back-way…', 1335 1341 'aaud.embed_hint': 'Paste this code on your own website/blog to embed your music with this player:', 1336 1342 'aaud.preview_player': 'Open player preview', … … 2279 2285 'aaud.fedi_off': 'Nicht im Fediverse geteilt (nur Web-Player, Datei verborgen) — zum Teilen klicken', 2280 2286 'aaud.embed_player': 'Einbettbarer Player', 2281 'aseo.mb_legend': 'MusicBrainz (dieselbe Künstlerin anderswo)', 2282 'aseo.mb_search_label': 'Dich selbst suchen', 2283 'aseo.mb_search_hint': 'der Name, unter dem du Musik veröffentlichst', 2284 'aseo.mb_hint': 'MusicBrainz ist das offene Register der Musikwelt. Verknüpfe deine Seite, und sie erscheint als sameAs im JSON-LD dieser Website und in deinem Fediverse-Profil — so wissen Suchmaschinen und Musikdienste, dass deine Musik von dir ist. Bei MusicBrainz selbst ändert sich nichts; wir verweisen nur darauf.', 2285 'aseo.mb_search': 'Suchen', 2286 'aseo.mb_placeholder': 'Dein Künstlername', 2287 'aseo.mb_none': 'Nichts gefunden. Noch nicht dabei? Du kannst dich auf musicbrainz.org eintragen — das geht nur dort, nicht aus Klonkt heraus.', 2288 'aseo.mb_pick': 'Das bin ich', 2287 'aseo.mb_legend': 'MusicBrainz-Verknüpfung', 2289 2288 'aseo.mb_linked': 'Verknüpft mit', 2290 2289 'aseo.mb_unlink': 'Trennen', 2291 2290 'aseo.mb_open': 'Bei MusicBrainz ansehen', 2291 'aseo.mb_pick': 'Das bin ich', 2292 'aseo.mb_none': 'Nichts gefunden. Noch nicht dabei? Du kannst dich auf musicbrainz.org eintragen — das geht nur dort, nicht aus Klonkt heraus.', 2292 2293 'aseo.mb_busy': 'Suche läuft…', 2293 2294 'aseo.mb_fail': 'MusicBrainz ist gerade nicht erreichbar.', 2295 'aseo.mb_hint': 'Hier verknüpfst du deine MusicBrainz-Künstler-ID mit deiner Domain, mit Rückweg-Validierung über deine "social networking"-Profilseite.', 2296 'aseo.mb_search_label': 'Nach deinem Namen suchen', 2297 'aseo.mb_search_hint': 'dein Künstlername oder deine MusicBrainz-ID, falls du sie kennst', 2298 'aseo.mb_placeholder': 'Ozzy Osbourne', 2299 'aseo.mb_search': 'Nachschlagen', 2300 'aseo.mb_verified': 'Gegenseitig: die MusicBrainz-Seite verweist zurück auf diese Domain.', 2301 'aseo.mb_unverified': 'Noch einseitig. Trage diese Domain auf deiner MusicBrainz-Seite unter "social networking" ein, dann ist die Verknüpfung von beiden Seiten bestätigt.', 2302 'aseo.mb_checking': 'Rückweg wird geprüft…', 2294 2303 'aaud.embed_hint': 'Füge diesen Code auf deiner eigenen Website/deinem Blog ein, um deine Musik mit diesem Player einzubetten:', 2295 2304 'aaud.preview_player': 'Player-Vorschau öffnen', -
src/views/pages/admin-seo.ejs
r013e16c rf50a84b 107 107 <button type="button" class="btn" id="mb-wis"><%= t('aseo.mb_unlink') %></button> 108 108 </p> 109 <%# De terug-weg. Een koppeling van onze kant is een BEWERING -- iedereen 110 kan een id typen. Pas als de MusicBrainz-pagina terugwijst is het een 111 paar, en dat staat hier met zoveel woorden zodat "eenzijdig" niet als 112 "klaar" leest. %> 113 <p class="mb-terugweg" id="mb-terugweg" hidden></p> 109 114 110 115 <label> -
test/musicbrainz.test.js
r013e16c rf50a84b 162 162 assert.equal(term.sameAs['@type'], '@id', 'het is een URI en geen tekst'); 163 163 }); 164 165 // ── De terug-weg (Robins "social networking"-validatie) ─────────────────── 166 167 test('een MBID in het zoekveld wordt rechtstreeks opgezocht', async () => { 168 // Zoeken op een UUID levert bij MusicBrainz niets op, dus zonder deze tak 169 // geeft plakken juist het slechtste resultaat. 170 globalThis.fetch = async (url) => { 171 verzoeken.push({ url: String(url) }); 172 return { ok: true, json: async () => ({ id: '8be31978-1884-4773-beae-f73df35b92aa', name: 'robo-burr', disambiguation: 'AKA roboburr' }) }; 173 }; 174 verzoeken.length = 0; 175 const een = await MB.haalArtiest('8be31978-1884-4773-beae-f73df35b92aa'); 176 assert.equal(een.naam, 'robo-burr'); 177 assert.match(verzoeken[0].url, /\/artist\/8be31978-1884-4773-beae-f73df35b92aa\?/, 'de lookup, niet de zoekopdracht'); 178 assert.equal(await MB.haalArtiest('nirvana'), null, 'geen MBID, geen lookup'); 179 }); 180 181 test('de terug-weg is pas waar als de pagina ONS domein noemt', async () => { 182 // Echt gemeten op 13-8: robo-burr heeft precies een url-relatie, type 183 // "social network", naar sound-fabrics.com. Dus voor dev.klonkt.com hoort 184 // hier false uit te komen -- en dat is de waarde van de controle. 185 globalThis.fetch = async () => ({ 186 ok: true, 187 json: async () => ({ relations: [{ type: 'social network', url: { resource: 'https://sound-fabrics.com/' } }] }), 188 }); 189 const mbid = '24abe2be-c0bc-4c63-9642-d6f89ec6a00a'; 190 const mis = await MB.controleerTerugweg(mbid, 'https://dev.klonkt.com'); 191 assert.equal(mis.verified, false, 'een andere site is geen terugweg'); 192 assert.deepEqual(mis.urls, ['https://sound-fabrics.com/']); 193 194 const raak = await MB.controleerTerugweg(mbid, 'https://sound-fabrics.com'); 195 assert.equal(raak.verified, true, 'dezelfde host telt, ongeacht pad of slash'); 196 }); 197 198 test('niet kunnen kijken is niet hetzelfde als niet gevonden', async () => { 199 // Bij een storing false EN een lege lijst -- nooit stilletjes "wederzijds". 200 globalThis.fetch = async () => { throw new Error('weg'); }; 201 const uit = await MB.controleerTerugweg('24abe2be-c0bc-4c63-9642-d6f89ec6a00a', 'https://dev.klonkt.com'); 202 assert.deepEqual(uit, { verified: false, urls: [] }); 203 });
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)