mirror of
https://github.com/Einundzwanzig-Podcast/einundzwanzig.space.git
synced 2026-04-17 05:08:42 +00:00
Paginate feed
This commit is contained in:
@@ -11,19 +11,122 @@ const json2xmlOpts = {
|
||||
cdataPropName: '__cdata',
|
||||
indentBy: ' '
|
||||
}
|
||||
const builder = new XMLBuilder(json2xmlOpts)
|
||||
|
||||
// Load and adapt feed
|
||||
const outputXML = builder.build(feed)
|
||||
const validation = XMLValidator.validate(outputXML)
|
||||
if (validation) {
|
||||
write(
|
||||
'dist/feed.xml',
|
||||
xmlFormat(outputXML, {
|
||||
indentation: json2xmlOpts.indentBy,
|
||||
collapseContent: true
|
||||
})
|
||||
)
|
||||
} else {
|
||||
console.error(validation.err)
|
||||
const PAGE_SIZE = 21
|
||||
|
||||
function writePage(feedJson, itemsSlice, pageIndex, totalPages) {
|
||||
const builder = new XMLBuilder(json2xmlOpts)
|
||||
const feedCopy = JSON.parse(JSON.stringify(feedJson))
|
||||
|
||||
// Ensure channel.item is the page slice
|
||||
feedCopy.rss = feedCopy.rss || {}
|
||||
feedCopy.rss.channel = feedCopy.rss.channel || {}
|
||||
feedCopy.rss.channel.item = itemsSlice
|
||||
|
||||
// Build atom links: adapt self, add prev/next where appropriate
|
||||
const origAtom = (feedJson.rss && feedJson.rss.channel && feedJson.rss.channel['atom:link']) || []
|
||||
const origSelf = Array.isArray(origAtom)
|
||||
? (origAtom.find(l => l.__attr && l.__attr.rel === 'self') || {}).__attr
|
||||
: (origAtom && origAtom.__attr) || {}
|
||||
const originalHref = (origSelf && origSelf.href) || ''
|
||||
const base = originalHref.replace(/\/feed(?:-page-\d+)?\.xml$/, '')
|
||||
|
||||
const pageNumber = pageIndex + 1
|
||||
const selfHref = pageIndex === 0 ? `${base}/feed.xml` : `${base}/feed-page-${pageNumber}.xml`
|
||||
|
||||
const newAtom = []
|
||||
newAtom.push({ __attr: { href: selfHref, rel: 'self', type: 'application/rss+xml' } })
|
||||
// preserve hub if present
|
||||
const hub = Array.isArray(origAtom) && origAtom.find(l => l.__attr && l.__attr.rel === 'hub')
|
||||
if (hub) newAtom.push(hub)
|
||||
|
||||
if (pageIndex > 0) {
|
||||
const prevHref = pageIndex === 1 ? `${base}/feed.xml` : `${base}/feed-page-${pageIndex}.xml`
|
||||
newAtom.push({ __attr: { href: prevHref, rel: 'prev', type: 'application/rss+xml' } })
|
||||
}
|
||||
|
||||
if (pageIndex < totalPages - 1) {
|
||||
const nextHref = `${base}/feed-page-${pageNumber + 1}.xml`
|
||||
newAtom.push({ __attr: { href: nextHref, rel: 'next', type: 'application/rss+xml' } })
|
||||
}
|
||||
|
||||
feedCopy.rss.channel['atom:link'] = newAtom
|
||||
|
||||
const outputXML = builder.build(feedCopy)
|
||||
const validation = XMLValidator.validate(outputXML)
|
||||
if (validation) {
|
||||
const filename = pageIndex === 0 ? 'dist/feed.xml' : `dist/feed-page-${pageNumber}.xml`
|
||||
write(
|
||||
filename,
|
||||
xmlFormat(outputXML, {
|
||||
indentation: json2xmlOpts.indentBy,
|
||||
collapseContent: true
|
||||
})
|
||||
)
|
||||
return filename
|
||||
} else {
|
||||
console.error('XML validation error:', validation.err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// Main: split items and write pages
|
||||
const items = (feed.rss && feed.rss.channel && feed.rss.channel.item) || []
|
||||
const totalPages = Math.max(1, Math.ceil(items.length / PAGE_SIZE))
|
||||
const written = []
|
||||
for (let i = 0; i < totalPages; i++) {
|
||||
const start = i * PAGE_SIZE
|
||||
const slice = items.slice(start, start + PAGE_SIZE)
|
||||
const out = writePage(feed, slice, i, totalPages)
|
||||
if (out) written.push(out)
|
||||
}
|
||||
|
||||
if (written.length) {
|
||||
console.log('Wrote paginated feeds:', written.join(', '))
|
||||
} else {
|
||||
console.error('No feed files written')
|
||||
}
|
||||
|
||||
// Additionally write a full archive feed with all items
|
||||
function writeFullFeed(feedJson, allItems) {
|
||||
const builder = new XMLBuilder(json2xmlOpts)
|
||||
const feedCopy = JSON.parse(JSON.stringify(feedJson))
|
||||
|
||||
feedCopy.rss = feedCopy.rss || {}
|
||||
feedCopy.rss.channel = feedCopy.rss.channel || {}
|
||||
feedCopy.rss.channel.item = allItems
|
||||
|
||||
// preserve and adapt atom links
|
||||
const origAtom = (feedJson.rss && feedJson.rss.channel && feedJson.rss.channel['atom:link']) || []
|
||||
const origSelf = Array.isArray(origAtom)
|
||||
? (origAtom.find(l => l.__attr && l.__attr.rel === 'self') || {}).__attr
|
||||
: (origAtom && origAtom.__attr) || {}
|
||||
const originalHref = (origSelf && origSelf.href) || ''
|
||||
const base = originalHref.replace(/\/feed(?:-page-\d+)?\.xml$/, '')
|
||||
|
||||
const newAtom = []
|
||||
newAtom.push({ __attr: { href: `${base}/feed-all.xml`, rel: 'self', type: 'application/rss+xml' } })
|
||||
const hub = Array.isArray(origAtom) && origAtom.find(l => l.__attr && l.__attr.rel === 'hub')
|
||||
if (hub) newAtom.push(hub)
|
||||
feedCopy.rss.channel['atom:link'] = newAtom
|
||||
|
||||
const outputXML = builder.build(feedCopy)
|
||||
const validation = XMLValidator.validate(outputXML)
|
||||
if (validation) {
|
||||
const filename = 'dist/feed-all.xml'
|
||||
write(
|
||||
filename,
|
||||
xmlFormat(outputXML, {
|
||||
indentation: json2xmlOpts.indentBy,
|
||||
collapseContent: true
|
||||
})
|
||||
)
|
||||
return filename
|
||||
} else {
|
||||
console.error('XML validation error (feed-all):', validation.err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const allOut = writeFullFeed(feed, items)
|
||||
if (allOut) console.log('Wrote full archive feed:', allOut)
|
||||
|
||||
Reference in New Issue
Block a user