parallel fetches + changed how it works
This commit is contained in:
parent
d22fd1ef9d
commit
cd63571efc
4 changed files with 111 additions and 38 deletions
|
|
@ -1,6 +1,25 @@
|
||||||
{
|
{
|
||||||
|
"Web Development": [
|
||||||
|
"https://hacks.mozilla.org/feed/",
|
||||||
|
"https://blogasdfasdf/",
|
||||||
|
"https://web.dev/feed.xml",
|
||||||
|
"https://v8.dev/blog.atom",
|
||||||
|
"https://alistapart.com/main/feed/",
|
||||||
|
"https://css-tricks.com/feed/",
|
||||||
|
"https://dev.to/feed"
|
||||||
|
],
|
||||||
"Blogs": [
|
"Blogs": [
|
||||||
"https://george.mand.is/feed.json",
|
"https://george.mand.is/feed.xml",
|
||||||
"https://joy.recurse.com/feed.atom"
|
"https://joy.recurse.com/feed.atom"
|
||||||
|
],
|
||||||
|
"My GitHub Projects": [
|
||||||
|
"https://github.com/georgemandis.atom",
|
||||||
|
"https://github.com/georgemandis/bubo-rss/releases.atom",
|
||||||
|
"https://github.com/georgemandis/konami-js/releases.atom",
|
||||||
|
"https://github.com/georgemandis/konami-js/commits/main.atom",
|
||||||
|
"https://github.com/javascriptforartists/cheer-me-up-and-sing-me-a-song/commits/master.atom",
|
||||||
|
"https://github.com/georgemandis/circuit-playground-midi-multi-tool/commits/master.atom",
|
||||||
|
"https://github.com/georgemandis/remote-working-list/commits/master.atom",
|
||||||
|
"https://github.com/georgemandis/tweeter-totter/commits/master.atom"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
17
package-lock.json
generated
17
package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"chalk": "^5.0.0",
|
||||||
"node-fetch": "^3.1.0",
|
"node-fetch": "^3.1.0",
|
||||||
"nunjucks": "^3.2.0",
|
"nunjucks": "^3.2.0",
|
||||||
"rss-parser": "^3.6.3"
|
"rss-parser": "^3.6.3"
|
||||||
|
|
@ -519,6 +520,17 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chalk": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
|
||||||
|
|
@ -2081,6 +2093,11 @@
|
||||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ=="
|
||||||
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "tsc --watch",
|
"dev": "tsc --watch",
|
||||||
"clean": "rm -rf dist",
|
"clean": "rm -rf dist",
|
||||||
"build": "tsc && node dist/index.js > public/index.html",
|
"build": "tsc",
|
||||||
"build:bubo": "node dist/index.js > public/index.html"
|
"start": "node dist/index.js"
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "George Mandis",
|
"name": "George Mandis",
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
},
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"chalk": "^5.0.0",
|
||||||
"node-fetch": "^3.1.0",
|
"node-fetch": "^3.1.0",
|
||||||
"nunjucks": "^3.2.0",
|
"nunjucks": "^3.2.0",
|
||||||
"rss-parser": "^3.6.3"
|
"rss-parser": "^3.6.3"
|
||||||
|
|
@ -35,4 +36,4 @@
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"typescript": "^4.5.2"
|
"typescript": "^4.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
104
src/index.ts
104
src/index.ts
|
|
@ -13,53 +13,89 @@
|
||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
import Parser from "rss-parser";
|
import Parser from "rss-parser";
|
||||||
import { Feeds, FeedItem } from "./@types/bubo";
|
import { Feeds, FeedItem } from "./@types/bubo";
|
||||||
|
import { Response } from "node-fetch";
|
||||||
import { render } from "./renderer.js";
|
import { render } from "./renderer.js";
|
||||||
import { getLink, getTitle, getTimestamp, parseFeed, getFeedList } from "./utilities.js";
|
import { getLink, getTitle, getTimestamp, parseFeed, getFeedList } from "./utilities.js";
|
||||||
|
import { writeFile } from "fs/promises";
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
const parser = new Parser();
|
const parser = new Parser();
|
||||||
const feedList = await getFeedList();
|
const feedList = await getFeedList();
|
||||||
const contentFromAllFeeds: Feeds = {};
|
const contentFromAllFeeds: Feeds = {};
|
||||||
const errors = [];
|
const errors: unknown[] = [];
|
||||||
|
const allFetches = [];
|
||||||
|
|
||||||
|
|
||||||
|
const error = chalk.bold.red;
|
||||||
|
const success = chalk.bold.green;
|
||||||
|
const time = chalk.cyanBright.bold;
|
||||||
|
|
||||||
|
|
||||||
|
// process each feed and its content
|
||||||
|
const processFeed = (
|
||||||
|
{
|
||||||
|
group, feed, startTime
|
||||||
|
}: { group: string; feed: string, startTime: number }
|
||||||
|
) => async (response: Response) => {
|
||||||
|
const body = await parseFeed(response);
|
||||||
|
|
||||||
|
// skip to the next one if this didn't work out
|
||||||
|
if (!body) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const contents: FeedItem =
|
||||||
|
(typeof body === "string" ? (await parser.parseString(body)) : body) as FeedItem;
|
||||||
|
|
||||||
|
contents.feed = feed;
|
||||||
|
contents.title = getTitle(contents);
|
||||||
|
contents.link = getLink(contents);
|
||||||
|
|
||||||
|
// try to normalize date attribute naming
|
||||||
|
contents?.items?.forEach((item) => {
|
||||||
|
item.timestamp = getTimestamp(item);
|
||||||
|
item.title = getTitle(item);
|
||||||
|
item.link = getLink(item);
|
||||||
|
});
|
||||||
|
contentFromAllFeeds[group].push(contents as object);
|
||||||
|
console.log(`${success("Successfully fetched:")} ${feed}`, time(`(${((Date.now() - startTime) / 1000)} seconds)`));
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`${error("Error processing:")} ${feed} (${((Date.now() - startTime) / 1000)} seconds)`);
|
||||||
|
errors.push(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// go through each group of feeds and process them
|
||||||
for (const [group, feeds] of Object.entries(feedList)) {
|
for (const [group, feeds] of Object.entries(feedList)) {
|
||||||
contentFromAllFeeds[group] = [];
|
contentFromAllFeeds[group] = [];
|
||||||
|
|
||||||
for (const feed of feeds) {
|
for (const feed of feeds) {
|
||||||
try {
|
console.log(`Fetching ${feed}...`);
|
||||||
|
const startTime = Date.now();
|
||||||
const response = await fetch(feed);
|
allFetches.push(
|
||||||
const body = await parseFeed(response);
|
fetch(feed).then(processFeed({ group, feed, startTime })).catch(err => {
|
||||||
|
console.log(error(`Error fetching ${feed} (${((Date.now() - startTime) / 1000)} seconds)`));
|
||||||
// skip to the next one if this didn't work out
|
errors.push(`Error fetching ${feed} ${err.toString()}`);
|
||||||
if (!body) continue;
|
})
|
||||||
|
);
|
||||||
const contents: FeedItem =
|
|
||||||
(typeof body === "string" ? (await parser.parseString(body)) : body) as FeedItem;
|
|
||||||
|
|
||||||
contents.feed = feed;
|
|
||||||
contents.title = getTitle(contents);
|
|
||||||
contents.link = getLink(contents);
|
|
||||||
|
|
||||||
// try to normalize date attribute naming
|
|
||||||
contents?.items?.forEach((item) => {
|
|
||||||
item.timestamp = getTimestamp(item);
|
|
||||||
item.title = getTitle(item);
|
|
||||||
item.link = getLink(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
contentFromAllFeeds[group].push(contents as object);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
errors.push(feed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate the static HTML output from our template renderer
|
|
||||||
const output = render({
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
data: contentFromAllFeeds,
|
Promise.all(allFetches).then(async () => {
|
||||||
errors: errors
|
console.log("\nDone fetching everything!");
|
||||||
|
// generate the static HTML output from our template renderer
|
||||||
|
const output = render({
|
||||||
|
data: contentFromAllFeeds,
|
||||||
|
errors: errors
|
||||||
|
});
|
||||||
|
|
||||||
|
// write the output to public/index.html
|
||||||
|
await writeFile("./public/index.html", output);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// return the rendered console and save it somewhere.
|
|
||||||
console.log(output);
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue