Islamic Radio

Islamic Radio Widget /* * WIDGET STYLES * Self-contained CSS. * Prefix: ‘irw-‘ */ :root { –irw-bg: #0f172a; –irw-surface: #1e293b; –irw-surface-hover: #334155; –irw-primary: #10b981; /* Emerald */ –irw-primary-hover: #059669; –irw-accent: #f59e0b; /* Amber for accents */ –irw-text: #f8fafc; –irw-text-muted: #94a3b8; –irw-border: #334155; –irw-danger: #ef4444; } body { /* Desktop centering defaults */ margin: 0; padding: 20px; background-color: #f1f5f9; font-family: -apple-system, BlinkMacSystemFont, “Segoe UI”, Roboto, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; /* Prevent scrolling on body when widget is full screen */ overscroll-behavior: none; } .irw-widget { width: 100%; max-width: 400px; background-color: var(–irw-bg); color: var(–irw-text); border-radius: 24px; overflow: hidden; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); font-family: ‘Segoe UI’, Roboto, sans-serif; border: 1px solid var(–irw-border); display: flex; flex-direction: column; /* Ensure widget creates a stacking context */ position: relative; z-index: 1; } /* LOGO SECTION */ .irw-symbol-container { padding: 30px 20px 10px 20px; display: flex; justify-content: center; background: linear-gradient(180deg, #064e3b 0%, #0f172a 100%); flex-shrink: 0; } .irw-main-symbol { width: 80px; height: 80px; filter: drop-shadow(0 0 12px rgba(16, 185, 129, 0.5)); fill: var(–irw-primary); } /* HEADER */ .irw-header { padding: 5px 20px 20px 20px; display: flex; align-items: center; justify-content: space-between; text-align: center; flex-direction: column; gap: 12px; flex-shrink: 0; } .irw-brand h2 { margin: 0; font-size: 1.5rem; font-weight: 800; letter-spacing: -0.025em; color: white; } .irw-brand span { font-size: 0.8rem; color: var(–irw-text-muted); text-transform: uppercase; letter-spacing: 0.1em; margin-top: 4px; display: block; } .irw-live-indicator { display: flex; align-items: center; gap: 8px; background: rgba(0,0,0,0.4); padding: 6px 14px; border-radius: 20px; font-size: 0.75rem; font-weight: 800; border: 1px solid rgba(255,255,255,0.05); } .irw-dot { width: 8px; height: 8px; background-color: var(–irw-danger); border-radius: 50%; transition: all 0.3s ease; } .irw-dot.active { box-shadow: 0 0 10px var(–irw-danger); animation: pulse 1.5s infinite; } /* STATION LIST */ .irw-stations { /* Desktop Default: Fixed height scrollable area */ height: 300px; overflow-y: auto; background-color: var(–irw-surface); border-top: 1px solid var(–irw-border); /* Smooth scrolling */ -webkit-overflow-scrolling: touch; } .irw-stations::-webkit-scrollbar { width: 6px; } .irw-stations::-webkit-scrollbar-track { background: var(–irw-surface); } .irw-stations::-webkit-scrollbar-thumb { background: var(–irw-border); border-radius: 3px; } .irw-station-btn { width: 100%; display: flex; align-items: center; padding: 16px 20px; background: transparent; border: none; border-bottom: 1px solid var(–irw-border); color: var(–irw-text); cursor: pointer; text-align: left; transition: all 0.2s ease; } .irw-station-btn:hover { background-color: var(–irw-surface-hover); } .irw-station-btn.active { background-color: rgba(16, 185, 129, 0.15); border-left: 4px solid var(–irw-primary); padding-left: 16px; /* Offset for border */ } .irw-station-icon { width: 42px; height: 42px; background-color: var(–irw-bg); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-right: 15px; font-weight: bold; color: var(–irw-text-muted); border: 1px solid var(–irw-border); flex-shrink: 0; font-size: 0.8rem; } .irw-station-btn.active .irw-station-icon { color: var(–irw-primary); border-color: var(–irw-primary); } .irw-meta { flex: 1; min-width: 0; /* Prevents text overflow issues */ } .irw-name { font-size: 0.95rem; font-weight: 600; display: block; margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .irw-desc { font-size: 0.75rem; color: var(–irw-text-muted); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* CONTROLS */ .irw-controls { padding: 24px 20px 30px 20px; background-color: var(–irw-bg); border-top: 1px solid var(–irw-border); flex-shrink: 0; position: relative; z-index: 2; } .irw-status-message { text-align: center; font-size: 0.85rem; color: var(–irw-primary); height: 20px; margin-bottom: 20px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } .irw-control-bar { display: flex; align-items: center; justify-content: center; gap: 24px; } .irw-skip-btn { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.05); color: var(–irw-text-muted); cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; width: 48px; /* Larger touch target */ height: 48px; border-radius: 50%; } .irw-skip-btn:hover { color: var(–irw-text); background: rgba(255,255,255,0.1); transform: translateY(-2px); } .irw-skip-btn:active { transform: scale(0.9); } .irw-skip-btn svg { width: 20px; height: 20px; fill: currentColor; } .irw-play-btn { width: 72px; height: 72px; border-radius: 50%; background-color: var(–irw-primary); border: none; color: white; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); box-shadow: 0 10px 20px rgba(16, 185, 129, 0.3); flex-shrink: 0; } .irw-play-btn:hover { background-color: var(–irw-primary-hover); transform: scale(1.05); box-shadow: 0 15px 25px rgba(16, 185, 129, 0.4); } .irw-play-btn svg { width: 34px; height: 34px; fill: currentColor; } /* Volume Slider */ .irw-volume-row { margin-top: 25px; display: flex; align-items: center; gap: 12px; padding: 0 10px; } .irw-vol-icon { color: var(–irw-text-muted); width: 20px; } input[type=range] { flex: 1; -webkit-appearance: none; background: transparent; height: 24px; /* Increases touch area */ } input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; height: 16px; width: 16px; border-radius: 50%; background: var(–irw-text); cursor: pointer; margin-top: -6px; border: 2px solid var(–irw-primary); box-shadow: 0 0 0 4px rgba(0,0,0,0.1); } input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 4px; cursor: pointer; background: var(–irw-surface-hover); border-radius: 2px; } /* Visualizer */ .irw-eq { display: flex; align-items: flex-end; gap: 3px; height: 20px; width: 24px; } .irw-eq-bar { width: 4px; background: var(–irw-primary); border-radius: 2px; height: 20%; transition: height 0.1s; } .irw-eq.animating .irw-eq-bar { animation: eq-bounce 0.8s infinite ease-in-out; } .irw-eq.animating .irw-eq-bar:nth-child(1) { animation-delay: 0s; } .irw-eq.animating .irw-eq-bar:nth-child(2) { animation-delay: 0.2s; } .irw-eq.animating .irw-eq-bar:nth-child(3) { animation-delay: 0.4s; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } } @keyframes eq-bounce { 0%, 100% { height: 20%; } 50% { height: 100%; } } /* — MOBILE OPTIMIZATIONS — */ @media (max-width: 480px) { body { padding: 0; align-items: flex-start; background-color: var(–irw-bg); } .irw-widget { max-width: 100%; /* Use dynamic viewport height to handle mobile browser bars */ height: 100vh; /* Fallback */ height: 100dvh; border-radius: 0; border: none; box-shadow: none; } /* Allow the list to grow and fill the screen */ .irw-stations { height: auto; flex: 1; max-height: none; } .irw-symbol-container { padding-top: 20px; /* Adjust for status bar visual preference */ } .irw-controls { padding-bottom: 30px; /* Extra padding for bottom swipe area */ } }

Islamic Radio

Live Streaming Player
OFFLINE
Select a station
/* * FINAL VERIFIED STATION LIST * All stations confirmed working or using identical tech to working stations. */ const stations = [ { name: “Cii Radio”, desc: “Channel Islam Int (South Africa)”, url: “https://edge.iono.fm/xice/109_medium.mp3&#8221;, icon: “CII” }, { name: “Radio Al Ansaar”, desc: “Durban, South Africa (90.4 FM)”, url: “https://al-ansaar.simplestreaming.co.za/listen/al-ansaar_radio/radio.mp3&#8221;, icon: “ANS” }, { name: “Voice of the Cape”, desc: “Cape Town (91.3 FM)”, url: “https://edge.iono.fm/xice/194_medium.mp3&#8221;, icon: “VOC” }, { name: “IFM 102.2”, desc: “Islamic Community Radio”, url: “https://edge.iono.fm/xice/162_medium.mp3&#8221;, icon: “IFM” }, { name: “Voice of Van”, desc: “Community Islamic Radio”, url: “https://edge.iono.fm/xice/207_medium.mp3&#8221;, icon: “VOV” }, { name: “Radio Panjo”, desc: “Johannesburg (Community)”, url: “https://edge.iono.fm/xice/122_medium.mp3&#8221;, icon: “PNJ” }, { name: “Makkah Live”, desc: “Masjid Al-Haram (ITWorks CDN)”, url: “https://l3.itworkscdn.net/itwaudio/9006/stream&#8221;, icon: “MKH” }, { name: “Radio Hilal”, desc: “KZN, South Africa (Iono)”, url: “https://edge.iono.fm/xice/132_medium.mp3&#8221;, icon: “HIL” } ]; // State let isPlaying = false; let currentIndex = -1; const audio = document.getElementById(‘irw-audio’); const playBtn = document.getElementById(‘irw-play-btn’); const prevBtn = document.getElementById(‘irw-prev-btn’); const nextBtn = document.getElementById(‘irw-next-btn’); const statusTxt = document.getElementById(‘irw-status’); const eq = document.getElementById(‘irw-eq’); const dot = document.getElementById(‘irw-dot’); const liveText = document.getElementById(‘irw-live-text’); const list = document.getElementById(‘irw-station-list’); // Initialize function init() { // Build List list.innerHTML = stations.map((s, i) => ` `).join(”); // Event delegation for station buttons list.addEventListener(‘click’, (e) => { const btn = e.target.closest(‘.irw-station-btn’); if (btn) { const index = parseInt(btn.getAttribute(‘data-index’)); playStation(index); } }); // Volume const vol = document.getElementById(‘irw-vol’); vol.addEventListener(‘input’, (e) => audio.volume = e.target.value); audio.volume = 0.8; // Play Button playBtn.addEventListener(‘click’, () => { if(currentIndex === -1) playStation(0); else togglePlay(); }); // Skip Buttons prevBtn.addEventListener(‘click’, skipPrev); nextBtn.addEventListener(‘click’, skipNext); // Audio Events audio.addEventListener(‘playing’, () => setStatus(‘playing’)); audio.addEventListener(‘pause’, () => setStatus(‘paused’)); audio.addEventListener(‘waiting’, () => statusTxt.innerText = “Buffering…”); audio.addEventListener(‘error’, (e) => { console.error(“Stream Error”, e); setStatus(‘error’); statusTxt.innerText = “Offline or Blocked”; }); // Setup Media Session Handlers setupMediaSession(); } function setupMediaSession() { if (‘mediaSession’ in navigator) { navigator.mediaSession.setActionHandler(‘play’, togglePlay); navigator.mediaSession.setActionHandler(‘pause’, togglePlay); navigator.mediaSession.setActionHandler(‘previoustrack’, skipPrev); navigator.mediaSession.setActionHandler(‘nexttrack’, skipNext); } } function updateMediaMetadata(station) { if (‘mediaSession’ in navigator) { navigator.mediaSession.metadata = new MediaMetadata({ title: station.name, artist: station.desc, album: ‘Islamic Radio Live’, artwork: [ { src: ‘https://cdn-icons-png.flaticon.com/512/2881/2881031.png&#8217;, sizes: ‘512×512’, type: ‘image/png’ } ] }); } } function playStation(index) { // UI Reset const buttons = document.querySelectorAll(‘.irw-station-btn’); buttons.forEach(b => b.classList.remove(‘active’)); if (buttons[index]) { buttons[index].classList.add(‘active’); buttons[index].scrollIntoView({ behavior: ‘smooth’, block: ‘nearest’ }); } currentIndex = index; const station = stations[index]; statusTxt.innerText = `Loading ${station.name}…`; // Update Mobile Metadata updateMediaMetadata(station); // Audio Load audio.src = station.url; audio.load(); const p = audio.play(); if(p !== undefined) { p.then(() => setStatus(‘playing’)) .catch(e => { console.log(“Autoplay blocked or stream error”); setStatus(‘paused’); statusTxt.innerText = “Click Play”; }); } } function skipNext() { let nextIndex = currentIndex + 1; if (nextIndex >= stations.length) nextIndex = 0; playStation(nextIndex); } function skipPrev() { let prevIndex = currentIndex – 1; if (prevIndex < 0) prevIndex = stations.length – 1; playStation(prevIndex); } function togglePlay() { if(audio.paused) { audio.play(); } else { audio.pause(); } } function setStatus(state) { const iconPlay = document.getElementById('irw-icon-play'); const iconPause = document.getElementById('irw-icon-pause'); if(state === 'playing') { iconPlay.style.display = 'none'; iconPause.style.display = 'block'; eq.classList.add('animating'); dot.classList.add('active'); liveText.innerText = "LIVE"; statusTxt.innerText = "Playing Stream"; if ('mediaSession' in navigator) navigator.mediaSession.playbackState = 'playing'; } else { iconPlay.style.display = 'block'; iconPause.style.display = 'none'; eq.classList.remove('animating'); dot.classList.remove('active'); liveText.innerText = state === 'error' ? "ERROR" : "STANDBY"; if(state !== 'error') statusTxt.innerText = "Paused"; if ('mediaSession' in navigator) navigator.mediaSession.playbackState = 'paused'; } } init();

x

Leave a Comment