From f478b059b3da15d61a8ebcd5b697da43bd25eecd Mon Sep 17 00:00:00 2001 From: Pas <74743263+Pasithea0@users.noreply.github.com> Date: Sun, 3 Aug 2025 12:47:08 -0600 Subject: [PATCH] use proxied fetcher for rss! --- .../components/NotificationModal.tsx | 122 ++++++++---------- .../hooks/useNotifications.ts | 106 +++++++-------- .../notificationsModal/utils/index.ts | 22 +++- 3 files changed, 117 insertions(+), 133 deletions(-) diff --git a/src/components/overlays/notificationsModal/components/NotificationModal.tsx b/src/components/overlays/notificationsModal/components/NotificationModal.tsx index 74ad4f83..d07b2ed9 100644 --- a/src/components/overlays/notificationsModal/components/NotificationModal.tsx +++ b/src/components/overlays/notificationsModal/components/NotificationModal.tsx @@ -8,11 +8,11 @@ import { SettingsView } from "./SettingsView"; import { FancyModal } from "../../Modal"; import { ModalView, NotificationItem, NotificationModalProps } from "../types"; import { + fetchRssFeed, formatDate, getAllFeeds, getCategoryColor, getCategoryLabel, - getFetchUrl, getSourceName, } from "../utils"; @@ -111,79 +111,61 @@ export function NotificationModal({ id }: NotificationModalProps) { if (!feedUrl.trim()) continue; try { - const fetchUrl = getFetchUrl(feedUrl); - const response = await fetch(fetchUrl); - if (response.ok) { - const responseText = await response.text(); + const xmlText = await fetchRssFeed(feedUrl); - // Handle CORS proxy response (JSON wrapper) - let xmlText = responseText; - try { - const jsonResponse = JSON.parse(responseText); - if (jsonResponse.contents) { - xmlText = jsonResponse.contents; - } - } catch { - // If it's not JSON, assume it's direct XML - xmlText = responseText; - } + // Basic validation that we got XML content + if ( + xmlText && + (xmlText.includes(" 0) { + items.forEach((item) => { + try { + const guid = item.querySelector("guid")?.textContent || ""; + const title = + item.querySelector("title")?.textContent || ""; + const link = item.querySelector("link")?.textContent || ""; + const description = + item.querySelector("description")?.textContent || ""; + const pubDate = + item.querySelector("pubDate")?.textContent || ""; + const category = + item.querySelector("category")?.textContent || ""; - // Check for parsing errors - const parserError = xmlDoc.querySelector("parsererror"); - if (!parserError && xmlDoc && xmlDoc.documentElement) { - const items = xmlDoc.querySelectorAll("item"); - if (items && items.length > 0) { - items.forEach((item) => { - try { - const guid = - item.querySelector("guid")?.textContent || ""; - const title = - item.querySelector("title")?.textContent || ""; - const link = - item.querySelector("link")?.textContent || ""; - const description = - item.querySelector("description")?.textContent || ""; - const pubDate = - item.querySelector("pubDate")?.textContent || ""; - const category = - item.querySelector("category")?.textContent || ""; - - // Skip items without essential data - if (!guid || !title) { - return; - } - - // Parse the publication date - const notificationDate = new Date(pubDate); - - allNotifications.push({ - guid, - title, - link, - description, - pubDate, - category, - source: getSourceName(feedUrl), - }); - - // Collect GUIDs of notifications older than autoReadDays - if (notificationDate <= autoReadDate) { - autoReadGuids.push(guid); - } - } catch (itemError) { - // Skip malformed items - console.warn("Skipping malformed RSS item:", itemError); + // Skip items without essential data + if (!guid || !title) { + return; } - }); - } + + // Parse the publication date + const notificationDate = new Date(pubDate); + + allNotifications.push({ + guid, + title, + link, + description, + pubDate, + category, + source: getSourceName(feedUrl), + }); + + // Collect GUIDs of notifications older than autoReadDays + if (notificationDate <= autoReadDate) { + autoReadGuids.push(guid); + } + } catch (itemError) { + // Skip malformed items + console.warn("Skipping malformed RSS item:", itemError); + } + }); } } } diff --git a/src/components/overlays/notificationsModal/hooks/useNotifications.ts b/src/components/overlays/notificationsModal/hooks/useNotifications.ts index f66d4456..9cdf7702 100644 --- a/src/components/overlays/notificationsModal/hooks/useNotifications.ts +++ b/src/components/overlays/notificationsModal/hooks/useNotifications.ts @@ -3,7 +3,7 @@ import { useEffect, useState } from "react"; import { useOverlayStack } from "@/stores/interface/overlayStack"; import { NotificationItem } from "../types"; -import { getAllFeeds, getFetchUrl, getSourceName } from "../utils"; +import { fetchRssFeed, getAllFeeds, getSourceName } from "../utils"; // Hook to manage notifications export function useNotifications() { @@ -25,70 +25,54 @@ export function useNotifications() { if (!feedUrl.trim()) continue; try { - const fetchUrl = getFetchUrl(feedUrl); - const response = await fetch(fetchUrl); - if (response.ok) { - const responseText = await response.text(); + const xmlText = await fetchRssFeed(feedUrl); - // Handle CORS proxy response (JSON wrapper) - let xmlText = responseText; - try { - const jsonResponse = JSON.parse(responseText); - if (jsonResponse.contents) { - xmlText = jsonResponse.contents; - } - } catch { - // If it's not JSON, assume it's direct XML - xmlText = responseText; - } + // Basic validation that we got XML content + if ( + xmlText && + (xmlText.includes(" 0) { + items.forEach((item) => { + try { + const guid = + item.querySelector("guid")?.textContent || ""; + const title = + item.querySelector("title")?.textContent || ""; + const link = + item.querySelector("link")?.textContent || ""; + const description = + item.querySelector("description")?.textContent || ""; + const pubDate = + item.querySelector("pubDate")?.textContent || ""; + const category = + item.querySelector("category")?.textContent || ""; - // Check for parsing errors - const parserError = xmlDoc.querySelector("parsererror"); - if (!parserError && xmlDoc && xmlDoc.documentElement) { - const items = xmlDoc.querySelectorAll("item"); - if (items && items.length > 0) { - items.forEach((item) => { - try { - const guid = - item.querySelector("guid")?.textContent || ""; - const title = - item.querySelector("title")?.textContent || ""; - const link = - item.querySelector("link")?.textContent || ""; - const description = - item.querySelector("description")?.textContent || ""; - const pubDate = - item.querySelector("pubDate")?.textContent || ""; - const category = - item.querySelector("category")?.textContent || ""; - - // Skip items without essential data - if (!guid || !title) { - return; - } - - allNotifications.push({ - guid, - title, - link, - description, - pubDate, - category, - source: getSourceName(feedUrl), - }); - } catch (itemError) { - // Skip malformed items silently + // Skip items without essential data + if (!guid || !title) { + return; } - }); - } + + allNotifications.push({ + guid, + title, + link, + description, + pubDate, + category, + source: getSourceName(feedUrl), + }); + } catch (itemError) { + // Skip malformed items silently + } + }); } } } diff --git a/src/components/overlays/notificationsModal/utils/index.ts b/src/components/overlays/notificationsModal/utils/index.ts index e509309b..8641a027 100644 --- a/src/components/overlays/notificationsModal/utils/index.ts +++ b/src/components/overlays/notificationsModal/utils/index.ts @@ -1,5 +1,6 @@ +import { proxiedFetch } from "@/backend/helpers/fetch"; + const DEFAULT_FEEDS = ["/notifications.xml"]; -// const CORS_PROXY = "http://api.allorigins.win/get?url="; // temporarily disabled export const getAllFeeds = (): string[] => { try { @@ -18,7 +19,24 @@ export const getFetchUrl = (feedUrl: string): string => { if (feedUrl.startsWith("/")) { return feedUrl; } - return feedUrl; // return `${CORS_PROXY}${encodeURIComponent(feedUrl)}`; + return feedUrl; +}; + +// New function to fetch RSS feeds using proxiedFetch +export const fetchRssFeed = async (feedUrl: string): Promise => { + if (feedUrl.startsWith("/")) { + // For local feeds, use regular fetch + const response = await fetch(feedUrl); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.text(); + } + // For external feeds, use proxiedFetch + const response = await proxiedFetch(feedUrl, { + responseType: "text", + }); + return response as string; }; export const getSourceName = (feedUrl: string): string => {