mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 17:55:33 +00:00
use proxied fetcher for rss!
This commit is contained in:
parent
a1366a99d0
commit
f478b059b3
3 changed files with 117 additions and 133 deletions
|
|
@ -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("<rss") || xmlText.includes("<feed"))
|
||||
) {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
||||
|
||||
// Basic validation that we got XML content
|
||||
if (
|
||||
xmlText &&
|
||||
(xmlText.includes("<rss") || xmlText.includes("<feed"))
|
||||
) {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
||||
// 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 || "";
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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("<rss") || xmlText.includes("<feed"))
|
||||
) {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
||||
|
||||
// Basic validation that we got XML content
|
||||
if (
|
||||
xmlText &&
|
||||
(xmlText.includes("<rss") || xmlText.includes("<feed"))
|
||||
) {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
||||
// 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 || "";
|
||||
|
||||
// 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
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string> => {
|
||||
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 => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue