// Utility functions export function generateId(): string { if (typeof crypto !== 'undefined' && crypto.randomUUID) { return crypto.randomUUID(); } // Fallback for environments without crypto return `id_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } export function formatDate(date: Date | string): string { const d = typeof date === 'string' ? new Date(date) : date; return d.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } export function truncateText(text: string, maxLength: number): string { if (text.length <= maxLength) return text; return text.substring(0, maxLength).trim() + '...'; } export function stripHtml(html: string): string { const tmp = document.createElement('div'); tmp.innerHTML = html; return tmp.textContent || tmp.innerText || ''; } export function parseFeedUrl(url: string): { host: string; path: string } | null { try { const parsed = new URL(url); return { host: parsed.hostname, path: parsed.pathname, }; } catch { return null; } } export function guessFeedUrl(baseUrl: string): string[] { const commonFeedPaths = [ '/feed', '/rss', '/rss.xml', '/feed.xml', '/atom.xml', '/atom', '/opml', ]; try { const url = new URL(baseUrl); // Ensure trailing slash for path concatenation const base = url.pathname.endsWith('/') ? url.pathname : `${url.pathname}/`; return commonFeedPaths.map((path) => `${url.origin}${base}${path}`); } catch { return []; } }