// 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 277 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 277 days ago