1/** 2 * News Feed - Fetches and displays RSS news about Nusrat Fateh Ali Khan 3 * Uses rss2json.com API for RSS-to-JSON conversion 4 */ 5 6(function() { 7 'use strict'; 8 9 const NEWS_CONFIG = { 10 // Google News RSS for NFAK 11 rssUrl: 'https://news.google.com/rss/search?q=nusrat+fateh+ali+khan&hl=en-US&gl=US&ceid=US:en', 12 // RSS2JSON API endpoint (free tier - no API key needed for basic use) 13 apiEndpoint: 'https://api.rss2json.com/v1/api.json', 14 maxItems: 6 15 }; 16 17 // Fallback news items if API fails 18 const FALLBACK_NEWS = [ 19 { 20 title: "Nusrat Fateh Ali Khan's Legacy Continues to Inspire Artists Worldwide", 21 link: "/blog/", 22 pubDate: new Date().toISOString(), 23 source: "NusratOnline" 24 }, 25 { 26 title: "Remembering the King of Qawwali on His Birth Anniversary", 27 link: "/legacy/", 28 pubDate: new Date().toISOString(), 29 source: "NusratOnline" 30 }, 31 { 32 title: "How NFAK's Music Transcends Borders and Generations", 33 link: "/articles/", 34 pubDate: new Date().toISOString(), 35 source: "NusratOnline" 36 } 37 ]; 38 39 /** 40 * Format date to readable string 41 */ 42 function formatDate(dateString) { 43 try { 44 const date = new Date(dateString); 45 const options = { year: 'numeric', month: 'short', day: 'numeric' }; 46 return date.toLocaleDateString('en-US', options); 47 } catch (e) { 48 return ''; 49 } 50 } 51 52 /** 53 * Extract source/domain from URL 54 */ 55 function extractSource(url) { 56 try { 57 const hostname = new URL(url).hostname; 58 return hostname.replace('www.', '').split('.')[0]; 59 } catch (e) { 60 return 'News'; 61 } 62 } 63 64 /** 65 * Create HTML for a news item 66 */ 67 function createNewsItemHTML(item) { 68 const title = item.title || 'Untitled'; 69 const link = item.link || '#'; 70 const date = formatDate(item.pubDate); 71 const source = item.source || extractSource(link); 72 73 return ` 74 <a href="${link}" class="news-card" target="_blank" rel="noopener"> 75 <span class="news-source">${source}</span> 76 <h4 class="news-title">${title}</h4> 77 <span class="news-date">${date}</span> 78 </a> 79 `; 80 } 81 82 /** 83 * Render news items to the container 84 */ 85 function renderNews(items, container) { 86 if (!container) return; 87 88 const html = items.slice(0, NEWS_CONFIG.maxItems) 89 .map(createNewsItemHTML) 90 .join(''); 91 92 container.innerHTML = html; 93 } 94 95 /** 96 * Show loading state 97 */ 98 function showLoading(container) { 99 if (!container) return; 100 container.innerHTML = ` 101 <div class="news-loading"> 102 <p>Loading latest news...</p> 103 </div> 104 `; 105 } 106 107 /** 108 * Fetch news from RSS feed 109 */ 110 async function fetchNews() { 111 const container = document.getElementById('news-feed-container'); 112 if (!container) return; 113 114 showLoading(container); 115 116 try { 117 const apiUrl = `${NEWS_CONFIG.apiEndpoint}?rss_url=${encodeURIComponent(NEWS_CONFIG.rssUrl)}`; 118 const response = await fetch(apiUrl); 119 120 if (!response.ok) { 121 throw new Error('Failed to fetch news'); 122 } 123 124 const data = await response.json(); 125 126 if (data.status === 'ok' && data.items && data.items.length > 0) { 127 renderNews(data.items, container); 128 } else { 129 // Use fallback if no items 130 renderNews(FALLBACK_NEWS, container); 131 } 132 } catch (error) { 133 console.warn('News feed error, using fallback:', error); 134 renderNews(FALLBACK_NEWS, container); 135 } 136 } 137 138 // Initialize when DOM is ready 139 if (document.readyState === 'loading') { 140 document.addEventListener('DOMContentLoaded', fetchNews); 141 } else { 142 fetchNews(); 143 } 144})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.