// Based on https://hub.windmill.dev/scripts/RSS/1529/rss-feed-fetcher-RSS#1536
import * as wmill from "https://deno.land/x/windmill@v1.85.0/mod.ts";
import { parse } from "https://deno.land/x/xml/mod.ts";
type Rss = {
url: string;
};
type Item = {
title: string;
link: string;
date: Date;
};
type FeedState = {
date: Date | undefined;
link: string | undefined;
title: string | undefined;
};
export async function main(
rssFeed: Rss,
byDate: boolean = true,
byLink: boolean = false,
byTitle: boolean = false,
clearState: boolean = false,
) {
const state = (await wmill.getInternalState()) || {};
const feedState: FeedState = clearState ? {} : state[rssFeed.url] || {};
if (!byDate) {
feedState.date = undefined;
}
if (!byLink) {
feedState.link = undefined;
}
if (!byTitle) {
feedState.title = undefined;
}
const items = await fetch(rssFeed.url)
.then((response) => response.text())
.then((str) => parse(str))
.then((feed) => {
let items = [];
if (feed["rss"]) {
items = rss2Items(feed);
} else if (feed["feed"]) {
items = atomItems(feed);
}
return newItemFilter(items, feedState);
});
if (items.length > 0) {
const newFeedState: FeedState = {
date: byDate
? new Date(Math.max(...items.map((item) => item.date.getTime())))
: undefined,
link: byLink ? items[0].link : undefined,
title: byTitle ? items[0].title : undefined,
};
state[rssFeed.url] = newFeedState;
await wmill.setInternalState(state);
}
return items.reverse();
}
function rss2Items(feed): Array<Item> {
let items = feed["rss"]["channel"]["item"] || [];
if (items.length === "undefined") {
// Single entry
items = [items];
}
return items.map((item) => ({
title: item.title,
link: item.link,
date: new Date(item.pubDate),
}));
}
function atomItems(feed): Array<Item> {
let items = feed["feed"]["entry"] || [];
if (items.length === "undefined") {
// Single entry
items = [items];
}
return items.map((item) => ({
title: typeof item.title === "string" ? item.title : item.title["#text"],
link: item.link instanceof Array
? item.link[0]["@href"]
: item.link["@href"],
date: new Date(item.updated),
}));
}
function newItemFilter(items: Array<Item>, state: FeedState): Array<Item> {
if (state.date && state.date.getTime() > 0) {
const date = state.date;
items = items.filter((item) => item.date > date);
}
if (state.link) {
const link = state.link;
const index = items.findIndex((item) => item.link === link);
if (index >= 0) {
items = items.slice(0, index);
}
}
if (state.title) {
const title = state.title;
const index = items.findIndex((item) => item.title === title);
if (index >= 0) {
items = items.slice(0, index);
}
}
return items;
}
Submitted by gabrielius.m896 23 days ago
import * as wmill from "https://deno.land/x/windmill@v1.85.0/mod.ts";
import { parse } from "https://deno.land/x/xml/mod.ts";
type Rss = {
url: string;
};
type Item = {
title: string;
link: string;
date: Date;
};
type FeedState = {
date: Date | undefined;
link: string | undefined;
title: string | undefined;
};
export async function main(
rssFeed: Rss,
byDate: boolean = true,
byLink: boolean = false,
byTitle: boolean = false,
clearState: boolean = false,
) {
const state = (await wmill.getInternalState()) || {};
const feedState: FeedState = clearState ? {} : state[rssFeed.url] || {};
if (!byDate) {
feedState.date = undefined;
}
if (!byLink) {
feedState.link = undefined;
}
if (!byTitle) {
feedState.title = undefined;
}
const items = await fetch(rssFeed.url)
.then((response) => response.text())
.then((str) => parse(str))
.then((feed) => {
let items = [];
if (feed["rss"]) {
items = rss2Items(feed);
} else if (feed["feed"]) {
items = atomItems(feed);
}
return newItemFilter(items, feedState);
});
if (items.length > 0) {
const newFeedState: FeedState = {
date: byDate
? new Date(Math.max(...items.map((item) => item.date.getTime())))
: undefined,
link: byLink ? items[0].link : undefined,
title: byTitle ? items[0].title : undefined,
};
state[rssFeed.url] = newFeedState;
await wmill.setInternalState(state);
}
return items.reverse();
}
function rss2Items(feed): Array<Item> {
let items = feed["rss"]["channel"]["item"] || [];
if (items.length === "undefined") {
// Single entry
items = [items];
}
return items.map((item) => ({
title: item.title,
link: item.link,
date: new Date(item.pubDate),
}));
}
function atomItems(feed): Array<Item> {
let items = feed["feed"]["entry"] || [];
if (items.length === "undefined") {
// Single entry
items = [items];
}
return items.map((item) => ({
title: typeof item.title === "string" ? item.title : item.title["#text"],
link: item.link instanceof Array
? item.link[0]["@href"]
: item.link["@href"],
date: new Date(item.updated),
}));
}
function newItemFilter(items: Array<Item>, state: FeedState): Array<Item> {
if (state.date && state.date.getTime() > 0) {
const date = state.date;
items = items.filter((item) => item.date > date);
}
if (state.link) {
const link = state.link;
const index = items.findIndex((item) => item.link === link);
if (index >= 0) {
items = items.slice(0, index);
}
}
if (state.title) {
const title = state.title;
const index = items.findIndex((item) => item.title === title);
if (index >= 0) {
items = items.slice(0, index);
}
}
return items;
}
Submitted by gabrielius.m896 23 days ago