Created
June 22, 2025 09:21
-
-
Save Soyunpelotilla/03365c6e9aeee8bd4528474e1f9832c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="es"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> | |
<title>CANALES</title> | |
<style> | |
:root { | |
--bg: #0d1117; | |
--card: #161b22; | |
--border: #30363d; | |
--text: #ffffff; | |
--accent: #58a6ff; | |
--epg: #8b949e; | |
--fav: #ffd700; | |
} | |
* { | |
box-sizing: border-box; | |
margin: 0; | |
padding: 0; | |
} | |
body { | |
background: var(--bg); | |
color: var(--text); | |
font-family: system-ui, sans-serif; | |
} | |
header { | |
text-align: center; | |
padding: 20px 10px 0; | |
} | |
h1 { | |
color: var(--accent); | |
font-size: 1.6rem; | |
margin-bottom: 6px; | |
} | |
.reloj-premium { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
gap: 8px; | |
background: linear-gradient(to right, #1f2933, #111820); | |
border: 1px solid #2d3741; | |
color: #e6edf3; | |
font-weight: 600; | |
font-size: 1rem; | |
padding: 10px 20px; | |
margin: 4px auto 12px; | |
max-width: 380px; | |
text-align: center; | |
border-radius: 12px; | |
box-shadow: 0 4px 16px rgba(0,0,0,0.4); | |
letter-spacing: 0.4px; | |
backdrop-filter: blur(4px); | |
text-shadow: 0 1px 2px #00000088; | |
} | |
#reloj-svg { | |
width: 1em; | |
height: 1em; | |
min-width: 1em; | |
min-height: 1em; | |
} | |
#notificacion-toast { | |
position: fixed; | |
top: 20px; | |
left: 50%; | |
transform: translateX(-50%); | |
background: #1f6feb; | |
color: white; | |
padding: 10px 20px; | |
border-radius: 8px; | |
font-weight: 600; | |
z-index: 9999; | |
box-shadow: 0 4px 12px rgba(0,0,0,0.4); | |
animation: fadeInOut 2s ease; | |
display: none; | |
} | |
@keyframes fadeInOut { | |
0% { opacity: 0; transform: translateX(-50%) translateY(-10px); } | |
10% { opacity: 1; transform: translateX(-50%) translateY(0); } | |
90% { opacity: 1; } | |
100% { opacity: 0; transform: translateX(-50%) translateY(-10px); } | |
} | |
.grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
gap: 16px; | |
padding: 10px 20px 20px; | |
} | |
.canal { | |
background: var(--card); | |
border: 1px solid var(--border); | |
border-radius: 8px; | |
text-align: center; | |
padding: 10px; | |
position: relative; | |
transition: transform 0.2s, outline 0.2s ease-in-out; | |
} | |
.canal:hover, | |
.canal:focus { | |
transform: scale(1.03); | |
cursor: pointer; | |
outline: 3px solid var(--accent); | |
z-index: 10; | |
} | |
.canal img { | |
max-width: 100%; | |
height: auto; | |
margin-bottom: 6px; | |
} | |
.canal span { | |
display: inline-block; | |
font-size: 0.95rem; | |
color: var(--text); | |
margin-bottom: 6px; | |
padding-bottom: 4px; | |
border-bottom: 1px solid var(--border); | |
} | |
.favorito { | |
position: absolute; | |
top: 4px; | |
left: 2px; | |
font-size: 0.8rem; | |
color: var(--fav); | |
background: rgba(0, 0, 0, 0.5); | |
border-radius: 50%; | |
padding: 3px; | |
display: none; | |
z-index: 2; | |
} | |
.favorito.activo { | |
display: inline-block; | |
animation: latido 0.4s ease; | |
} | |
@keyframes latido { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.4); } | |
100% { transform: scale(1); } | |
} | |
.epg { | |
font-size: 0.72rem; | |
color: #ffffff; | |
margin-top: 6px; | |
min-height: 2.6em; | |
display: block; | |
text-align: center; | |
line-height: 1.3; | |
white-space: pre-line; | |
} | |
.epg-actual { | |
color: #00e676 !important; | |
font-weight: 600; | |
display: block; | |
margin-bottom: 2px; | |
} | |
.epg span:not(.epg-actual) { | |
color: #58a6ff !important; | |
} | |
.epg-cargando { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
gap: 6px; | |
font-size: 0.72rem; | |
color: var(--epg); | |
} | |
.spinner { | |
width: 12px; | |
height: 12px; | |
border: 2px solid #ccc; | |
border-top: 2px solid var(--accent); | |
border-radius: 50%; | |
animation: girar 0.8s linear infinite; | |
} | |
@keyframes girar { | |
0% { transform: rotate(0deg); } | |
100% { transform: rotate(360deg); } | |
} | |
#buscador { | |
padding: 14px; | |
width: 90%; | |
max-width: 500px; | |
border-radius: 8px; | |
border: 2px solid var(--border); | |
background: var(--card); | |
color: var(--text); | |
margin: 14px auto 24px; | |
display: block; | |
font-size: 1.1rem; | |
box-shadow: 0 2px 8px rgba(0,0,0,0.2); | |
} | |
.tarjeta-superior { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
font-weight: bold; | |
} | |
.tarjeta-superior .icono { | |
font-size: 1.4rem; | |
margin-bottom: 4px; | |
} | |
.tarjeta-superior .epg { | |
display: none; | |
} | |
@media (max-width: 600px) { | |
.grid { gap: 20px; } | |
.canal { padding: 14px 10px; } | |
} | |
body, .grid, .canal, .epg, header, h1, h2, .estado, .favorito { | |
user-select: none !important; | |
-webkit-user-select: none !important; | |
} | |
#buscador { | |
user-select: text !important; | |
-webkit-user-select: text !important; | |
inputmode: text; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="notificacion-toast" class="reloj-premium"></div> | |
<header> | |
<h1>CANALES</h1> | |
<div class="reloj-premium"> | |
<svg id="reloj-svg" viewBox="0 0 100 100"> | |
<circle cx="50" cy="50" r="48" stroke="#58a6ff" stroke-width="4" fill="none"/> | |
<line id="hora" x1="50" y1="50" x2="50" y2="30" stroke="#e6edf3" stroke-width="5" stroke-linecap="round"/> | |
<line id="minuto" x1="50" y1="50" x2="50" y2="20" stroke="#e6edf3" stroke-width="3" stroke-linecap="round"/> | |
</svg> | |
<span id="reloj-local-texto"></span> | |
</div> | |
</header> | |
<section class="grid" id="tarjetas-superiores"> | |
<div class="canal tarjeta-superior" onclick="toggleFavoritos()" tabindex="0"> | |
<div class="icono">⭐</div> | |
<span>FAVORITOS</span> | |
</div> | |
<div class="canal tarjeta-superior" onclick="abrirEventos()" tabindex="0"> | |
<div class="icono">📅</div> | |
<span>EVENTOS</span> | |
</div> | |
</section> | |
<input | |
type="text" | |
id="buscador" | |
placeholder="Buscar canal…" | |
oninput="buscarCanalPorPrefijo()" | |
autocomplete="off" | |
autocorrect="off" | |
spellcheck="false" | |
tabindex="0" | |
/> | |
<main class="grid" id="contenedor-canales"> | |
<!-- 1. M+ LALIGA --> | |
<div class="canal" data-url="acestream://c9321006921967d6258df6945f1d598a5c0cbf1e" data-epg-id="M+ LaLiga TV HD" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://i.postimg.cc/8kqQxd4V/Background-Eraser-20250426-065222036.png" alt="M+ LALIGA"> | |
<span class="canal-nombre">M+ LALIGA ELCANO</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 2. M+ LALIGA 2 --> | |
<div class="canal" data-url="acestream://51b363b1c4d42724e05240ad068ad219df8042ec" data-epg-id="M+ LaLiga TV 2 HD" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://i.postimg.cc/K8xVy0gC/Background-Eraser-20250426-065847659.png" alt="M+ LALIGA 2"> | |
<span class="canal-nombre">M+ LALIGA 2 ELCANO</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 3. M+ LALIGA 4K --> | |
<div class="canal" data-url="acestream://cc9b7f5fe416069a2110da0909b0f915043c468b" data-epg-id="M+ LaLiga TV UHD" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://i.postimg.cc/8kqQxd4V/Background-Eraser-20250426-065222036.png" alt="M+ LALIGA 4K"> | |
<span class="canal-nombre">M+ LALIGA 4K NEW LOOP</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 4. DAZN LALIGA --> | |
<div class="canal" data-url="acestream://e2b8a4aba2f4ea3dd68992fcdb65c9e62d910b05" data-epg-id="DAZN LaLiga HD" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://i.postimg.cc/j5hg1ZwX/Background-Eraser-20250425-234039911.png" alt="DAZN LALIGA"> | |
<span class="canal-nombre">DAZN LALIGA ELCANO</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 5. DAZN LALIGA 2 --> | |
<div class="canal" data-url="acestream://51dbbfb42f8091e4ea7a2186b566a40e780953d9" data-epg-id="DAZN LaLiga 2 HD" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://i.postimg.cc/MZV1bdfM/IMG-20250425-234650.png" alt="DAZN LALIGA 2"> | |
<span class="canal-nombre">DAZN LALIGA 2 ELCANO</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 6. DAZN 1 (m3u8) --> | |
<div class="canal" data-url="http://185.189.225.150:85/Eurosport1/index.m3u8" data-epg-id="DAZN 1" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/3/3e/DAZN_1_Logo.svg" alt="DAZN 1"> | |
<span class="canal-nombre">DAZN 1</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 7. DAZN 2 --> | |
<div class="canal" data-url="acestream://dazn2feedabcdefabcdefabcdefabcdefabcd5678" data-epg-id="DAZN 2" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/7/7e/DAZN_2.svg" alt="DAZN 2"> | |
<span class="canal-nombre">DAZN 2</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 8. DAZN 3 --> | |
<div class="canal" data-url="acestream://dazn3feedabcdefabcdefabcdefabcdefabcd0000" data-epg-id="DAZN 3" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/0/0d/DAZN_3.svg" alt="DAZN 3"> | |
<span class="canal-nombre">DAZN 3</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 9. DAZN F1 --> | |
<div class="canal" data-url="acestream://f1streamabcdefabcdefabcdefabcdefabcdef55" data-epg-id="DAZN F1" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/1/1f/DAZN_F1_2024_logo.svg" alt="DAZN F1"> | |
<span class="canal-nombre">DAZN F1</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 10. MOVISTAR DEPORTES --> | |
<div class="canal" data-url="acestream://movdeportes11112222333344445555666677778888" data-epg-id="Movistar Deportes" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/3/3e/Movistar_Deportes.svg" alt="MOVISTAR DEPORTES"> | |
<span class="canal-nombre">MOVISTAR DEPORTES</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 11. MOVISTAR DEPORTES 2 --> | |
<div class="canal" data-url="acestream://movdeportes2abcdefabcdefabcdefabcdefabcd" data-epg-id="Movistar Deportes 2" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6e/Movistar_Deportes_2.svg" alt="MOVISTAR DEPORTES 2"> | |
<span class="canal-nombre">MOVISTAR DEPORTES 2</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 12. MOVISTAR DEPORTES 3 --> | |
<div class="canal" data-url="acestream://movdeportes3abcdefabcdefabcdefabcdefabcd" data-epg-id="Movistar Deportes 3" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://www.movistarplus.es/recorte/m-logos/65x65/m-plus-deportes-3.png" alt="MOVISTAR DEPORTES 3"> | |
<span class="canal-nombre">MOVISTAR DEPORTES 3</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 13. MOVISTAR DEPORTES 4 --> | |
<div class="canal" data-url="acestream://movdeportes4abcdefabcdefabcdefabcdefabcd" data-epg-id="Movistar Deportes 4" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://www.movistarplus.es/recorte/m-logos/65x65/m-plus-deportes-4.png" alt="MOVISTAR DEPORTES 4"> | |
<span class="canal-nombre">MOVISTAR DEPORTES 4</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 14. EUROSPORT 1 --> | |
<div class="canal" data-url="acestream://eurosport1abcdefabcdefabcdefabcdefabcdef" data-epg-id="Eurosport 1" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/5/5e/Eurosport_1_Logo_2015.svg" alt="EUROSPORT 1"> | |
<span class="canal-nombre">EUROSPORT 1</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 15. EUROSPORT 2 --> | |
<div class="canal" data-url="acestream://eurosport2abcdefabcdefabcdefabcdefabcdef" data-epg-id="Eurosport 2" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/9/9e/Eurosport_2_Logo_2015.svg" alt="EUROSPORT 2"> | |
<span class="canal-nombre">EUROSPORT 2</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 16. MOVISTAR VAMOS --> | |
<div class="canal" data-url="acestream://vamosabcdefabcdefabcdefabcdefabcdefabcd" data-epg-id="Vamos por M+" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Vamos_por_Movistar_Plus%2B_2023_Logo.svg" alt="MOVISTAR VAMOS"> | |
<span class="canal-nombre">MOVISTAR VAMOS</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 17. MOVISTAR GOLF --> | |
<div class="canal" data-url="acestream://golfabcdefabcdefabcdefabcdefabcdefabcd" data-epg-id="Movistar Golf" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/4/4e/Movistar_Golf.svg" alt="MOVISTAR GOLF"> | |
<span class="canal-nombre">MOVISTAR GOLF</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 18. GOL PLAY --> | |
<div class="canal" data-url="acestream://golplayabcdefabcdefabcdefabcdefabcdef" data-epg-id="GOL PLAY" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/1/1f/Gol_Play_logo.svg" alt="GOL PLAY"> | |
<span class="canal-nombre">GOL PLAY</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 19. ONETORO --> | |
<div class="canal" data-url="acestream://onetoroabcdefabcdefabcdefabcdefabcdef" data-epg-id="OneToro TV" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/3/3f/OneToro_TV_logo.svg" alt="ONETORO"> | |
<span class="canal-nombre">ONETORO</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 20. FOX SPORTS --> | |
<div class="canal" data-url="acestream://foxsportsabcdefabcdefabcdefabcdefabcdef" data-epg-id="FOX Sports" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6e/FOX_Sports_logo.svg" alt="FOX SPORTS"> | |
<span class="canal-nombre">FOX SPORTS</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 21. ESPN DEPORTES --> | |
<div class="canal" data-url="acestream://espndeportesabcdefabcdefabcdefabcdefabcd" data-epg-id="ESPN Deportes" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/2/2f/ESPN_Deportes_logo.svg" alt="ESPN DEPORTES"> | |
<span class="canal-nombre">ESPN DEPORTES</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 22. ESPN --> | |
<div class="canal" data-url="acestream://espnabcdefabcdefabcdefabcdefabcdefabcd" data-epg-id="ESPN" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/2/2f/ESPN_wordmark.svg" alt="ESPN"> | |
<span class="canal-nombre">ESPN</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 23. ESPN MEXICO --> | |
<div class="canal" data-url="acestream://espnmexicoabcdefabcdefabcdefabcdefabcd" data-epg-id="ESPN México" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/2/2f/ESPN_wordmark.svg" alt="ESPN MEXICO"> | |
<span class="canal-nombre">ESPN MEXICO</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 24. FOX DEPORTES --> | |
<div class="canal" data-url="acestream://foxdeportesabcdefabcdefabcdefabcdefabcd" data-epg-id="FOX Deportes" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6e/FOX_Deportes_logo.svg" alt="FOX DEPORTES"> | |
<span class="canal-nombre">FOX DEPORTES</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 25. TUDN --> | |
<div class="canal" data-url="acestream://tudnabcdefabcdefabcdefabcdefabcdefabcd" data-epg-id="TUDN" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/3/3e/TUDN_Logo.svg" alt="TUDN"> | |
<span class="canal-nombre">TUDN</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 26. UNIMAS --> | |
<div class="canal" data-url="acestream://unimasabcdefabcdefabcdefabcdefabcdef" data-epg-id="UniMás" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/1/1e/UniMas_logo_2021.svg" alt="UNIMAS"> | |
<span class="canal-nombre">UNIMAS</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 27. UNIVISION --> | |
<div class="canal" data-url="acestream://univisionabcdefabcdefabcdefabcdefabcd" data-epg-id="Univision" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/3/3e/Univision_logo_2019.svg" alt="UNIVISION"> | |
<span class="canal-nombre">UNIVISION</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 28. BEIN SPORTS Ñ --> | |
<div class="canal" data-url="acestream://beinsportsnabcdefabcdefabcdefabcdefabcd" data-epg-id="beIN Sports Ñ" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/2/2e/Bein_Sport_en_espa%C3%B1ol_logo.svg" alt="BEIN SPORTS Ñ"> | |
<span class="canal-nombre">BEIN SPORTS Ñ</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 29. DSPORTS --> | |
<div class="canal" data-url="acestream://dsportsabcdefabcdefabcdefabcdefabcdef" data-epg-id="DSports" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/4/4f/DSports_logo.svg" alt="DSPORTS"> | |
<span class="canal-nombre">DSPORTS</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
<!-- 30. TNT SPORTS --> | |
<div class="canal" data-url="acestream://tntsportsabcdefabcdefabcdefabcdefabcd" data-epg-id="TNT Sports" tabindex="0"> | |
<div class="favorito">⭐</div> | |
<img src="https://upload.wikimedia.org/wikipedia/commons/9/9d/TNT_Sports_Argentina_logo.svg" alt="TNT SPORTS"> | |
<span class="canal-nombre">TNT SPORTS</span> | |
<div class="epg"><span class="epg-cargando">Cargando… <span class="spinner"></span></span></div> | |
</div> | |
</main> | |
<!-- Reproductor de vídeo para streams .m3u8 --> | |
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> | |
<script> | |
const video = document.createElement("video"); | |
video.setAttribute("id", "reproductor-m3u8"); | |
video.setAttribute("controls", true); | |
video.setAttribute("autoplay", true); | |
video.setAttribute("playsinline", true); | |
video.setAttribute("tabindex", "0"); | |
video.style.position = "fixed"; | |
video.style.top = "0"; | |
video.style.left = "0"; | |
video.style.width = "100vw"; | |
video.style.height = "100vh"; | |
video.style.zIndex = "99999"; | |
video.style.display = "none"; | |
video.style.backgroundColor = "#000"; | |
document.body.appendChild(video); | |
let hlsPlayer = null; | |
let bloqueaPop = false; | |
let canalActivoAntesReproductor = null; | |
function reproducirM3U8(url) { | |
canalActivoAntesReproductor = document.activeElement; | |
video.pause(); | |
video.src = ""; | |
video.load(); | |
video.style.display = "block"; | |
document.body.classList.add("modo-reproductor"); | |
video.muted = false; | |
if (window.hlsPlayer) hlsPlayer.destroy(); | |
if (Hls.isSupported()) { | |
hlsPlayer = new Hls(); | |
hlsPlayer.loadSource(url); | |
hlsPlayer.attachMedia(video); | |
window.hlsPlayer = hlsPlayer; | |
} else if (video.canPlayType("application/vnd.apple.mpegurl")) { | |
video.src = url; | |
} else { | |
alert("Tu navegador no soporta este tipo de vídeo."); | |
return; | |
} | |
history.pushState({ reproductor: true }, "reproductor"); | |
bloqueaPop = true; | |
setTimeout(() => bloqueaPop = false, 300); | |
const esTV = /Android TV|BRAVIA|AFT/.test(navigator.userAgent); | |
setTimeout(() => { | |
video.play().catch(() => { | |
if (esTV) { | |
mostrarNotificacion("Presiona OK para iniciar la reproducción"); | |
video.setAttribute("controls", true); | |
video.focus(); | |
} | |
}); | |
}, 300); | |
video.addEventListener("click", () => video.play()); | |
video.addEventListener("keydown", e => { | |
if (e.key === "Enter") video.play(); | |
}); | |
} | |
function cerrarReproductor() { | |
if (hlsPlayer) { | |
hlsPlayer.destroy(); | |
hlsPlayer = null; | |
} | |
video.pause(); | |
video.removeAttribute("src"); | |
video.load(); | |
video.style.display = "none"; | |
document.body.classList.remove("modo-reproductor"); | |
if (canalActivoAntesReproductor && canalActivoAntesReproductor.classList.contains("canal")) { | |
canalActivoAntesReproductor.scrollIntoView({ behavior: "smooth", block: "center" }); | |
setTimeout(() => canalActivoAntesReproductor.focus(), 100); | |
} | |
} | |
// Swipe ← para cerrar | |
let startX = 0; | |
video.addEventListener("touchstart", e => startX = e.touches[0].clientX); | |
video.addEventListener("touchend", e => { | |
if (e.changedTouches[0].clientX - startX < -60) cerrarReproductor(); | |
}); | |
// ESC o Backspace | |
document.addEventListener("keydown", e => { | |
if ((e.key === "Escape" || e.key === "Backspace") && video.style.display === "block") { | |
cerrarReproductor(); | |
history.back(); | |
} | |
}); | |
// Botón Atrás Android TV | |
window.onpopstate = () => { | |
if (bloqueaPop) return; | |
if (video.style.display === "block") { | |
cerrarReproductor(); | |
history.pushState({ reproductor: true }, "reproductor"); | |
} | |
}; | |
// Conexión con las tarjetas de canal | |
window.addEventListener("DOMContentLoaded", () => { | |
document.querySelectorAll(".canal").forEach(canal => { | |
const url = canal.getAttribute("data-url"); | |
if (!url?.endsWith(".m3u8")) return; | |
canal.addEventListener("click", e => { | |
if (e.target.classList.contains("favorito")) return; | |
e.stopPropagation(); | |
reproducirM3U8(url); | |
}); | |
}); | |
}); | |
</script> | |
<script> | |
function emojiParaEPG(t) { | |
const txt = t.toLowerCase(); | |
if (/f[úu]tbol|liga|champions|premier|madrid|bar[çc]a/.test(txt)) return "⚽"; | |
if (/nba|baloncesto|basket/.test(txt)) return "🏀"; | |
if (/tenis|wta|atp/.test(txt)) return "🎾"; | |
if (/moto ?gp|motogp/.test(txt)) return "🏍️"; | |
if (/fórmula|formula|f1\b/.test(txt)) return "🏎️"; | |
if (/boxeo|mma|ufc/.test(txt)) return "🥊"; | |
if (/cine|pel[ií]cula/.test(txt)) return "🎬"; | |
if (/serie|cap[íi]tulo|episodio/.test(txt)) return "📺"; | |
if (/docu|documental/.test(txt)) return "📚"; | |
return "📽️"; | |
} | |
function mostrarNotificacion(texto) { | |
const toast = document.getElementById("notificacion-toast"); | |
toast.textContent = texto; | |
toast.style.display = "block"; | |
setTimeout(() => toast.style.display = "none", 2000); | |
} | |
function toggleFavorito(nombre, estrella) { | |
const favs = JSON.parse(localStorage.getItem("favs") || "[]"); | |
const idx = favs.indexOf(nombre); | |
if (idx >= 0) { | |
favs.splice(idx, 1); | |
estrella?.classList.remove("activo"); | |
mostrarNotificacion("Eliminado de favoritos"); | |
} else { | |
favs.push(nombre); | |
estrella?.classList.add("activo"); | |
mostrarNotificacion("Añadido a favoritos"); | |
} | |
localStorage.setItem("favs", JSON.stringify(favs)); | |
cargarFavoritos(); | |
buscarCanalPorPrefijo(); | |
} | |
function cargarFavoritos() { | |
const favs = JSON.parse(localStorage.getItem("favs") || "[]"); | |
document.querySelectorAll("#contenedor-canales .canal").forEach(canal => { | |
const nombre = canal.querySelector(".canal-nombre")?.textContent.trim(); | |
const estrella = canal.querySelector(".favorito"); | |
const esFav = favs.includes(nombre); | |
estrella.classList.toggle("activo", esFav); | |
estrella.style.display = esFav ? "inline-block" : "none"; | |
}); | |
} | |
let soloFavoritos = false; | |
function toggleFavoritos() { | |
soloFavoritos = !soloFavoritos; | |
buscarCanalPorPrefijo(); | |
} | |
function buscarCanalPorPrefijo() { | |
const texto = document.getElementById("buscador").value.trim().toLowerCase(); | |
const favs = JSON.parse(localStorage.getItem("favs") || "[]"); | |
document.querySelectorAll("#contenedor-canales .canal").forEach(canal => { | |
const nombreSpan = canal.querySelector(".canal-nombre"); | |
if (!nombreSpan) return; | |
const nombre = nombreSpan.textContent.trim().toLowerCase(); | |
const esFavorito = favs.includes(nombreSpan.textContent.trim()); | |
const coincide = nombre.startsWith(texto); | |
const visible = coincide && (!soloFavoritos || esFavorito); | |
canal.style.display = visible ? "block" : "none"; | |
}); | |
} | |
function abrirEventos() { | |
location.href = "https://ciriaco-liart.vercel.app/"; | |
} | |
function actualizarRelojLocal() { | |
const ahora = new Date(); | |
const formato = ahora.toLocaleString("es-ES", { | |
weekday: "long", | |
day: "numeric", | |
month: "long", | |
hour: "2-digit", | |
minute: "2-digit" | |
}).toUpperCase(); | |
document.getElementById("reloj-local-texto").textContent = formato; | |
const hora = ahora.getHours() % 12; | |
const min = ahora.getMinutes(); | |
const anguloH = (hora + min / 60) * 30; | |
const anguloM = min * 6; | |
document.getElementById("hora").setAttribute("transform", `rotate(${anguloH} 50 50)`); | |
document.getElementById("minuto").setAttribute("transform", `rotate(${anguloM} 50 50)`); | |
} | |
setInterval(actualizarRelojLocal, 1000); | |
</script> | |
<script> | |
function parseFechaEPG(str) { | |
const y = str.slice(0, 4), m = str.slice(4, 6), d = str.slice(6, 8); | |
const h = str.slice(8, 10), min = str.slice(10, 12); | |
return new Date(`${y}-${m}-${d}T${h}:${min}:00`); | |
} | |
let epgXML = null; | |
function actualizarEPG() { | |
if (!epgXML) return; | |
const ahora = new Date(); | |
document.querySelectorAll(".canal").forEach(canal => { | |
const id = canal.getAttribute("data-epg-id"); | |
const contenedor = canal.querySelector(".epg"); | |
if (!id || !contenedor) return; | |
const programas = [...epgXML.querySelectorAll(`programme[channel="${id}"]`)]; | |
const eventos = programas.map(p => { | |
return { | |
ini: parseFechaEPG(p.getAttribute("start")), | |
fin: parseFechaEPG(p.getAttribute("stop")), | |
titulo: p.querySelector("title")?.textContent || "Sin título" | |
}; | |
}).filter(e => e.fin > ahora).slice(0, 2); | |
if (!eventos.length) { | |
contenedor.textContent = "Sin datos"; | |
return; | |
} | |
const [actual, siguiente] = eventos; | |
let html = ""; | |
if (actual) { | |
const h1 = actual.ini.toTimeString().slice(0,5); | |
const h2 = actual.fin.toTimeString().slice(0,5); | |
html += `<span class="epg-actual">${emojiParaEPG(actual.titulo)} ${h1}-${h2} ${actual.titulo}</span>\n`; | |
} | |
if (siguiente) { | |
const h3 = siguiente.ini.toTimeString().slice(0,5); | |
const h4 = siguiente.fin.toTimeString().slice(0,5); | |
html += `<span>${emojiParaEPG(siguiente.titulo)} ${h3}-${h4} ${siguiente.titulo}</span>`; | |
} | |
contenedor.innerHTML = html; | |
}); | |
} | |
function cargarEPG() { | |
fetch("https://raw.githubusercontent.com/davidmuma/EPG_dobleM/refs/heads/master/guiatv.xml") | |
.then(r => r.text()) | |
.then(xml => { | |
epgXML = new DOMParser().parseFromString(xml, "text/xml"); | |
actualizarEPG(); | |
setInterval(actualizarEPG, 3600000); | |
}) | |
.catch(err => { | |
console.warn("EPG no disponible:", err); | |
document.querySelectorAll(".epg").forEach(e => e.textContent = "Sin datos"); | |
}); | |
} | |
</script> | |
<script> | |
window.addEventListener("load", () => { | |
cargarFavoritos(); | |
cargarEPG(); | |
actualizarRelojLocal(); | |
buscarCanalPorPrefijo(); | |
const esAndroidTV = /Android TV|BRAVIA|AFT/.test(navigator.userAgent); | |
if (esAndroidTV) { | |
document.getElementById("buscador")?.setAttribute("inputmode", "none"); | |
} | |
document.getElementById("buscador").addEventListener("input", () => { | |
buscarCanalPorPrefijo(); | |
}); | |
document.querySelectorAll(".canal").forEach(canal => { | |
const estrella = canal.querySelector(".favorito"); | |
const nombre = canal.querySelector(".canal-nombre")?.textContent.trim(); | |
let longPressTimer; | |
canal.addEventListener("touchstart", () => { | |
longPressTimer = setTimeout(() => toggleFavorito(nombre, estrella), 500); | |
}); | |
canal.addEventListener("touchend", () => clearTimeout(longPressTimer)); | |
canal.addEventListener("keydown", e => { | |
if (e.key === "Enter") { | |
e.preventDefault(); | |
longPressTimer = setTimeout(() => toggleFavorito(nombre, estrella), 500); | |
} | |
}); | |
canal.addEventListener("keyup", e => { | |
if (e.key === "Enter") { | |
clearTimeout(longPressTimer); | |
const url = canal.getAttribute("data-url"); | |
if (url?.endsWith(".m3u8")) { | |
reproducirM3U8(url); | |
} else if (url) { | |
window.open(url, "_blank"); | |
} | |
} | |
}); | |
canal.addEventListener("click", e => { | |
if (e.target.classList.contains("favorito")) { | |
toggleFavorito(nombre, estrella); | |
e.stopPropagation(); | |
return; | |
} | |
const url = canal.getAttribute("data-url"); | |
if (url?.endsWith(".m3u8")) { | |
reproducirM3U8(url); | |
} else if (url) { | |
window.open(url, "_blank"); | |
} | |
}); | |
}); | |
}); | |
window.addEventListener("popstate", () => { | |
if (!document.body.classList.contains("modo-reproductor")) { | |
// No autoenfoque al volver: navegación libre | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment