Changeset 5300652 in Klonkt for src/assets/js/mod/admin-audio.js


Ignore:
Timestamp:
08/13/2026 01:08:32 PM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
6401681
Parents:
a117862
git-author:
Robin <roboburr@…> (08/13/2026 12:10:40 PM)
git-committer:
Robin <roboburr@…> (08/13/2026 01:08:32 PM)
Message:

Stap 2: "Ben jij dit?" in Beheer -> Audio (shaer-mbz)

Een paneel bovenaan het audioscherm: zoek op je artiestennaam (voorgevuld met
wat er al in de site staat), kies je eigen pagina, klaar. Drie talen.

DE TOELICHTING IS HET HELE PUNT. Elke kandidaat toont MusicBrainz'
disambiguation naast soort, land en jaren -- er zijn drie bands die Nirvana
heten, en met alleen een naam kiest iemand de verkeerde. Wij kiezen NIET voor
de artiest, ook niet als er precies een treffer is: een verkeerd geraden MBID
zet jouw naam onder andermans werk.

ONTKOPPELEN KAN. Om dezelfde reden: zo'n vergissing hoort met een klik terug
te draaien te zijn, niet met een databasebewerking.

Alleen een echte MBID komt de kolom in; de route weigert een URL of een handle.
De naam bewaren we ernaast zodat het scherm kan tonen WAT er hangt zonder
ervoor te netwerken -- en zodat een verkeerde koppeling opvalt.

TWEE DINGEN UIT DE HUISREGELS. De kandidaten gaan met textContent het scherm op
en niet als HTML: dat is tekst uit een vreemd register. En het blok hangt in
run() en niet op moduleniveau -- deze modules krijgen bij elke paginawissel
opnieuw init(), en een blok dat maar een keer per sessie draait is precies wat
shaer-5s1 opleverde. Ik had hem er eerst buiten gezet.

Als iemand niet in MusicBrainz staat zegt het scherm dat hij zich daar kan
aanmelden -- en erbij dat dat alleen dáár kan, niet vanuit Klonkt. Dat is geen
bescheidenheid maar hun API: artiesten zijn er niet mee aan te maken.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/assets/js/mod/admin-audio.js

    ra117862 r5300652  
    452452  });
    453453})();
     454
     455  // MusicBrainz-paneel (shaer-mbz). Binnen run(), niet op moduleniveau:
     456  // deze modules krijgen bij elke paginawissel opnieuw init(), en een blok dat
     457  // maar een keer per sessie draait is precies wat shaer-5s1 opleverde.
     458  wireMusicBrainz();
    454459}
     460
     461// ── MusicBrainz: ben jij dit? (shaer-mbz, stap 2) ─────────────────
     462//
     463// De kandidaten komen van de server, want MusicBrainz eist een verzoek per
     464// seconde per APPLICATIE en een User-Agent met contact -- allebei niet vanuit
     465// een browser af te dwingen.
     466//
     467// WIJ KIEZEN NIET. Ook niet als er precies een treffer is: een verkeerd
     468// geraden MBID zet jouw naam onder andermans werk. De knop staat er, de klik
     469// is van de artiest.
     470function wireMusicBrainz() {
     471  const knop = document.getElementById('mb-zoek-btn');
     472  const veld = document.getElementById('mb-q');
     473  const uit = document.getElementById('mb-uit');
     474  if (!knop || !veld || !uit || knop.__wired) return;
     475  knop.__wired = true;
     476
     477  const el = (tag, cls, tekst) => {
     478    const e = document.createElement(tag);
     479    if (cls) e.className = cls;
     480    if (tekst != null) e.textContent = tekst;   // textContent: nooit HTML uit een vreemd register
     481    return e;
     482  };
     483
     484  async function zoek() {
     485    const q = (veld.value || '').trim();
     486    if (!q) return;
     487    uit.hidden = false;
     488    uit.replaceChildren(el('p', 'ax-hint', T.aaud_mb_busy || 'Zoeken…'));
     489    knop.disabled = true;
     490    try {
     491      const r = await fetch(`api/musicbrainz?q=${encodeURIComponent(q)}`, { credentials: 'same-origin' });
     492      const j = await r.json();
     493      toon((j && j.kandidaten) || []);
     494    } catch {
     495      uit.replaceChildren(el('p', 'ax-hint', T.aaud_mb_fail || 'MusicBrainz is even niet bereikbaar.'));
     496    } finally {
     497      knop.disabled = false;
     498    }
     499  }
     500
     501  function toon(kandidaten) {
     502    if (!kandidaten.length) {
     503      uit.replaceChildren(el('p', 'ax-hint', T.aaud_mb_none || 'Niets gevonden.'));
     504      return;
     505    }
     506    const lijst = el('ul', 'mb-lijst');
     507    for (const k of kandidaten) {
     508      const li = el('li', 'mb-kandidaat');
     509      li.appendChild(el('strong', null, k.naam));
     510      // De toelichting is het hele punt: er zijn drie bands die Nirvana heten,
     511      // en zonder dit veld kiest iemand de verkeerde.
     512      const bij = [k.toelichting, k.soort, k.land, k.jaren].filter(Boolean).join(' · ');
     513      if (bij) li.appendChild(el('small', 'mb-bij', bij));
     514      const open = el('a', 'mb-open', T.aaud_mb_open || 'Bekijk op MusicBrainz');
     515      open.href = k.url; open.target = '_blank'; open.rel = 'noopener';
     516      li.appendChild(open);
     517      li.appendChild(kiesForm(k));
     518      lijst.appendChild(li);
     519    }
     520    uit.replaceChildren(lijst);
     521  }
     522
     523  function kiesForm(k) {
     524    const f = document.createElement('form');
     525    f.method = 'POST';
     526    f.action = 'musicbrainz/link';
     527    for (const [naam, waarde] of [['_csrf', csrf()], ['mbid', k.mbid], ['naam', k.naam]]) {
     528      const i = document.createElement('input');
     529      i.type = 'hidden'; i.name = naam; i.value = waarde || '';
     530      f.appendChild(i);
     531    }
     532    const b = el('button', 'ax-btn', T.aaud_mb_pick || 'Dit ben ik');
     533    b.type = 'submit';
     534    f.appendChild(b);
     535    return f;
     536  }
     537
     538  // Het token staat al in elk formulier op deze pagina; er is er geen apart voor.
     539  const csrf = () => (document.querySelector('input[name="_csrf"]') || {}).value || '';
     540
     541  knop.addEventListener('click', zoek);
     542  veld.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); zoek(); } });
     543}
Note: See TracChangeset for help on using the changeset viewer.