Changeset 47ca083 in Klonkt for src/routes/feed.js
- Timestamp:
- 08/08/2026 05:06:43 AM (5 weeks ago)
- Branches:
- main
- Children:
- 2220c49
- Parents:
- fb22f78
- git-author:
- Robin <roboburr@…> (08/08/2026 05:05:39 AM)
- git-committer:
- Robin <roboburr@…> (08/08/2026 05:06:43 AM)
- File:
-
- 1 edited
-
src/routes/feed.js (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/feed.js
rfb22f78 r47ca083 12 12 import express from 'express'; 13 13 import db from '../config/database.js'; 14 import { siteOpenTracks } from '../services/ActivityPubService.js'; 14 15 15 16 const router = express.Router(); … … 50 51 const base = origin + (res.locals.siteUrlBase || ''); 51 52 const posts = postsForFeed(site.id); 53 54 // De tracks die deze site aan de federatie heeft opengezet, elk als eigen 55 // item met een <enclosure> (shaer-0nh). Dat laatste is wat een podcast-app 56 // zoekt: zonder enclosure is een feed voor hem leeg, hoe veel items er ook 57 // in staan -- en de actor adverteert deze feed nu juist als kanaal-feed. 58 // 59 // EEN ITEM PER TRACK, want RSS 2.0 staat maar EEN enclosure per item toe. 60 // Een album in een item proppen zou betekenen dat er van vijf nummers vier 61 // verdwijnen. Dezelfde keuze als in de outbox: de post is het bericht, de 62 // track is de publicatie. 63 // 64 // Welke tracks open zijn beslist de AP-service, niet deze route: dat is een 65 // poortregel en die hoort op een plek te staan. 66 const tracks = siteOpenTracks(site.id); 52 67 const lastBuild = posts[0]?.published_at || new Date().toISOString(); 68 69 const wanneer = (d) => { const t = Date.parse(d); return Number.isNaN(t) ? 0 : t; }; 70 const items = [ 71 ...posts.map((p) => ({ op: wanneer(p.published_at), xml: ` <item> 72 <title>${escapeXml(p.title || '(untitled)')}</title> 73 <link>${escapeXml(base + '/' + p.slug)}</link> 74 <guid isPermaLink="true">${escapeXml(base + '/' + p.slug)}</guid> 75 <pubDate>${new Date(p.published_at).toUTCString()}</pubDate> 76 <author>${escapeXml((p.author_email || 'noreply@localhost') + ' (' + p.author_username + ')')}</author> 77 <description>${escapeXml(p.excerpt || '')}</description> 78 </item>` })), 79 ...tracks.map((t) => { 80 const fn = t.filename || (t.storage_path || '').split('/').pop(); 81 // Geen <link>: Klonkt heeft geen trackpagina, en een post over vijf 82 // nummers is niet de pagina van dit ene nummer. De guid is daarom geen 83 // permalink maar de stabiele AP-id van de track. 84 return { op: wanneer(t.created_at), xml: ` <item> 85 <title>${escapeXml(t.title || 'Audio')}</title> 86 <guid isPermaLink="false">${escapeXml(`${base}/ap/users/${encodeURIComponent(site.slug)}/tracks/${encodeURIComponent(t.id)}`)}</guid> 87 <pubDate>${new Date(t.created_at || Date.now()).toUTCString()}</pubDate> 88 <description>${escapeXml(t.artist || '')}</description> 89 <enclosure url="${escapeXml(`${base}/audio/stream/${encodeURIComponent(fn)}`)}" length="${Number(t.size) || 0}" type="${escapeXml(t.mime_type || 'audio/mpeg')}" />${t.duration ? ` 90 <itunes:duration>${Math.round(t.duration)}</itunes:duration>` : ''} 91 </item>` }; 92 }), 93 ].sort((a, b) => b.op - a.op).map((x) => x.xml).join('\n'); 53 94 54 95 res.set('Content-Type', 'application/rss+xml; charset=utf-8'); 55 96 res.send(`<?xml version="1.0" encoding="UTF-8"?> 56 <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" >97 <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"> 57 98 <channel> 58 99 <title>${escapeXml(site.title)}</title> … … 62 103 <lastBuildDate>${new Date(lastBuild).toUTCString()}</lastBuildDate> 63 104 <atom:link href="${escapeXml(base + '/feed.xml')}" rel="self" type="application/rss+xml" /> 64 ${posts.map(p => ` <item> 65 <title>${escapeXml(p.title || '(untitled)')}</title> 66 <link>${escapeXml(base + '/' + p.slug)}</link> 67 <guid isPermaLink="true">${escapeXml(base + '/' + p.slug)}</guid> 68 <pubDate>${new Date(p.published_at).toUTCString()}</pubDate> 69 <author>${escapeXml((p.author_email || 'noreply@localhost') + ' (' + p.author_username + ')')}</author> 70 <description>${escapeXml(p.excerpt || '')}</description> 71 </item>`).join('\n')} 105 ${items} 72 106 </channel> 73 107 </rss>`);
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)