Ignore:
Timestamp:
08/15/2026 07:15:55 AM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
5e16b8a
Parents:
2091647
Message:

Luisteraars: een eigen tab, want het is een eigen soort relatie (shaer-0nh)

Accounts die aan de BIBLIOTHEEK hangen in plaats van aan de actor. Ze krijgen de
muziek en met opzet NIET de gewone posts -- wie zich op een platenkast
abonneert heeft niet om de Krant gevraagd.

EEN EIGEN TABEL EN GEEN VLAG, en dat is de kern. Zolang ze in
ap_library_followers staan kan een postbezorging ze niet per ongeluk meenemen.
Een vlag op ap_followers die iemand vergeet te filteren doet dat wel, en die
fout is aan onze kant onzichtbaar: de posts komen gewoon aan bij mensen die er
niet om vroegen. De vorm moet de fout onmogelijk maken, niet alleen
onwaarschijnlijk. Een test bewaakt dat ap_followers leeg blijft.

WAT ER WERKT

  • Follow op /ap/users/<slug>/library wordt herkend, meteen geaccepteerd en vastgelegd. Meteen, want de bibliotheek is openbaar (alles erin is fedi_open) -- er valt niets goed te keuren, en dan is wachten oneerlijk.
  • Undo(Follow) haalt hem er meteen weer uit.
  • Volgen is idempotent; remote servers sturen een Follow gerust nog eens.
  • inboxen() ontdubbelt op gedeelde inbox: twee luisteraars op dezelfde instance krijgen EEN bezorging.
  • de tab in Mediabeheer, met naam, handle, sinds en laatste bezorging, in drie talen.

DE HERKENNING IS STRENG. libraryOwnerSlug eist dat de uri met ONZE basis begint
en dat de site bestaat -- via localSlugOf, dezelfde zeef als gisteren. Anders
levert andermans /library met dezelfde padstaart hier een luisteraar op onze
naam op.

WAT ER NOG NIET IS, en dat is de volgende stap: de BEZORGING. Er gaat nog geen
Create(Audio) naar deze inboxen. De lijst vult zich dus wel en "laatste
bezorging" blijft leeg -- eerlijk, want er is niets bezorgd.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r2091647 r732272a  
    3434// De muziekkant woont in music/ (shaer-drc). Doorgeven wat hier altijd
    3535// vandaan kwam, zodat elke bestaande aanroep blijft werken.
     36import { luisteraars } from './music/index.js';
    3637import { TRACK_KOLOMMEN,
    3738  playlistOpenTracks, siteOpenTracks, openTrack, trackHostPosts,
     
    356357  const pagina = pickLink(o.url, () => true);
    357358  return { html: HtmlSanitizerService.sanitize(o.content || ''), atts, url: pagina ? pagina.href : null };
     359}
     360
     361/**
     362 * De site achter een library-uri, of null. Zelfde strengheid als localSlugOf:
     363 * de uri moet met ONZE basis beginnen en de site moet bestaan -- anders levert
     364 * andermans /library met dezelfde padstaart hier een volger op onze naam op.
     365 */
     366function libraryOwnerSlug(uri) {
     367  const u = String(uri || '');
     368  if (!u.endsWith('/library')) return null;
     369  return localSlugOf(u.slice(0, -'/library'.length));
    358370}
    359371
     
    23562368  if (type === 'Follow') {
    23572369    const who = typeof act.actor === 'string' ? act.actor : (act.actor && act.actor.id);
     2370    // EERST: volgt iemand onze BIBLIOTHEEK in plaats van onze actor? (shaer-0nh)
     2371    //
     2372    // Een luisteraar krijgt de muziek en NIET de gewone posts -- wie zich
     2373    // abonneert op een platenkast heeft niet om de Krant gevraagd. Vandaar een
     2374    // eigen tabel: zolang ze daar staan kan een postbezorging ze niet per
     2375    // ongeluk meenemen.
     2376    //
     2377    // De bibliotheek is openbaar (alles erin is fedi_open), dus dit accepteert
     2378    // meteen. Er valt niets goed te keuren, en dan is wachten oneerlijk.
     2379    const libSlug = libraryOwnerSlug(typeof act.object === 'string' ? act.object : (act.object && act.object.id));
     2380    if (who && libSlug) {
     2381      const remote = await fetchActor(who);
     2382      if (!remote || !remote.inbox) return 202;
     2383      const fi = actorInfo(remote, who);
     2384      luisteraars.voegToe(libSlug, {
     2385        actorUri: who, inbox: remote.inbox,
     2386        sharedInbox: (remote.endpoints && remote.endpoints.sharedInbox) || null,
     2387        name: fi.name, handle: fi.handle, icon: fi.icon,
     2388      });
     2389      const keys = getOrCreateKeys(libSlug);
     2390      const accept = {
     2391        '@context': AP_CONTEXT,
     2392        id: `${actorId(base, libSlug)}#accept-library-${Date.now()}-${rid()}`,
     2393        type: 'Accept', actor: actorId(base, libSlug), object: act,
     2394      };
     2395      deliver(remote.inbox, accept, `${actorId(base, libSlug)}#main-key`, keys.privatePem)
     2396        .catch(() => { /* de volger staat er; een mislukte Accept mag dat niet omgooien */ });
     2397      console.log('[AP] library follow from', who, '->', libSlug);
     2398      return 202;
     2399    }
    23582400    // slugParam is de eigenaar van een per-actor inbox; op de GEDEELDE inbox is
    23592401    // die er niet en werd de slug uit act.object geraden. Zonder hostcontrole
     
    24392481    return 202;
    24402482  }
     2483  // Een luisteraar die weggaat, hoort meteen weg te zijn.
     2484  if (type === 'Undo' && act.object && act.object.type === 'Follow') {
     2485    const doel = typeof act.object.object === 'string' ? act.object.object : (act.object.object && act.object.object.id);
     2486    const libSlug = libraryOwnerSlug(doel);
     2487    const wie = typeof act.actor === 'string' ? act.actor : (act.actor && act.actor.id);
     2488    if (libSlug && wie && luisteraars.verwijder(libSlug, wie)) {
     2489      console.log('[AP] library unfollow from', wie, '->', libSlug);
     2490      return 202;
     2491    }
     2492  }
     2493
    24412494  if (type === 'Undo' && act.object) {
    24422495    const who = typeof act.actor === 'string' ? act.actor : (act.actor && act.actor.id);
Note: See TracChangeset for help on using the changeset viewer.