/* 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 = `
${esc(cat)}
`; const list = col.querySelector(".rss-list"); root.appendChild(col); feeds.forEach((feed) => { const block = document.createElement("li"); block.className = "rss-feed-block"; block.innerHTML = `${esc(feed.name)}`; list.appendChild(block); const itemsUl = block.querySelector(".rss-items"); fetchFeed(feed.url) .then((items) => { itemsUl.innerHTML = items.length ? items .map( (it) => `
  • ${esc(it.title)}
  • ` ) .join("") : '
  • Geen items
  • '; }) .catch(() => { itemsUl.innerHTML = `
  • Open feed →
  • `; }); }); } function injectHub() { if (document.getElementById("elkadi-rss-hub")) return; const scan = document.createElement("div"); scan.className = "palantir-scanline"; const noise = document.createElement("div"); noise.className = "palantir-noise"; document.body.appendChild(scan); document.body.appendChild(noise); const hub = document.createElement("div"); hub.id = "elkadi-rss-hub"; hub.className = "rss-hub"; hub.innerHTML = '
    INTEL FEEDSLive RSS · vernieuwt elke 15 min
    '; const grid = hub.querySelector(".rss-grid"); Object.entries(FEEDS).forEach(([cat, feeds]) => renderColumn(cat, feeds, grid)); const services = document.getElementById("services"); if (services && services.parentNode) { services.parentNode.insertBefore(hub, services); } else { document.body.prepend(hub); } setInterval(() => { hub.querySelectorAll(".rss-column").forEach((c) => c.remove()); const g = hub.querySelector(".rss-grid"); Object.entries(FEEDS).forEach(([cat, feeds]) => renderColumn(cat, feeds, g)); }, REFRESH_MS); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => setTimeout(injectHub, 400)); } else { setTimeout(injectHub, 400); } })();