Support for multiple feeds & viewing individual sources
This commit is contained in:
parent
12c815fde3
commit
5c3f804a14
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@ node_modules/
|
|||||||
/out/*
|
/out/*
|
||||||
/cache.json
|
/cache.json
|
||||||
/config.js
|
/config.js
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
*.ignore
|
8
README
8
README
@ -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
161
index.js
@ -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!')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user