Changeset cf5073b in Klonkt


Ignore:
Timestamp:
08/08/2026 05:47:57 AM (5 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
f3a2556
Parents:
4d81de5
git-author:
Robin <roboburr@…> (08/08/2026 05:46:48 AM)
git-committer:
Robin <roboburr@…> (08/08/2026 05:47:57 AM)
Message:

Onze Audio inhoudelijk gelijk aan die van Funkwhale

Dezelfde track aan beide kanten naast elkaar gelegd -- 0METAL MARIO, bij hen op
the_ceeesg en bij ons op dev -- en de uitkomst was gunstiger dan verwacht.

OP ELK VELD WAAR AS2 IETS ZEGT ZIJN WIJ CONFORM EN ZIJ NIET, en dat is precies
een veld: duration. AS2 zegt MUST xsd:duration ("PT103S"), schema.org zegt
hetzelfde in ISO 8601, Funkwhale stuurt 103. Daar bewegen we dus niet.

Al hun EXTRA velden bleken geen eigen verzinsel maar termen die schema.org
gewoon heeft -- en schema.org stond al in onze context. Overgenomen zonder
concessie: de SLEUTELS zijn die van Funkwhale, want daar leest hij op, de
BETEKENIS komt van schema.org. Geen vreemd vocabulaire binnengehaald.

to op het OBJECT, niet alleen op de omhullende Create: een los

opgehaalde track moet zelf kunnen zeggen dat hij openbaar is

position het nummer op de plaat
license schema:license
size schema:contentSize, OP DE LINK -- het is die representatie die
bitrate schema:bitrate zoveel bytes is, niet het nummer
image naast icon; allebei AS2-kern, wij lazen icon, zij lezen image

BITRATE IS AFGELEID, niet gegokt: bytes maal acht gedeeld door seconden IS de
gemiddelde bitrate van een bestand. Alleen als we allebei de getallen hebben --
liever geen veld dan een verzonnen getal.

LICENTIE IS DE ENIGE MET EEN VERTAALSLAG. Bij ons is het vrije tekst uit een
keuzelijst ("CC BY 4.0"), bij hen een URI. Alleen de waarden die onze eigen
keuzelijst aanbiedt worden vertaald -- die kennen we exact. "Alle rechten
voorbehouden" heeft geen URI en levert dus niets op, en een al ingevulde URI
gaat ongemoeid door. Een zelfbedachte licentie-URI is erger dan geen: een lezer
gelooft hem.

Onderweg: t.position en t.license moesten alsnog in de trackquery, die
selecteerde ze niet.

7 tests.

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

Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r4d81de5 rcf5073b  
    5252    value: 'schema:value',
    5353    embedUrl: { '@id': 'schema:embedUrl', '@type': '@id' },
     54    // Wat een track beschrijft en AS2 niet kent (shaer-0nh). Funkwhale zet deze
     55    // vier op zijn Audio; het bleken geen eigen verzinsels maar termen die
     56    // schema.org gewoon heeft -- en schema.org stond hier al. De SLEUTELS zijn
     57    // die van Funkwhale, want daar leest hij op; de BETEKENIS komt van
     58    // schema.org, dus we hoeven geen vreemd vocabulaire binnen te halen.
     59    license: { '@id': 'schema:license', '@type': '@id' },
     60    position: 'schema:position',
     61    bitrate: 'schema:bitrate',
     62    size: 'schema:contentSize',
    5463    // Poll (Question) extension: Question/oneOf/anyOf/endTime/closed are AS2 core, but the
    5564    // per-poll unique-voter count is a Mastodon (toot) term — declare it so the emitted
     
    10671076// m.size hoort erbij voor de RSS-enclosure: die eist een lengte in bytes.
    10681077const TRACK_KOLOMMEN = `t.id, t.title, t.artist, t.duration, t.cover_url, t.created_at,
     1078     t.position, t.license,
    10691079     m.filename, m.storage_path, m.mime_type, m.size`;
    10701080
     
    11231133  const abs = (u) => !u ? null : (/^https?:/i.test(u) ? u : `${base}${u.startsWith('/') ? '' : '/'}${u}`);
    11241134  const fn = r.filename || (r.storage_path || '').split('/').pop();
     1135  // De bestandsgegevens horen bij de LINK, niet bij het object: het is die ene
     1136  // representatie die zoveel bytes is en die bitrate heeft, niet het nummer.
     1137  // Zo doet Funkwhale het ook.
     1138  const bestand = { type: 'Link', href: `${base}/audio/stream/${encodeURIComponent(fn)}`, mediaType: r.mime_type || 'audio/mpeg' };
     1139  if (Number(r.size)) bestand.size = Number(r.size);
     1140  // Bitrate leiden we af uit bytes en seconden. Geen gok: voor een bestand IS
     1141  // dat de gemiddelde bitrate, en bij CBR ook de echte. Alleen als we allebei
     1142  // de getallen hebben -- liever geen veld dan een verzonnen getal.
     1143  if (Number(r.size) && Number(r.duration)) bestand.bitrate = Math.round((Number(r.size) * 8) / Number(r.duration));
     1144
    11251145  const a = {
    11261146    ...(opts.standalone ? { '@context': AP_CONTEXT } : {}),
     
    11291149    name: r.title || 'Audio',
    11301150    attributedTo: actorId(base, site.slug),
    1131     url: [{ type: 'Link', href: `${base}/audio/stream/${encodeURIComponent(fn)}`, mediaType: r.mime_type || 'audio/mpeg' }],
     1151    // Op het OBJECT, niet alleen op de omhullende Create: een los opgehaalde
     1152    // track moet zelf kunnen zeggen dat hij openbaar is.
     1153    to: [PUBLIC],
     1154    url: [bestand],
    11321155  };
    11331156  if (r.artist) a.summary = r.artist;              // artiest als summary: kaal AS2, geen eigen vocab
    11341157  if (r.duration) a.duration = `PT${Math.round(r.duration)}S`;
    11351158  if (r.created_at) a.published = new Date(r.created_at).toISOString();
     1159  if (Number(r.position)) a.position = Number(r.position);
     1160  const lic = licentieUri(r.license);
     1161  if (lic) a.license = lic;
    11361162  const art = abs(r.cover_url || opts.coverFallback || null);
    1137   if (art) a.icon = { type: 'Image', mediaType: guessMediaType(art), url: art };
     1163  // icon EN image: allebei AS2-kern. Wij gebruikten alleen icon; Funkwhale
     1164  // leest image. Dezelfde hoes, twee namen, niemand die iets misloopt.
     1165  if (art) {
     1166    const plaat = { type: 'Image', mediaType: guessMediaType(art), url: art };
     1167    a.icon = plaat;
     1168    a.image = plaat;
     1169  }
    11381170  return a;
     1171}
     1172
     1173/**
     1174 * Onze licentie is VRIJE TEKST uit een keuzelijst ("CC BY 4.0", "Alle rechten
     1175 * voorbehouden"); schema.org en Funkwhale willen een URI. Alleen de waarden die
     1176 * onze eigen keuzelijst aanbiedt worden vertaald -- die kennen we exact. Al het
     1177 * andere levert niets op: een zelfbedachte licentie-URI is erger dan geen, want
     1178 * een lezer gelooft hem.
     1179 */
     1180const LICENTIES = {
     1181  'cc0 1.0 (publiek domein)': 'http://creativecommons.org/publicdomain/zero/1.0/',
     1182  'cc by 4.0': 'http://creativecommons.org/licenses/by/4.0/',
     1183  'cc by-sa 4.0': 'http://creativecommons.org/licenses/by-sa/4.0/',
     1184  'cc by-nc 4.0': 'http://creativecommons.org/licenses/by-nc/4.0/',
     1185  'cc by-nc-sa 4.0': 'http://creativecommons.org/licenses/by-nc-sa/4.0/',
     1186  'cc by-nd 4.0': 'http://creativecommons.org/licenses/by-nd/4.0/',
     1187};
     1188export function licentieUri(waarde) {
     1189  const s = String(waarde || '').trim();
     1190  if (!s) return null;
     1191  if (/^https?:\/\//i.test(s)) return safeUrl(s);   // iemand vulde al een URI in
     1192  return LICENTIES[s.toLowerCase()] || null;        // "Alle rechten voorbehouden" heeft er geen
    11391193}
    11401194
  • test/ap-tracks.test.js

    r4d81de5 rcf5073b  
    7575  assert.equal(a.duration, 'PT203S');
    7676  assert.equal(a.summary, 'De Band');
    77   assert.deepEqual(a.url, [{
    78     type: 'Link', href: 'https://test.example/audio/stream/open.mp3', mediaType: 'audio/mpeg',
    79   }], 'de mediaType hoort bij de link, niet bij het object');
     77  // De Link draagt sinds de veldvergelijking met Funkwhale ook de
     78  // bestandsgegevens: die horen bij DEZE representatie, niet bij het nummer.
     79  assert.equal(a.url.length, 1);
     80  assert.equal(a.url[0].type, 'Link');
     81  assert.equal(a.url[0].href, 'https://test.example/audio/stream/open.mp3');
     82  assert.equal(a.url[0].mediaType, 'audio/mpeg', 'de mediaType hoort bij de link, niet bij het object');
     83  assert.equal(a.mediaType, undefined, 'en dus NIET op het object');
    8084  assert.equal(a.icon.url, 'https://test.example/media/hoes.jpg');
    8185});
Note: See TracChangeset for help on using the changeset viewer.