source: Klonkt/src/services/music/luisteraars.js@ 732272a

main
Last change on this file since 732272a was 732272a, checked in by Robin <roboburr@…>, 4 weeks ago

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@…>

  • Property mode set to 100644
File size: 3.0 KB
Line 
1/**
2 * Luisteraars: wie de BIBLIOTHEEK volgt (shaer-0nh).
3 *
4 * Een aparte soort volger. Ze hangen aan `/ap/users/<slug>/library` en niet aan
5 * de actor, en dat verschil is de hele bedoeling: een luisteraar krijgt de
6 * muziek en NIET de gewone posts. Iemand die zich abonneert op een
7 * platenkast heeft niet gevraagd om de Krant.
8 *
9 * WAAROM EEN EIGEN TABEL EN GEEN VLAG op ap_followers: zolang ze ergens anders
10 * staan kan een bezorging ze niet per ongeluk meenemen. Een vlag die iemand
11 * vergeet te filteren doet dat wel, en dan is de fout stil -- de posts komen
12 * gewoon aan bij mensen die er niet om vroegen, en niemand ziet het aan onze
13 * kant. Dit is dezelfde afweging als bij de wachtrijen: de vorm moet de fout
14 * onmogelijk maken, niet alleen onwaarschijnlijk.
15 */
16import db from '../../config/database.js';
17
18const stmt = (sql) => db.prepare(sql);
19
20/** Erbij, of bijwerken als hij er al was. Volgen is idempotent. */
21export function voegToe(slug, { actorUri, inbox, sharedInbox, name, handle, icon }) {
22 if (!slug || !actorUri) return false;
23 try {
24 stmt(`INSERT INTO ap_library_followers (slug, actor_uri, inbox, shared_inbox, name, handle, icon)
25 VALUES (?,?,?,?,?,?,?)
26 ON CONFLICT (slug, actor_uri) DO UPDATE SET
27 inbox = excluded.inbox, shared_inbox = excluded.shared_inbox,
28 name = excluded.name, handle = excluded.handle, icon = excluded.icon`)
29 .run(slug, actorUri, inbox || null, sharedInbox || null, name || null, handle || null, icon || null);
30 return true;
31 } catch { return false; }
32}
33
34/** Weg. Een Undo(Follow) hoort meteen te werken, niet pas na een opruiming. */
35export function verwijder(slug, actorUri) {
36 try { return stmt('DELETE FROM ap_library_followers WHERE slug = ? AND actor_uri = ?').run(slug, actorUri).changes > 0; }
37 catch { return false; }
38}
39
40/** Voor het beheerscherm. */
41export function lijst(slug) {
42 try {
43 return stmt(`SELECT actor_uri, inbox, shared_inbox, name, handle, icon, created_at, last_delivery_at, last_error_at
44 FROM ap_library_followers WHERE slug = ? ORDER BY created_at DESC`).all(slug);
45 } catch { return []; }
46}
47
48export function telling(slug) {
49 try { return stmt('SELECT COUNT(*) n FROM ap_library_followers WHERE slug = ?').get(slug).n; }
50 catch { return 0; }
51}
52
53/** Volgt deze actor onze bibliotheek al? */
54export function isLuisteraar(slug, actorUri) {
55 try { return !!stmt('SELECT 1 FROM ap_library_followers WHERE slug = ? AND actor_uri = ?').get(slug, actorUri); }
56 catch { return false; }
57}
58
59/**
60 * De inboxen om muziek naartoe te sturen, ontdubbeld op gedeelde inbox.
61 * Nog niemand gebruikt dit -- de bezorging is de volgende stap -- maar het hoort
62 * bij de opslag en niet bij de aanroeper.
63 */
64export function inboxen(slug) {
65 const uit = new Map();
66 for (const r of lijst(slug)) {
67 const adres = r.shared_inbox || r.inbox;
68 if (adres && !uit.has(adres)) uit.set(adres, r.actor_uri);
69 }
70 return [...uit.keys()];
71}
72
73export default { voegToe, verwijder, lijst, telling, isLuisteraar, inboxen };
Note: See TracBrowser for help on using the repository browser.