Changeset aed0092 in Klonkt for src/services
- Timestamp:
- 08/11/2026 06:35:19 PM (4 weeks ago)
- Branches:
- main
- Children:
- 960f015
- Parents:
- cb3001e
- Location:
- src/services
- Files:
-
- 4 edited
-
ActivityPubService.js (modified) (6 diffs)
-
ap-core.js (modified) (1 diff)
-
guardianship/queues.js (modified) (1 diff)
-
music/index.js (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
rcb3001e raed0092 29 29 import Blocklist from './BlocklistService.js'; 30 30 import * as Guardianship from './guardianship/index.js'; 31 import { PUBLIC, AP_CONTEXT, safeUrl, actorId, noteId, guessMediaType, normalizeTags, tagParts, hashtagTags, buildHashtagList } from './ap-core.js';31 import { PUBLIC, AP_CONTEXT, safeUrl, actorId, noteId, guessMediaType, normalizeTags, tagParts, hashtagTags, buildHashtagList, pagedCollection } from './ap-core.js'; 32 32 // Doorgeven wat hier altijd vandaan kwam, zodat elke bestaande aanroep blijft werken. 33 33 export { AP_CONTEXT, actorId, noteId, guessMediaType }; … … 1043 1043 // wie hem vandaag leest hoort er morgen niet voor te hoeven pagineren. Er is 1044 1044 // precies een pagina, dus first en last wijzen naar dezelfde. 1045 const eerste = `${id}?page=1`; 1046 if (page) { 1047 return { 1048 '@context': AP_CONTEXT, 1049 id: eerste, 1050 type: 'OrderedCollectionPage', 1051 partOf: id, 1052 totalItems: items.length, 1053 orderedItems: items, 1054 }; 1055 } 1056 return { 1057 '@context': AP_CONTEXT, 1058 id, 1059 type: 'OrderedCollection', 1060 totalItems: items.length, 1061 first: eerste, 1062 last: eerste, 1063 orderedItems: items, 1064 }; 1045 return pagedCollection(id, items, { page }); 1065 1046 } 1066 1047 … … 1070 1051 export function buildFollowers(base, site, count, items = null) { 1071 1052 const id = `${actorId(base, site.slug)}/followers`; 1072 return { 1073 '@context': AP_CONTEXT, 1074 id, 1075 type: 'OrderedCollection', 1076 totalItems: items ? items.length : (count || 0), 1077 orderedItems: items || [], // count-only for the public; full for the owner 1078 }; 1053 // count-only for the public; full for the owner 1054 return pagedCollection(id, items || [], { totalItems: items ? items.length : (count || 0) }); 1079 1055 } 1080 1056 … … 1083 1059 export function buildFollowing(base, site, count, items = null) { 1084 1060 const id = `${actorId(base, site.slug)}/following`; 1085 return { 1086 '@context': AP_CONTEXT, 1087 id, 1088 type: 'OrderedCollection', 1089 totalItems: items ? items.length : (count || 0), 1090 orderedItems: items || [], // count-only for the public; full for the owner 1091 }; 1061 // count-only for the public; full for the owner 1062 return pagedCollection(id, items || [], { totalItems: items ? items.length : (count || 0) }); 1092 1063 } 1093 1064 … … 1098 1069 const id = `${actorId(base, site.slug)}/featured`; 1099 1070 const items = (posts || []).map((p) => buildNote(base, site, p)); 1100 return { 1101 '@context': AP_CONTEXT, 1102 id, 1103 type: 'OrderedCollection', 1104 totalItems: items.length, 1105 orderedItems: items, 1106 }; 1071 return pagedCollection(id, items); 1107 1072 } 1108 1073 … … 6555 6520 6556 6521 export default { 6557 AP_CONTEXT, getOrCreateKeys, apWants, sendAP, actorId, noteId, stripLeadingMentions, 6522 AP_CONTEXT, getOrCreateKeys, apWants, sendAP, actorId, noteId, stripLeadingMentions, pagedCollection, 6558 6523 buildActor, buildNote, buildCreate, buildOutbox, buildFollowers, buildFollowing, buildFeatured, 6559 6524 channelUrls, channelCategory, timelineFields, guessMediaType, -
src/services/ap-core.js
rcb3001e raed0092 187 187 return out; 188 188 } 189 190 /** 191 * Een AS2-collectie MET de paginavelden erbij (shaer-0nh, 11-8). 192 * 193 * WAAROM DIT EEN HELPER IS EN GEEN REGELS. Funkwhale weigerde onze outbox met 194 * "first: This field is required" en "last: This field is required" -- de eerste 195 * concrete reden die we hoorden waarom er niets van ons binnenkwam. AS2 EIST die 196 * velden niet, maar bijna iedereen pagineert, en een lezer die de paginaweg 197 * volgt liep dood. Toen dat voor de outbox gerepareerd was misten alle andere 198 * collecties ze nog steeds. Een helper zorgt dat de volgende collectie ze niet 199 * opnieuw vergeet. 200 * 201 * DE ITEMS BLIJVEN INLINE op de wortel. Shaer bouwt zijn feed daaruit, en wie 202 * hem vandaag leest hoort er morgen niet voor te hoeven pagineren. Onze 203 * collecties zijn gekapt, dus er is precies EEN pagina en wijzen first en last 204 * naar dezelfde. 205 * 206 * @param {string} id de collectie-uri, zonder query 207 * @param {Array} items wat erin zit (mag leeg) 208 * @param {object} opts 209 * totalItems als de telling niet items.length is (followers geeft publiek 210 * alleen een AANTAL en houdt de lijst dicht) 211 * page true -> een OrderedCollectionPage met partOf in plaats van de wortel 212 * extra velden die op de wortel horen (attributedTo, shaer:*) 213 */ 214 export function pagedCollection(id, items, { totalItems, page = false, extra = {} } = {}) { 215 const lijst = items || []; 216 const telling = totalItems === undefined ? lijst.length : totalItems; 217 const eerste = `${id}?page=1`; 218 if (page) { 219 return { 220 '@context': AP_CONTEXT, 221 id: eerste, 222 type: 'OrderedCollectionPage', 223 partOf: id, 224 totalItems: telling, 225 orderedItems: lijst, 226 }; 227 } 228 return { 229 '@context': AP_CONTEXT, 230 id, 231 type: 'OrderedCollection', 232 ...extra, 233 totalItems: telling, 234 first: eerste, 235 last: eerste, 236 orderedItems: lijst, 237 }; 238 } -
src/services/guardianship/queues.js
rcb3001e raed0092 20 20 import * as handshake from './handshake.js'; 21 21 22 // De @context zet de route erop (queueRoute), dus hier bewust niet 23 // pagedCollection uit ap-core -- die voegt hem toe en dan staat hij er twee 24 // keer. Wel dezelfde paginavelden, om dezelfde reden: een lezer die de 25 // paginaweg volgt hoort niet dood te lopen (Funkwhale, 11-8). 22 26 const collection = (id, items) => ({ 23 id, type: 'OrderedCollection', totalItems: items.length, orderedItems: items, 27 id, type: 'OrderedCollection', totalItems: items.length, 28 first: `${id}?page=1`, last: `${id}?page=1`, 29 orderedItems: items, 24 30 }); 25 31 -
src/services/music/index.js
rcb3001e raed0092 14 14 15 15 import db from '../../config/database.js'; 16 import { AP_CONTEXT, PUBLIC, actorId, noteId, safeUrl, guessMediaType, buildHashtagList } from '../ap-core.js';16 import { AP_CONTEXT, PUBLIC, actorId, noteId, safeUrl, guessMediaType, buildHashtagList, pagedCollection } from '../ap-core.js'; 17 17 import { afleidenUitInsluitingen, ingeslotenPlaylists } from '../../assets/js/shared/post-music-type.js'; 18 18 … … 201 201 /** De collectie van alle open tracks van een site (shaer-0nh, stap 3). */ 202 202 export function buildTrackCollection(base, site, rows) { 203 return { 204 '@context': AP_CONTEXT, 205 id: `${actorId(base, site.slug)}/tracks`, 206 type: 'OrderedCollection', 207 attributedTo: actorId(base, site.slug), 208 totalItems: (rows || []).length, 209 // Eén zoekopdracht voor alle rijen samen; zie trackHostPosts. 210 orderedItems: (() => { 211 const posts = site.id ? trackHostPosts(site.id) : null; 212 return (rows || []).map((r) => buildTrackAudio(base, site, r, { hostPosts: posts })); 213 })(), 214 }; 203 // Eén zoekopdracht voor alle rijen samen; zie trackHostPosts. 204 const posts = site.id ? trackHostPosts(site.id) : null; 205 const items = (rows || []).map((r) => buildTrackAudio(base, site, r, { hostPosts: posts })); 206 return pagedCollection(`${actorId(base, site.slug)}/tracks`, items, { extra: { attributedTo: actorId(base, site.slug) } }); 215 207 } 216 208 … … 270 262 return stub; 271 263 }); 272 return { 273 '@context': AP_CONTEXT, 274 id: colId, 275 type: 'OrderedCollection', 276 attributedTo: actorId(base, site.slug), 277 totalItems: items.length, 278 orderedItems: items, 279 }; 264 return pagedCollection(colId, items, { extra: { attributedTo: actorId(base, site.slug) } }); 280 265 } 281 266 … … 289 274 const hostPosts = site.id ? trackHostPosts(site.id) : null; 290 275 const items = (rows || []).map((r) => buildTrackAudio(base, site, r, { coverFallback: playlist.cover_url || null, hostPosts })); 291 const out = { 292 '@context': AP_CONTEXT, 293 id: `${actorId(base, site.slug)}/playlists/${playlist.id}`, 294 type: 'OrderedCollection', 295 name: playlist.title, 296 attributedTo: actorId(base, site.slug), 297 totalItems: items.length, 298 orderedItems: items, 299 }; 276 const out = pagedCollection(`${actorId(base, site.slug)}/playlists/${playlist.id}`, items, { 277 extra: { name: playlist.title, attributedTo: actorId(base, site.slug) }, 278 }); 300 279 // Album of playlist is presentatie; op de draad is het één samenvattingsveld. 301 280 const parts = []; … … 449 428 450 429 const hostPosts = new Map(rows.map((r) => [r.id, { id: post.id, slug: post.slug }])); 451 const out = { 452 '@context': AP_CONTEXT, 453 id: postTracksId(base, site, post.id), 454 type: 'OrderedCollection', 455 attributedTo: actorId(base, site.slug), 456 totalItems: rows.length, 457 orderedItems: rows.map((r) => buildTrackAudio(base, site, r, { hostPosts })), 458 }; 430 const out = pagedCollection(postTracksId(base, site, post.id), 431 rows.map((r) => buildTrackAudio(base, site, r, { hostPosts })), 432 { extra: { attributedTo: actorId(base, site.slug) } }); 459 433 return leenVanPost(base, site, out, post); 460 434 }
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)