
{"id":730,"date":"2026-03-18T22:46:17","date_gmt":"2026-03-18T21:46:17","guid":{"rendered":"https:\/\/feflavisalsa.com\/?page_id=730"},"modified":"2026-03-19T00:04:26","modified_gmt":"2026-03-18T23:04:26","slug":"radio-kln","status":"publish","type":"page","link":"https:\/\/feflavisalsa.com\/index.php\/radio-kln\/","title":{"rendered":"radio kln"},"content":{"rendered":"\n<!doctype html>\n<html lang=\"es\">\n<head>\n  <meta charset=\"utf-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\" \/>\n  <title>feflavisalsa &#8211; Embed Player<\/title>\n  <style>\n    :root{\n      --bg:#808000; \/* requested background color *\/\n      --card:#ffffff;\n      --accent:#3aa76a;\n      --muted:#3f6b53;\n      --glass: rgba(0,0,0,0.04);\n    }\n    *{box-sizing:border-box;font-family:Inter, system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial;}\n    html,body{height:100%;margin:0;background:var(--bg);color:#072a3b;-webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;overflow:hidden;}\n    #player{height:100%;display:flex;align-items:center;justify-content:center;padding:20px;}\n    .card{width:100%;max-width:520px;background:var(--card);border-radius:14px;padding:16px;box-shadow:0 8px 30px rgba(8,34,56,0.12);border:1px solid rgba(6,30,46,0.06);}\n    .header{display:flex;gap:12px;align-items:center;}\n    .logo{width:56px;height:56px;border-radius:10px;display:flex;align-items:center;justify-content:center;overflow:hidden;background:transparent;box-shadow:0 2px 6px rgba(0,0,0,0.06);}\n    .logo img{width:100%;height:100%;object-fit:cover;display:block;}\n    .meta{flex:1;min-width:0;}\n    .title{font-size:18px;font-weight:600;margin-bottom:4px;color:var(--accent);}\n    .status{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:13px;}\n    .live{width:10px;height:10px;border-radius:50%;display:inline-block;}\n    .live.offline{background:#a0b3bd;}\n    .live.online{background:var(--accent);box-shadow:0 0 8px rgba(30,144,255,0.2);}\n    .controls{display:flex;align-items:center;gap:8px;margin-top:12px;}\n    .btn{background:var(--glass);border:1px solid rgba(6,30,46,0.06);color:inherit;padding:10px 12px;border-radius:10px;font-size:16px;min-width:44px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;}\n    .btn.large{font-size:20px;padding:14px 16px;border-radius:12px;}\n    .btn:active{transform:translateY(1px);}\n    .vol{flex:1;display:flex;align-items:center;justify-content:flex-end;}\n    input[type=range]{width:140px;}\n    .info{margin-top:12px;}\n    .track{margin-top:8px;font-size:13px;}\n    .track-title{font-weight:600;color:var(--muted);max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\n    .track-sub{font-size:12px;color:rgba(7,42,59,0.7);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\n    .bar{width:100%;height:8px;background:rgba(6,30,46,0.04);border-radius:8px;overflow:hidden;position:relative;}\n    .fill{height:100%;width:0%;background:linear-gradient(90deg,#7fd1ff,#1e90ff);transition:width 220ms linear;}\n    .conn{margin-top:8px;font-size:13px;color:var(--muted);}\n    .footer{margin-top:12px;text-align:right;color:var(--muted);font-size:12px;}\n    @media (max-width:420px){\n      .card{padding:12px;border-radius:10px;}\n      .logo{width:48px;height:48px;font-size:18px;}\n      .btn.large{padding:12px 14px;}\n      input[type=range]{width:110px;}\n    }\n    \/* make iframe content fill available area *\/\n    html,body,#player{height:100%}\n  <\/style>\n<\/head>\n<body>\n  <main id=\"player\" role=\"application\">\n    <div class=\"card\">\n      <div class=\"header\">\n        <div class=\"logo\" aria-hidden=\"true\">\n          <img decoding=\"async\" src=\"https:\/\/feflavisalsa.com\/wp-content\/uploads\/2024\/08\/nuevo-2-512-x-512.png\" alt=\"feflavisalsa logo\" \/>\n        <\/div>\n        <div class=\"meta\">\n          <div class=\"title\">feflavisalsa<\/div>\n          <div class=\"status\">\n            <span id=\"liveDot\" class=\"live offline\" aria-hidden=\"true\"><\/span>\n            <span id=\"statusText\">Desconectado<\/span>\n          <\/div>\n          <div class=\"track\" aria-live=\"polite\">\n            <div id=\"trackTitle\" class=\"track-title\">\u2014<\/div>\n            <div id=\"trackMeta\" class=\"track-sub\">\u2014<\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"controls\">\n        <button id=\"playBtn\" class=\"btn large\" aria-label=\"Play\">\u25b6<\/button>\n        <button id=\"muteBtn\" class=\"btn\" aria-label=\"Silenciar\">\ud83d\udd0a<\/button>\n        <div class=\"vol\">\n          <input id=\"volume\" type=\"range\" min=\"0\" max=\"1\" step=\"0.01\" value=\"1\" aria-label=\"Volumen\" \/>\n        <\/div>\n      <\/div>\n\n      <div class=\"info\">\n        <div class=\"meters\">\n          <div id=\"bufferBar\" class=\"bar\"><div id=\"bufferFill\" class=\"fill\"><\/div><\/div>\n          <div id=\"connectionMsg\" class=\"conn\">Cargando&#8230;<\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"footer\">\n        <small>Fuente: feflavisalsa<\/small>\n      <\/div>\n    <\/div>\n  <\/main>\n\n  <audio id=\"audio\" crossorigin=\"anonymous\"><\/audio>\n\n  <script>\n  (function(){\n    const STREAM_URL = 'https:\/\/feflavisalsaradio.com\/listen\/feflavisalsa_radio\/radio.mp3';\n    const audio = document.getElementById('audio');\n    const playBtn = document.getElementById('playBtn');\n    const muteBtn = document.getElementById('muteBtn');\n    const volume = document.getElementById('volume');\n    const bufferFill = document.getElementById('bufferFill');\n    const statusText = document.getElementById('statusText');\n    const liveDot = document.getElementById('liveDot');\n    const connectionMsg = document.getElementById('connectionMsg');\n    const trackTitleEl = document.getElementById('trackTitle');\n    const trackMetaEl = document.getElementById('trackMeta');\n    let metadataController = null;\n    let icyMetaInt = null;\n    let reconnectTimer = null;\n    let trying = false;\n    audio.preload = 'none';\n    audio.crossOrigin = 'anonymous';\n    function setStatus(text, online=false){\n      statusText.textContent = text;\n      connectionMsg.textContent = text;\n      liveDot.classList.toggle('online', online);\n      liveDot.classList.toggle('offline', !online);\n    }\n    async function startStream(){\n      if (trying) return;\n      trying = true;\n      clearReconnect();\n      setStatus('Conectando...');\n      startIcyMetadata();\n      audio.src = STREAM_URL + '?_=' + Date.now();\n      try {\n        await audio.play();\n        setStatus('En vivo', true);\n        playBtn.textContent = '\u23f8';\n      } catch (err){\n        setStatus('Autoplay bloqueado o error', false);\n        playBtn.textContent = '\u25b6';\n        scheduleReconnect();\n      } finally{\n        trying = false;\n      }\n    }\n    function stopStream(){\n      try{ audio.pause(); }catch(e){}\n      audio.removeAttribute('src');\n      audio.load();\n      setStatus('Detenido', false);\n      playBtn.textContent = '\u25b6';\n      clearReconnect();\n      stopIcyMetadata();\n      trackTitleEl.textContent = '\u2014';\n      trackMetaEl.textContent = '\u2014';\n    }\n    function scheduleReconnect(delay = 5000){\n      clearReconnect();\n      reconnectTimer = setTimeout(() => { startStream(); }, delay);\n    }\n    async function startIcyMetadata(){\n      stopIcyMetadata();\n      metadataController = new AbortController();\n      const signal = metadataController.signal;\n      try {\n        const resp = await fetch(STREAM_URL, {\n          method: 'GET',\n          mode: 'cors',\n          cache: 'no-store',\n          headers: { 'Icy-MetaData': '1' },\n          signal\n        });\n        icyMetaInt = parseInt(resp.headers.get('icy-metaint') || resp.headers.get('Icy-MetaInt') || resp.headers.get('Icy-Metaint') || 0, 10) || null;\n        if (!icyMetaInt) {\n          const streamTitleHdr = resp.headers.get('icy-name') || resp.headers.get('icy-description') || '';\n          if (streamTitleHdr) {\n            trackTitleEl.textContent = streamTitleHdr;\n          }\n          return;\n        }\n        const reader = resp.body.getReader();\n        let buffer = new Uint8Array(0);\n        while (!signal.aborted) {\n          const { done, value } = await reader.read();\n          if (done) break;\n          const newBuf = new Uint8Array(buffer.length + value.length);\n          newBuf.set(buffer, 0);\n          newBuf.set(value, buffer.length);\n          buffer = newBuf;\n          while (buffer.length >= icyMetaInt + 1) {\n            buffer = buffer.slice(icyMetaInt);\n            const metaLen = buffer[0] * 16;\n            if (metaLen > 0) {\n              if (buffer.length - 1 < metaLen) break;\n              const metaBytes = buffer.slice(1, 1 + metaLen);\n              const metaStr = new TextDecoder().decode(metaBytes).replace(\/\\0+$\/,'');\n              const m = \/StreamTitle='([^']*)'\/.exec(metaStr);\n              if (m &#038;&#038; m[1]) updateMetadata(m[1]);\n              else if (metaStr.trim()) updateMetadata(metaStr.trim());\n              buffer = buffer.slice(1 + metaLen);\n            } else {\n              buffer = buffer.slice(1);\n            }\n          }\n        }\n      } catch (err) {\n        \/\/ ignore\n      } finally {}\n    }\n    function stopIcyMetadata(){\n      if (metadataController) {\n        try { metadataController.abort(); } catch(e){}\n        metadataController = null;\n        icyMetaInt = null;\n      }\n    }\n    function updateMetadata(raw){\n      const parts = raw.split(' - ');\n      if (parts.length >= 2) {\n        trackTitleEl.textContent = parts.slice(0, parts.length-1).join(' - ').trim();\n        trackMetaEl.textContent = parts[parts.length-1].trim();\n      } else {\n        trackTitleEl.textContent = raw;\n        trackMetaEl.textContent = '';\n      }\n    }\n    function clearReconnect(){ if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } }\n    playBtn.addEventListener('click', () => {\n      if (!audio.src) { startStream(); return; }\n      if (audio.paused) startStream();\n      else { audio.pause(); playBtn.textContent = '\u25b6'; setStatus('Pausado', false); }\n    });\n    muteBtn.addEventListener('click', () => {\n      audio.muted = !audio.muted;\n      muteBtn.textContent = audio.muted ? '\ud83d\udd07' : '\ud83d\udd0a';\n    });\n    volume.addEventListener('input', (e) => {\n      audio.volume = parseFloat(e.target.value);\n      audio.muted = audio.volume === 0;\n      muteBtn.textContent = audio.muted ? '\ud83d\udd07' : '\ud83d\udd0a';\n    });\n    let bufferInterval = null;\n    function startBufferMonitor(){\n      if (bufferInterval) return;\n      bufferInterval = setInterval(()=>{\n        try {\n          const buffered = audio.buffered;\n          const duration = audio.duration;\n          let percent = 0;\n          if (buffered && buffered.length){\n            const end = buffered.end(buffered.length - 1);\n            if (isFinite(duration) && duration > 0) percent = (end \/ duration) * 100;\n            else percent = Math.min(100, (end \/ 10) * 100);\n          }\n          bufferFill.style.width = percent + '%';\n        } catch(e){}\n      }, 400);\n    }\n    function stopBufferMonitor(){ if (bufferInterval){ clearInterval(bufferInterval); bufferInterval = null; bufferFill.style.width = '0%'; } }\n    audio.addEventListener('playing', () => { setStatus('En vivo', true); playBtn.textContent = '\u23f8'; startBufferMonitor(); clearReconnect(); });\n    audio.addEventListener('pause', () => { if (audio.src) setStatus('Pausado', false); stopBufferMonitor(); });\n    audio.addEventListener('error', (e) => { setStatus('Error de reproducci\u00f3n', false); stopBufferMonitor(); scheduleReconnect(5000); });\n    audio.addEventListener('stalled', () => { setStatus('Conexi\u00f3n interrumpida', false); scheduleReconnect(4000); });\n    audio.addEventListener('waiting', () => { setStatus('Buffering...', false); });\n    audio.addEventListener('abort', () => { setStatus('Abortado', false); stopBufferMonitor(); });\n    window.addEventListener('load', () => { volume.value = 1; audio.volume = 1; startStream(); });\n    document.addEventListener('visibilitychange', () => {\n      if (document.hidden) {\n        if (!audio.paused) { audio.pause(); setStatus('Pausado (fondo)', false); }\n      }\n    });\n  })();\n  <\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>feflavisalsa &#8211; Embed Player feflavisalsa Desconectado \u2014 \u2014 \u25b6 \ud83d\udd0a Cargando&#8230; Fuente: feflavisalsa<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_uag_custom_page_level_css":"","footnotes":""},"class_list":["post-730","page","type-page","status-publish","hentry"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false,"audioigniter_cover":false},"uagb_author_info":{"display_name":"kgdzlw","author_link":"https:\/\/feflavisalsa.com\/index.php\/author\/kgdzlw\/"},"uagb_comment_info":0,"uagb_excerpt":"feflavisalsa &#8211; Embed Player feflavisalsa Desconectado \u2014 \u2014 \u25b6 \ud83d\udd0a Cargando&#8230; Fuente: feflavisalsa","_links":{"self":[{"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/pages\/730","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/comments?post=730"}],"version-history":[{"count":10,"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/pages\/730\/revisions"}],"predecessor-version":[{"id":747,"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/pages\/730\/revisions\/747"}],"wp:attachment":[{"href":"https:\/\/feflavisalsa.com\/index.php\/wp-json\/wp\/v2\/media?parent=730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}