(function () {
'use strict';
// Delete the class 'preload' from the body when the page is loaded
window.addEventListener('DOMContentLoaded', event => {
document.body.classList.remove('preload');
});
const buttons = document.querySelectorAll('[data-outside]');
const ACTIVE_CLASS = 'is-active';
function outsideClick(button) {
if (!button) return;
const target = document.getElementById(button.dataset.outside);
if (!target) return;
function toggleClasses() {
button.classList.toggle(ACTIVE_CLASS);
target.classList.toggle(ACTIVE_CLASS);
if (button.classList.contains(ACTIVE_CLASS)) {
document.addEventListener('click', clickOutside);
return;
}
document.removeEventListener('click', clickOutside);
}
button.addEventListener('click', toggleClasses);
function clickOutside(event) {
if (!target.contains(event.target) && !button.contains(event.target)) {
toggleClasses();
document.removeEventListener('click', clickOutside);
}
}
const closeButton = target.querySelector('[data-close]');
if (closeButton) {
closeButton.addEventListener('click', () => {
button.classList.remove(ACTIVE_CLASS);
target.classList.remove(ACTIVE_CLASS);
document.removeEventListener('click', clickOutside);
});
}
}
buttons.forEach(button => {
outsideClick(button);
});
// Función para inicializar el lienzo (canvas)
function initCanvas(container) {
const canvas = document.createElement('canvas');
canvas.setAttribute('id', 'visualizerCanvas');
canvas.setAttribute('class', 'visualizer-item');
container.appendChild(canvas);
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
return canvas;
}
// Función para cambiar el lienzo según el tamaño del contenedor
function resizeCanvas(canvas, container) {
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
}
// Visualizer
const visualizer = (audio, container) => {
if (!audio || !container) {
return;
}
const options = {
fftSize: container.dataset.fftSize || 2048,
numBars: container.dataset.bars || 40,
maxHeight: container.dataset.maxHeight || 255
};
const ctx = new AudioContext();
const audioSource = ctx.createMediaElementSource(audio);
const analyzer = ctx.createAnalyser();
audioSource.connect(analyzer);
audioSource.connect(ctx.destination);
const frequencyData = new Uint8Array(analyzer.frequencyBinCount);
const canvas = initCanvas(container);
const canvasCtx = canvas.getContext('2d');
// Crear barras
const renderBars = () => {
resizeCanvas(canvas, container);
analyzer.getByteFrequencyData(frequencyData);
if (options.fftSize) {
analyzer.fftSize = options.fftSize;
}
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < options.numBars; i++) {
const index = Math.floor((i + 10) * (i < options.numBars / 2 ? 2 : 1));
const fd = frequencyData[index];
const barHeight = Math.max(4, fd || 0) + options.maxHeight / 255;
const barWidth = canvas.width / options.numBars;
const x = i * barWidth;
const y = canvas.height - barHeight;
canvasCtx.fillStyle = 'white';
canvasCtx.fillRect(x, y, barWidth - 2, barHeight);
}
requestAnimationFrame(renderBars);
};
renderBars();
// Listener del cambio de espacio en la ventana
window.addEventListener('resize', () => {
resizeCanvas(canvas, container);
});
};
const API_KEY_LYRICS = '1637b78dc3b129e6843ed674489a92d0';
const cache = {};
// Iconos de Meteor Icons: https://meteoricons.com/
const icons = {
play: '',
pause: '',
facebook: '',
twitter: '',
instagram: '',
youtube: '',
tiktok: '',
whatsapp: '',
telegram: '',
tv: '',
ios: '',
android: ''
};
const pixel = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdj+P//PxcACQYDCF0ysWYAAAAASUVORK5CYII=';
const changeImageSize = (url, size) => url.replace(/100x100/, size);
// Obtener Datos desde Stream Africa
const getDataFromStreamAfrica = async (artist, title, defaultArt, defaultCover) => {
let text;
if (artist === null || artist === title) {
text = `${title} - ${title}`;
} else {
text = `${artist} - ${title}`;
}
const cacheKey = text.toLowerCase();
if (cache[cacheKey]) {
return cache[cacheKey];
}
const API_URL = `https://api.streamafrica.net/new.search.php?query=${encodeURIComponent(text)}&service=itunes`;
const response = await fetch(API_URL);
if (title === 'MIXX SHOW RADIO' || response.status === 403) {
const results = {
title,
artist,
art: defaultArt,
cover: defaultCover,
stream_url: '#not-found'
};
cache[cacheKey] = results;
return results;
}
const data = response.ok ? await response.json() : {};
if (!data.results || data.results.length === 0) {
const results = {
title,
artist,
art: defaultArt,
cover: defaultCover,
stream_url: '#not-found'
};
cache[cacheKey] = results;
return results;
}
const stream = data.results;
const results = {
title: stream.title || title,
artist: stream.artist || artist,
thumbnail: stream.artwork || defaultArt,
art: stream.artwork || defaultArt,
cover: stream.artwork || defaultCover,
stream_url: stream.stream_url || '#not-found'
};
cache[cacheKey] = results;
return results;
};
// Obtener Datos desde iTunes
const getDataFromITunes = async (artist, title, defaultArt, defaultCover) => {
let text;
if (artist === title) {
text = `${title}`;
} else {
text = `${artist} - ${title}`;
}
const cacheKey = text.toLowerCase();
if (cache[cacheKey]) {
return cache[cacheKey];
}
// SyntaxError: Unexpected end of JSON input
const response = await fetch(`https://itunes.apple.com/search?limit=1&term=${encodeURIComponent(text)}`);
if (response.status === 403) {
const results = {
title,
artist,
art: defaultArt,
cover: defaultCover,
stream_url: '#not-found'
};
return results;
}
const data = response.ok ? await response.json() : {};
if (!data.results || data.results.length === 0) {
const results = {
title,
artist,
art: defaultArt,
cover: defaultCover,
stream_url: '#not-found'
};
return results;
}
const itunes = data.results[0];
const results = {
title: itunes.trackName || title,
artist: itunes.artistName || artist,
thumbnail: itunes.artworkUrl100 || defaultArt,
art: itunes.artworkUrl100 ? changeImageSize(itunes.artworkUrl100, '1500x1500') : defaultArt,
cover: itunes.artworkUrl100 ? changeImageSize(itunes.artworkUrl100, '1500x1500') : defaultCover,
stream_url: '#not-found'
};
cache[cacheKey] = results;
return results;
};
// Determinar de donde obtener los datos
async function getDataFrom({
artist,
title,
art,
cover,
server
}) {
let dataFrom = {};
if (server.toLowerCase() === 'africa') {
dataFrom = await getDataFromStreamAfrica(artist, title, art, cover);
} else {
dataFrom = await getDataFromITunes(artist, title, art, cover);
}
return dataFrom;
}
// Obtener letras de canciones
const getLyrics = async (artist, name) => {
try {
const response = await fetch(`https://api.vagalume.com.br/search.php?apikey=${API_KEY_LYRICS}&art=${encodeURIComponent(artist)}&mus=${encodeURIComponent(name)}`);
const data = await response.json();
if (data.type === 'exact' || data.type === 'aprox') {
const lyrics = data.mus[0].text;
return lyrics;
} else {
return 'Not found lyrics';
}
} catch (error) {
console.error('Error fetching lyrics:', error);
return 'Not found lyrics';
}
};
// Crear un elemento HTML a partir de una cadena de texto
function createElementFromHTML(htmlString) {
const div = document.createElement('div');
div.innerHTML = htmlString.trim();
return div.firstChild;
}
// Eliminar elementos innecesarios del texto
function sanitizeText(text) {
return text.replace(/^\d+\.\)\s/, '').replace(/
$/, '');
}
// Normalizar historial
function normalizeHistory(api) {
let artist;
let song;
let history = api.song_history || api.history || api.songHistory || [];
history = history.slice(0, 4);
const historyNormalized = history.map(item => {
if (api.song_history) {
artist = item.song.artist;
song = item.song.title;
} else if (api.history) {
artist = sanitizeText(item.split(' - ')[0] || item);
song = sanitizeText(item.split(' - ')[1] || item);
} else if (api.songHistory) {
artist = item.artist;
song = item.title;
}
return {
artist,
song
};
});
// limitar a 4 elementos
return historyNormalized;
}
function createTempImage(src) {
return new Promise((resolve, reject) => {
const img = document.createElement('img');
img.crossOrigin = 'Anonymous';
img.src = `https://images.weserv.nl/?url=${src}`;
img.onload = () => resolve(img);
img.onerror = reject;
});
}
function normalizeTitle(api) {
let title;
let artist;
if (api.songtitle && api.songtitle.includes(' - ')) {
title = api.songtitle.split(' - ')[0];
artist = api.songtitle.split(' - ')[1];
} else if (api.now_playing) {
title = api.now_playing.song.title;
artist = api.now_playing.song.artist;
} else if (api.artist && api.title) {
title = api.title;
artist = api.artist;
} else if (api.currenttrack_title) {
title = api.currenttrack_title;
artist = api.currenttrack_artist;
} else if (api.title && api.djprofile && api.djusername) {
title = api.title.split(' - ')[1];
artist = api.title.split(' - ')[0];
} else {
title = api.currentSong;
artist = api.currentArtist;
}
return {
title,
artist
};
}
const playButton = document.querySelector('.player-button-play');
const visualizerContainer = document.querySelector('.visualizer');
const audio = new Audio();
audio.crossOrigin = 'anonymous';
let hasVisualizer = false;
function play(audio, newSource = null) {
if (newSource) {
audio.src = newSource;
}
// Visualizer
if (!hasVisualizer) {
visualizer(audio, visualizerContainer);
hasVisualizer = true;
}
audio.load();
audio.play();
playButton.innerHTML = icons.pause;
playButton.classList.add('is-active');
document.body.classList.add('is-playing');
}
function pause(audio) {
audio.pause();
playButton.innerHTML = icons.play;
playButton.classList.remove('is-active');
document.body.classList.remove('is-playing');
}
// Botón play/pause, al pausar detener el stream, al reproducir iniciar el stream de nuevo
// playButton, play, pause son funciones exportadas que se usaran en otros archivos
if (playButton !== null) {
playButton.addEventListener('click', async () => {
if (audio.paused) {
play(audio);
} else {
pause(audio);
}
});
}
const range = document.querySelector('.player-volume');
const rangeFill = document.querySelector('.player-range-fill');
const rangeWrapper = document.querySelector('.player-range-wrapper');
const rangeThumb = document.querySelector('.player-range-thumb');
const currentVolume = localStorage.getItem('volume') || 100;
// Rango recorrido
function setRangeWidth(percent) {
{
rangeFill.style.height = `${percent}%`;
}
}
// Posición del thumb
function setThumbPosition(percent) {
const compensatedWidth = rangeWrapper.offsetHeight - rangeThumb.offsetHeight ;
const thumbPosition = percent / 100 * compensatedWidth;
{
rangeThumb.style.bottom = `${thumbPosition}px`;
}
}
// Actualiza el volumen al cambiar el rango
function updateVolume(value) {
range.value = value;
setRangeWidth(value);
setThumbPosition(value);
localStorage.setItem('volume', value);
audio.volume = value / 100;
}
// Valor inicial
if (range !== null) {
updateVolume(currentVolume);
// Escucha el cambio del rango
range.addEventListener('input', event => {
updateVolume(event.target.value);
});
// Escucha el movimiento del mouse
rangeThumb.addEventListener('mousedown', () => {
document.addEventListener('mousemove', handleThumbDrag);
});
}
// Mueve el thumb y actualiza el volumen
function handleThumbDrag(event) {
const rangeRect = range.getBoundingClientRect();
const click = event.clientY - rangeRect.top;
let percent = click / range.offsetWidth * 100;
percent = 100 - percent;
percent = Math.max(0, Math.min(100, percent));
const value = Math.round((range.max - range.min) * (percent / 100)) + parseInt(range.min);
updateVolume(value);
}
// Deja de escuchar el movimiento del mouse
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', handleThumbDrag);
});
window.addEventListener('resize', () => {
const currentPercent = range.value;
setRangeWidth(currentPercent);
setThumbPosition(currentPercent);
});
const songNow = document.querySelector('.song-now');
const stationsList = document.getElementById('stations');
const stationName = document.querySelector('.station-name');
const stationDescription = document.querySelector('.station-description');
const headerLogoImg = document.querySelector('.header-logo-img');
const playerArtwork = document.querySelector('.player-artwork img:first-child');
const playerCoverImg = document.querySelector('.player-cover-image');
const playerSocial = document.querySelectorAll('.player-social');
const playerApps = document.querySelector('.footer-app');
const playerTv = document.querySelector('.online-tv');
const playerTvHeader = document.querySelector('.online-tv-header');
const playerTvModal = document.getElementById('modal-tv');
const playerProgram = document.querySelector('.player-program');
const lyricsContent = document.getElementById('lyrics');
const history = document.getElementById('history');
const historyTemplate = `