<div class=”canelaradio-player”>

<!– ==========================================
REPRODUCTOR
=========================================== –>

<div class=”cr-main”>

<div class=”cr-live”>
<span class=”cr-live-dot”></span>
AL AIRE AHORA
</div>

<div class=”cr-player-content”>

<button
class=”cr-play-button”
id=”crPlayButton”
type=”button”
aria-label=”Reproducir”
>
<span class=”cr-play-icon”>▶</span>
<span class=”cr-pause-icon”>❚❚</span>
</button>

<div class=”cr-info”>

<h2 id=”crStationName”>
Pichincha 106.5 FM
</h2>

<p id=”crProgram”>
Radiación Temprana
</p>

<p
class=”cr-frequency”
id=”crFrequency”
>
Pichincha 106.5 FM
</p>

</div>

<div class=”cr-volume”>

<span class=”cr-volume-icon”>
🔊
</span>

<input
type=”range”
id=”crVolume”
min=”0″
max=”1″
step=”0.01″
value=”1″
aria-label=”Volumen”
>

</div>

</div>

<div
class=”cr-status”
id=”crStatus”
>
Presiona ▶ para escuchar
</div>

<audio
id=”crAudio”
preload=”none”
></audio>

</div>

<!– ==========================================
EMISORAS
=========================================== –>

<div class=”cr-selector”>

<div class=”cr-selector-title”>
ELIGE TU EMISORA
<span>→</span>
</div>

<div class=”cr-carousel-wrapper”>

<button
class=”cr-arrow cr-arrow-left”
id=”crPrev”
type=”button”
aria-label=”Emisora anterior”
>

</button>

<div
class=”cr-stations”
id=”crStations”
></div>

<button
class=”cr-arrow cr-arrow-right”
id=”crNext”
type=”button”
aria-label=”Siguiente emisora”
>

</button>

</div>

</div>

</div>

<style>

/* =========================================================
CANELA RADIO
ESTILOS GENERALES
========================================================= */

.canelaradio-player {

–cr-green: #073f2d;
–cr-green-light: #0b523b;

–cr-orange: #f5a623;
–cr-orange-light: #ffd89c;

width: 100vw;
max-width: 100vw;

/*
* ESTA ES LA CLAVE PARA SALIR
* DEL CONTENEDOR DE ELEMENTOR
*/
margin-left: calc(50% – 50vw);
margin-right: calc(50% – 50vw);

padding: 40px 5%;

background: #f5a623;

box-sizing: border-box;

font-family:
Arial,
Helvetica,
sans-serif;

overflow: hidden;

}

/* =========================================================
BOX SIZING
========================================================= */

.canelaradio-player *,
.canelaradio-player *::before,
.canelaradio-player *::after {

box-sizing: border-box;

}

/* =========================================================
REPRODUCTOR PRINCIPAL
========================================================= */

.cr-main {

width: 100%;
max-width: 1400px;

margin-left: auto;
margin-right: auto;

padding:
28px 32px 22px;

background:
var(–cr-green);

border-radius: 22px;

color: white;

box-shadow:
0 12px 30px rgba(0,0,0,.10);

}

/* =========================================================
AL AIRE
========================================================= */

.cr-live {

display: flex;

align-items: center;

gap: 8px;

margin-bottom: 22px;

color:
#e8eee9;

font-size: 12px;

font-weight: 700;

letter-spacing: 1.5px;

}

.cr-live-dot {

width: 7px;
height: 7px;

flex: 0 0 7px;

border-radius: 50%;

background:
#ff594f;

box-shadow:
0 0 0 4px
rgba(255,89,79,.12);

animation:
crPulse 1.7s infinite;

}

@keyframes crPulse {

0% {

box-shadow:
0 0 0 0
rgba(255,89,79,.45);

}

70% {

box-shadow:
0 0 0 7px
rgba(255,89,79,0);

}

100% {

box-shadow:
0 0 0 0
rgba(255,89,79,0);

}

}

/* =========================================================
CONTENIDO PRINCIPAL
========================================================= */

.cr-player-content {

width: 100%;

display: flex;

align-items: center;

gap: 22px;

min-width: 0;

}

/* =========================================================
PLAY
========================================================= */

.cr-play-button {

width: 64px;
height: 64px;

min-width: 64px;

flex:
0 0 64px;

border: none;

border-radius: 50%;

padding: 0;

background:
#f15b3a;

color: white;

display: flex;

align-items: center;

justify-content: center;

cursor: pointer;

font-size: 23px;

transition:
transform .2s ease,
background .2s ease,
box-shadow .2s ease;

}

.cr-play-button:hover {

transform:
scale(1.06);

background:
#ff6845;

box-shadow:
0 7px 18px
rgba(0,0,0,.18);

}

.cr-play-icon {

display: block;

margin-left: 4px;

}

.cr-pause-icon {

display: none;

font-size: 17px;

}

.cr-play-button.playing
.cr-play-icon {

display: none;

}

.cr-play-button.playing
.cr-pause-icon {

display: block;

}

/* =========================================================
INFORMACIÓN
========================================================= */

.cr-info {

flex:
1 1 auto;

width: 0;

min-width: 0;

overflow: hidden;

}

.cr-info h2 {

margin:
0 0 6px;

padding: 0;

color: white;

font-size: 27px;

line-height: 1.15;

font-weight: 800;

white-space: nowrap;

overflow: hidden;

text-overflow: ellipsis;

}

.cr-info p {

margin: 0;

padding: 0;

}

#crProgram {

color:
rgba(255,255,255,.82);

font-size: 14px;

margin-bottom: 5px;

white-space: nowrap;

overflow: hidden;

text-overflow: ellipsis;

}

.cr-frequency {

color:
rgba(255,255,255,.58);

font-size: 13px;

white-space: nowrap;

overflow: hidden;

text-overflow: ellipsis;

}

/* =========================================================
VOLUMEN
========================================================= */

.cr-volume {

flex:
0 0 auto;

display: flex;

align-items: center;

gap: 10px;

}

.cr-volume-icon {

font-size: 18px;

}

.cr-volume input {

width: 100px;

max-width: 100px;

accent-color:
var(–cr-orange);

cursor: pointer;

}

/* =========================================================
ESTADO
========================================================= */

.cr-status {

margin-top: 18px;

color:
rgba(255,255,255,.55);

font-size: 12px;

}

.cr-status.playing {

color:
#a8e4c5;

}

/* =========================================================
AUDIO
========================================================= */

#crAudio {

display: none;

}

/* =========================================================
SELECTOR
========================================================= */

.cr-selector {

width: 100%;

max-width: 1400px;

margin:
22px auto 0;

}

.cr-selector-title {

margin-bottom: 12px;

color:
#17352c;

font-size: 12px;

font-weight: 800;

letter-spacing: 1.2px;

}

.cr-selector-title span {

color:
var(–cr-orange);

margin-left: 3px;

}

/* =========================================================
CARRUSEL
========================================================= */

.cr-carousel-wrapper {

width: 100%;

min-width: 0;

display: flex;

align-items: center;

gap: 8px;

}

.cr-stations {

width: 0;

min-width: 0;

flex:
1 1 auto;

display: flex;

gap: 10px;

overflow-x: auto;

overflow-y: hidden;

padding:
3px 2px 8px;

scroll-behavior: smooth;

scrollbar-width: none;

-webkit-overflow-scrolling:
touch;

}

.cr-stations::-webkit-scrollbar {

display: none;

}

/* =========================================================
BOTONES EMISORAS
========================================================= */

.cr-station {

flex:
0 0 auto;

display: flex;

align-items: center;

gap: 6px;

padding:
12px 20px;

border: none;

border-radius: 30px;

background:
#ffe2b4;

color:
#49331d;

font-family:
Arial,
Helvetica,
sans-serif;

font-size: 13px;

white-space: nowrap;

cursor: pointer;

transition:
background .2s ease,
color .2s ease,
transform .2s ease;

}

.cr-station span {

font-weight: 600;

}

.cr-station strong {

font-weight: 800;

}

.cr-station:hover {

background:
#ffd397;

transform:
translateY(-2px);

}

.cr-station.active {

background:
var(–cr-green);

color: white;

}

/* =========================================================
FLECHAS
========================================================= */

.cr-arrow {

width: 36px;
height: 36px;

min-width: 36px;

flex:
0 0 36px;

border: none;

border-radius: 50%;

background:
var(–cr-green);

color: white;

display: flex;

align-items: center;

justify-content: center;

font-size: 23px;

line-height: 1;

cursor: pointer;

}

.cr-arrow:hover {

background:
var(–cr-green-light);

}

/* =========================================================
TABLET
========================================================= */

@media only screen and (max-width: 767px) {

/*
* FULL WIDTH REAL EN MÓVIL
*
* El reproductor sale del contenedor
* limitado de Elementor.
*/

.canelaradio-player {

width: 100vw !important;

max-width: 100vw !important;

margin-left:
calc(50% – 50vw) !important;

margin-right:
calc(50% – 50vw) !important;

padding:
24px 16px !important;

overflow:
hidden !important;

box-sizing:
border-box !important;

}

/*
* PLAYER INTERNO
*/

.cr-main {

width: 100% !important;

max-width: none !important;

margin:
0 !important;

padding:
24px 20px 18px;

border-radius:
18px;

}

/*
* CONTENIDO
*/

.cr-player-content {

width:
100%;

min-width:
0;

gap:
14px;

}

/*
* PLAY
*/

.cr-play-button {

width:
58px;

height:
58px;

min-width:
58px;

flex:
0 0 58px;

font-size:
19px;

}

/*
* INFORMACIÓN
*/

.cr-info {

width:
0;

min-width:
0;

flex:
1 1 auto;

overflow:
hidden;

}

.cr-info h2 {

font-size:
21px;

line-height:
1.15;

white-space:
nowrap;

overflow:
hidden;

text-overflow:
ellipsis;

}

#crProgram {

font-size:
13px;

white-space:
nowrap;

overflow:
hidden;

text-overflow:
ellipsis;

}

.cr-frequency {

font-size:
12px;

white-space:
nowrap;

overflow:
hidden;

text-overflow:
ellipsis;

}

/*
* OCULTAR VOLUMEN EN CELULAR
*/

.cr-volume {

display:
none;

}

/*
* ESTADO
*/

.cr-status {

margin-top:
15px;

font-size:
11px;

}

/*
* SELECTOR
*/

.cr-selector {

width:
100%;

max-width:
none;

margin:
20px 0 0;

}

/*
* CARRUSEL
*/

.cr-carousel-wrapper {

width:
100%;

min-width:
0;

}

.cr-stations {

width:
0;

min-width:
0;

flex:
1 1 auto;

gap:
8px;

overflow-x:
auto;

overflow-y:
hidden;

padding:
3px 2px 8px;

}

/*
* OCULTAR FLECHAS
* En móvil se usa swipe.
*/

.cr-arrow {

display:
none;

}

/*
* BOTONES
*/

.cr-station {

padding:
11px 16px;

font-size:
12px;

}

.cr-selector-title {

margin-bottom:
9px;

font-size:
10px;

}

}

/* =========================================================
CELULAR
========================================================= */

@media only screen and (max-width: 480px) {

.canelaradio-player {

width:
100vw !important;

max-width:
100vw !important;

margin-left:
calc(50% – 50vw) !important;

margin-right:
calc(50% – 50vw) !important;

padding:
20px 12px 24px !important;

}

.cr-main {

width:
100% !important;

padding:
21px 17px 17px;

border-radius:
17px;

}

.cr-live {

margin-bottom:
17px;

font-size:
10px;

letter-spacing:
1.1px;

}

.cr-player-content {

gap:
12px;

}

.cr-play-button {

width:
52px;

height:
52px;

min-width:
52px;

flex:
0 0 52px;

font-size:
18px;

}

.cr-info h2 {

font-size:
19px;

}

#crProgram {

font-size:
12px;

}

.cr-frequency {

font-size:
11px;

}

.cr-status {

margin-top:
13px;

font-size:
10px;

}

.cr-selector {

margin-top:
18px;

}

.cr-station {

padding:
10px 15px;

font-size:
11px;

}

}

/* =========================================================
CELULAR MUY PEQUEÑO
========================================================= */

@media only screen and (max-width: 360px) {

.canelaradio-player {

padding-left:
10px !important;

padding-right:
10px !important;

}

.cr-main {

padding:
19px 14px 15px;

}

.cr-play-button {

width:
48px;

height:
48px;

min-width:
48px;

flex:
0 0 48px;

}

.cr-info h2 {

font-size:
17px;

}

}

</style>

<script>

(function () {

/* =========================================================
EMISORAS
========================================================= */

const stations = [

{
name: “Pichincha 106.5 FM”,
frequency: “Pichincha 106.5 FM”,
program: “Radiación Temprana”,
stream: “https://canelaradio.makrodigital.com:9280/stream”
},

{
name: “Guayas 90.5 FM”,
frequency: “Guayas 90.5 FM”,
program: “Canela Radio Guayas”,
stream: “https://canelaradio.makrodigital.com:9290/stream”
},

{
name: “Azuay y Cañar 107.3 FM”,
frequency: “Azuay y Cañar 107.3 FM”,
program: “Canela Radio Azuay y Cañar”,
stream: “https://cuenca.canelaradio.makrodigital.com:9270/stream”
},

{
name: “Tungurahua 106.5 FM”,
frequency: “Tungurahua 106.5 FM”,
program: “Canela Radio Tungurahua”,
stream: “https://canelaradio.makrodigital.com:9260/stream”
},

{
name: “Imbabura 92.7 FM”,
frequency: “Imbabura 92.7 FM”,
program: “Canela Radio Imbabura”,
stream: “https://canelaradio.makrodigital.com:9250/stream”
},

{
name: “Carchi 92.9 FM”,
frequency: “Carchi 92.9 FM”,
program: “Canela Radio Carchi”,
stream: “http://canelaradio.makrodigital.com:9470/stream”
},

{
name: “Loja 96.9 / 98.9 FM”,
frequency: “Loja 96.9 FM y 98.9 FM”,
program: “Canela Radio Loja”,
stream: “https://canelaradio.makrodigital.com:9190/stream”
},

{
name: “Sucumbíos 94.5 FM”,
frequency: “Sucumbíos 94.5 FM”,
program: “Canela Radio Sucumbíos”,
stream: “https://canelaradio.makrodigital.com:9230/stream”
},

{
name: “Morona Santiago 91.7 FM”,
frequency: “Morona Santiago 91.7 FM”,
program: “Canela Radio Morona Santiago”,
stream: “https://canelaradio.makrodigital.com:9220/stream”
},

{
name: “El Oro 100.7 FM”,
frequency: “El Oro 100.7 FM”,
program: “Canela Radio El Oro”,
stream: “https://canelaradio.makrodigital.com:9240/stream”
},

{
name: “Manabí 102.5 FM”,
frequency: “Manabí 102.5 FM”,
program: “Canela Radio Manabí”,
stream: “https://manabi.canelaradio.makrodigital.com:9216/stream”
},

{
name: “Chimborazo 94.5 FM”,
frequency: “Chimborazo 94.5 FM”,
program: “Canela Radio Chimborazo”,
stream: “https://canelaradio.makrodigital.com:9212/stream”
},

{
name: “Napo 106.1 FM”,
frequency: “Napo 106.1 FM”,
program: “Canela Radio Napo”,
stream: “https://canelaradio.makrodigital.com:9202/stream”
},

{
name: “Bolívar 90.3 FM”,
frequency: “Bolívar 90.3 FM”,
program: “Canela Radio Bolívar”,
stream: “https://canelaradio.makrodigital.com:9208/stream”
},

{
name: “Los Ríos 90.7 FM”,
frequency: “Los Ríos 90.7 FM”,
program: “Canela Radio Los Ríos”,
stream: “https://canelaradio.makrodigital.com:9208/stream”
},

{
name: “Pastaza 101.9 FM”,
frequency: “Pastaza 101.9 FM”,
program: “Canela Radio Pastaza”,
stream: “https://canelaradio.makrodigital.com:9180/stream”
}

];

/* =========================================================
ELEMENTOS
========================================================= */

const audio =
document.getElementById(“crAudio”);

const playButton =
document.getElementById(“crPlayButton”);

const stationName =
document.getElementById(“crStationName”);

const program =
document.getElementById(“crProgram”);

const frequency =
document.getElementById(“crFrequency”);

const volume =
document.getElementById(“crVolume”);

const status =
document.getElementById(“crStatus”);

const stationsContainer =
document.getElementById(“crStations”);

const prevButton =
document.getElementById(“crPrev”);

const nextButton =
document.getElementById(“crNext”);

/* =========================================================
CREAR BOTONES
========================================================= */

stations.forEach(
function (station, index) {

const button =
document.createElement(“button”);

button.type =
“button”;

button.className =
“cr-station”;

button.dataset.index =
index;

/*
* Separar nombre y frecuencia
*/

let displayName =
station.name;

let displayFrequency =
“”;

const parts =
station.name.split(” “);

if (parts.length >= 3) {

const possibleFrequency =
parts.slice(-2).join(” “);

if (
possibleFrequency.includes(“FM”)
) {

displayFrequency =
possibleFrequency;

displayName =
parts
.slice(0, -2)
.join(” “);

}

}

button.innerHTML =

“<span>” +
displayName +
“</span>” +

(
displayFrequency

?

“<strong>” +
displayFrequency
.replace(” FM”, “”) +
“</strong>”

:

“”
);

button.addEventListener(
“click”,
function () {

loadStation(
index,
true
);

}
);

stationsContainer.appendChild(
button
);

}
);

const stationButtons =
document.querySelectorAll(
“.cr-station”
);

/* =========================================================
CARGAR EMISORA
========================================================= */

function loadStation(
index,
shouldPlay
) {

if (!stations[index]) {

return;

}

const station =
stations[index];

stationName.textContent =
station.name;

program.textContent =
station.program;

frequency.textContent =
station.frequency;

/*
* Activar botón
*/

stationButtons.forEach(
function (button, i) {

button.classList.toggle(
“active”,
i === index
);

}
);

/*
* Detener audio anterior
*/

audio.pause();

audio.removeAttribute(
“src”
);

audio.load();

/*
* Nuevo stream
*/

audio.src =
station.stream;

audio.load();

/*
* Estado
*/

playButton.classList.remove(
“playing”
);

status.classList.remove(
“playing”
);

status.textContent =
“Presiona ▶ para escuchar”;

/*
* Centrar botón seleccionado
*/

const activeButton =
stationButtons[index];

if (activeButton) {

activeButton.scrollIntoView({

behavior:
“smooth”,

block:
“nearest”,

inline:
“center”

});

}

/*
* Reproducir automáticamente
* cuando se selecciona una emisora
*/

if (shouldPlay) {

const promise =
audio.play();

if (
promise !== undefined
) {

promise.then(
function () {

playButton.classList.add(
“playing”
);

status.textContent =
“● Escuchando en vivo”;

status.classList.add(
“playing”
);

}
).catch(
function () {

status.textContent =
“Presiona ▶ para reproducir”;

}
);

}

}

}

/* =========================================================
PLAY / PAUSE
========================================================= */

playButton.addEventListener(
“click”,
function () {

if (audio.paused) {

const promise =
audio.play();

if (
promise !== undefined
) {

promise.then(
function () {

playButton.classList.add(
“playing”
);

status.textContent =
“● Escuchando en vivo”;

status.classList.add(
“playing”
);

}
).catch(
function () {

status.textContent =
“No se pudo iniciar el streaming”;

status.classList.remove(
“playing”
);

}
);

}

} else {

audio.pause();

playButton.classList.remove(
“playing”
);

status.textContent =
“Streaming pausado”;

status.classList.remove(
“playing”
);

}

}
);

/* =========================================================
EVENTO PLAYING
========================================================= */

audio.addEventListener(
“playing”,
function () {

playButton.classList.add(
“playing”
);

status.textContent =
“● Escuchando en vivo”;

status.classList.add(
“playing”
);

}
);

/* =========================================================
EVENTO PAUSE
========================================================= */

audio.addEventListener(
“pause”,
function () {

playButton.classList.remove(
“playing”
);

}
);

/* =========================================================
ESPERANDO STREAM
========================================================= */

audio.addEventListener(
“waiting”,
function () {

status.textContent =
“Conectando con la emisora…”;

status.classList.remove(
“playing”
);

}
);

/* =========================================================
ERROR STREAM
========================================================= */

audio.addEventListener(
“error”,
function () {

playButton.classList.remove(
“playing”
);

status.classList.remove(
“playing”
);

status.textContent =
“No se pudo conectar con esta emisora”;

}
);

/* =========================================================
VOLUMEN
========================================================= */

volume.addEventListener(
“input”,
function () {

audio.volume =
Number(volume.value);

}
);

/* =========================================================
FLECHA IZQUIERDA
========================================================= */

prevButton.addEventListener(
“click”,
function () {

stationsContainer.scrollBy({

left:
-300,

behavior:
“smooth”

});

}
);

/* =========================================================
FLECHA DERECHA
========================================================= */

nextButton.addEventListener(
“click”,
function () {

stationsContainer.scrollBy({

left:
300,

behavior:
“smooth”

});

}
);

/* =========================================================
INICIAR
========================================================= */

loadStation(
0,
false
);

})();
</script>

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *