/* EL-KADI OPS — live RSS panels (Palantir feed hub) */
(function () {
const FEEDS = {
"Tech News": [
{ name: "Hacker News", url: "https://hnrss.org/frontpage" },
{ name: "Ars Technica", url: "https://feeds.arstechnica.com/arstechnica/index" },
{ name: "The Verge", url: "https://www.theverge.com/rss/index.xml" },
{ name: "Lobsters", url: "https://lobste.rs/rss" },
],
Security: [
{ name: "BleepingComputer", url: "https://www.bleepingcomputer.com/feed/" },
{ name: "Krebs", url: "https://krebsonsecurity.com/feed/" },
{ name: "The Hacker News", url: "https://feeds.feedburner.com/TheHackersNews" },
],
Homelab: [
{ name: "selfh.st", url: "https://selfh.st/rss/" },
{ name: "Proxmox Forum", url: "https://forum.proxmox.com/forums/-/index.rss" },
{ name: "r/selfhosted", url: "https://www.reddit.com/r/selfhosted/.rss" },
{ name: "Docker Blog", url: "https://www.docker.com/blog/feed/" },
{ name: "LinuxServer.io", url: "https://www.linuxserver.io/blog/rss/" },
],
"AI & Dev": [
{ name: "OpenAI Blog", url: "https://openai.com/blog/rss.xml" },
{ name: "Hugging Face", url: "https://huggingface.co/blog/feed.xml" },
{ name: "GitHub Blog", url: "https://github.blog/feed/" },
],
};
const PROXY = "https://api.allorigins.win/raw?url=";
const REFRESH_MS = 15 * 60 * 1000;
function esc(s) {
const d = document.createElement("div");
d.textContent = s || "";
return d.innerHTML;
}
function relTime(pub) {
if (!pub) return "";
const t = new Date(pub).getTime();
if (Number.isNaN(t)) return "";
const m = Math.floor((Date.now() - t) / 60000);
if (m < 60) return `${m}m`;
const h = Math.floor(m / 60);
if (h < 48) return `${h}h`;
return `${Math.floor(h / 24)}d`;
}
async function fetchFeed(feedUrl) {
const res = await fetch(PROXY + encodeURIComponent(feedUrl), { cache: "no-store" });
if (!res.ok) throw new Error("fetch failed");
const xml = new DOMParser().parseFromString(await res.text(), "text/xml");
const items = xml.querySelectorAll("item, entry");
return Array.from(items)
.slice(0, 6)
.map((item) => {
const title =
item.querySelector("title")?.textContent?.trim() ||
item.querySelector("title")?.innerHTML?.trim() ||
"—";
const link =
item.querySelector("link")?.getAttribute("href") ||
item.querySelector("link")?.textContent?.trim() ||
item.querySelector("id")?.textContent?.trim() ||
"#";
const pub =
item.querySelector("pubDate")?.textContent ||
item.querySelector("published")?.textContent ||
item.querySelector("updated")?.textContent;
return { title, link, pub };
});
}
function renderColumn(cat, feeds, root) {
const col = document.createElement("section");
col.className = "rss-column";
col.innerHTML = `