Support for multiple feeds & viewing individual sources

This commit is contained in:
dakedres 2024-01-10 16:57:35 -05:00
parent 12c815fde3
commit 5c3f804a14
3 changed files with 125 additions and 51 deletions

3
.gitignore vendored
View File

@ -5,3 +5,6 @@ node_modules/
/out/* /out/*
/cache.json /cache.json
/config.js /config.js
# Testing
*.ignore

8
README
View File

@ -2,11 +2,13 @@
┏┓┏┏┏┏┓┏┓┏┓ ┏┓┏┏┏┏┓┏┓┏┓
┛ ┛┛┛┛┗┛┗┗┫ ┛ ┛┛┛┛┗┛┗┗┫
RSS-based art collator Rsssing is an RSS-based feed for art blogs. It generates a series of web pages
to be uploaded to a web server, or simply viewed in the browser. Tumblr and
Twitter (through nitter) sources are supported.
Do not expect quality code. Only works with the Bun[1] runtime | Usage
Rssssing only works with the Bun[1] runtime
Usage
- Run `bun run setup`, `npm run setup`, etc. - Run `bun run setup`, `npm run setup`, etc.
- Add usernames and such to the "feeds" array in config.js - Add usernames and such to the "feeds" array in config.js
- `bun .` - `bun .`

161
index.js
View File

@ -1,5 +1,5 @@
const fetch = require('node-fetch') const fetch = require('node-fetch')
const config = require('./config.js') const config = require('./config.js.ignore')
const Path = require('path') const Path = require('path')
let cache = require('./cache.json') let cache = require('./cache.json')
@ -144,52 +144,60 @@ const processTumblr = (rss, user) => {
const oneDay = 1000 * 60 * 60 * 24 const oneDay = 1000 * 60 * 60 * 24
const print = async feeds => { const printFeed = async (sources, directory, header) => {
// Coalate // Coalate
let masterFeed = [] let feed = []
let tooLongAgo = (Date.now() - (Date.now() % oneDay)) - oneDay * config.tooLongAgo let tooLongAgo = (Date.now() - (Date.now() % oneDay)) - oneDay * config.tooLongAgo
let missingFeeds = 0 let missingSources = 0
for(let feed of feeds) { for(let source of sources) {
if(feed == undefined) { if(source == undefined) {
missingFeeds++ missingSources++
continue continue
} }
for(let post of feed) { for(let post of source) {
if(tooLongAgo && post.date > tooLongAgo) if(tooLongAgo && post.date > tooLongAgo)
masterFeed.push(post) feed.push(post)
} }
} }
masterFeed = masterFeed.sort((a, b) => a.date < b.date) feed = feed.sort((a, b) => a.date < b.date)
if(missingFeeds) { if(missingSources) {
console.log('Missing ' + missingFeeds + ' feeds!') console.log('Missing ' + missingSources + ' feeds!')
} }
// Render // Render
let pages = [] let pages = []
for(let i = 0; i < Math.ceil(masterFeed.length / config.pageSize); i++) { for(let i = 0; i < Math.ceil(feed.length / config.pageSize); i++) {
pages.push(masterFeed.slice(i * config.pageSize, (i + 1) * config.pageSize) ) pages.push(feed.slice(i * config.pageSize, (i + 1) * config.pageSize) )
} }
// Write // Write
console.log('Writing...')
for(let i = 0; i < pages.length; i++) { for(let i = 0; i < pages.length; i++) {
Bun.write('out/' + (i == 0 ? 'index' : i) + '.html', renderPage(pages[i], i, pages.length) ) let nextPage = i + 1
let link = nextPage === pages.length ?
`<a href="data:text/html,">end</a>` :
`<a href="${nextPage}.html">next</a>`
Bun.write(
Path.join(directory, (i == 0 ? 'index' : i) + '.html'),
renderPage(`Page ${i + 1}`, pages[i], header, link)
)
} }
} }
const renderPage = (posts, index, pageCount) => { const renderPage = (title, posts, header, footer) => {
let html = `\ let html = `\
<html> <html>
<head> <head>
<title>Page ${index + 1}</title> <title>${title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<style> <style>
body { body {
@ -217,27 +225,33 @@ const renderPage = (posts, index, pageCount) => {
</style> </style>
</head> </head>
<body>\n` <body>`
if(header) {
html += `
<header>
${header}
</header>
`
}
for(let post of posts) { for(let post of posts) {
let date = new Date(post.date) let date = new Date(post.date)
html += `\ html += `
${post.images.map(renderImage).join('\n')} ${post.images.map(renderImage).join('\n')}
<p><b>${post.user}</b> ${date.getMonth()}/${date.getDate()}/${date.getFullYear()} <a href="${post.link}">open</a></p><hr>\n` <p><b>${post.user}</b> ${date.getMonth()}/${date.getDate()}/${date.getFullYear()} <a href="${post.link}">open</a></p><hr>`
} }
let nextPage = index + 1 if(footer) {
html += `
<footer>
let link = nextPage === pageCount ? ${footer}
`<a href="data:text/html,">end</a>` : </footer>`
`<a href="${nextPage}.html">next</a>` }
html += ` html += `
<footer>
${link}
</footer>
</body> </body>
</html>` </html>`
return html return html
@ -247,30 +261,85 @@ const renderImage = image => `\
<a href="${image}"><img src="${image}" loading="lazy"></img></a>` <a href="${image}"><img src="${image}" loading="lazy"></img></a>`
const main = async () => { const main = async () => {
const feeds = [] let feeds = []
let allSources = []
const subscribe = feedPromise => { for(let feedName in config.feeds) {
return feedPromise let feed = config.feeds[feedName]
.catch(error => { let sources = []
console.error(error)
})
.then(feed => {
feeds.push(feed)
})
}
console.log('Grabbing posts...') const subscribe = (sourcePromise, type, name) =>
for(let user of config.feeds.nitter) { sourcePromise
await subscribe(handleNitterUser(user) ) .catch(error => console.error(error) )
.then(source => {
sources.push(source)
allSources.push({
type,
name,
link: Path.join(type, name),
source
})
})
if(feed.nitter) {
for(let user of feed.nitter) {
await subscribe(handleNitterUser(user), 'nitter', user)
} }
console.log('Caching sources...') console.log('Caching sources...')
Bun.write('cache.json', JSON.stringify(cache, null, 2)) Bun.write('cache.json', JSON.stringify(cache, null, 2))
for(let user of config.feeds.tumblr) {
await subscribe(handleTumblrUser(user) )
} }
await print(feeds) if(feed.tumblr) {
for(let user of feed.tumblr) {
await subscribe(handleTumblrUser(user), 'tumblr', user)
}
}
let link = feed.main ? '' : feedName
feeds.push({
name: feedName,
main: feed.main,
sources,
link
})
}
const buildFeedNav = depth => {
const buildLink = (page, name = page.link) => {
let link = '../'.repeat(depth) + page.link
if(config.linkToIndex)
link += '/index.html'
return `<div><a href="${link}">${name}</a></div>`
}
return `\
<details>
<summary>Feeds</summary>
<section>
${buildLink({ link: '' }, 'main')}
${feeds.filter(feed => !feed.main).map(feed => buildLink(feed)).join('\n')}
<hr>
${allSources.map(source => buildLink(source)).join('\n')}
</section>
</details>
<hr>`
}
console.log('Writing...')
for(let source of allSources) {
console.log(source)
await printFeed([ source.source ], Path.join('out', source.link), buildFeedNav(2))
}
for(let feed of feeds) {
await printFeed(feed.sources, Path.join('out', feed.link), buildFeedNav(feed.main ? 0 : 1))
}
console.log('Done!') console.log('Done!')
} }