anycoder-7bce00f9 / index.html
Rubentnoda's picture
Upload folder using huggingface_hub
8783795 verified
Raw
History Blame Contribute Delete
33.9 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Control Multimedia Chromecast - Hostelería</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #2563eb;
--secondary: #7c3aed;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--dark: #1f2937;
--light: #f3f4f6;
--card-bg: rgba(255, 255, 255, 0.95);
--gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--gradient-2: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #1e3a8a 0%, #312e81 50%, #581c87 100%);
min-height: 100vh;
color: var(--dark);
position: relative;
overflow-x: hidden;
}
/* Animated background */
.bg-animation {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: -1;
opacity: 0.1;
}
.floating-shape {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
animation: float 20s infinite ease-in-out;
}
@keyframes float {
0%,
100% {
transform: translateY(0) rotate(0deg);
}
33% {
transform: translateY(-30px) rotate(120deg);
}
66% {
transform: translateY(30px) rotate(240deg);
}
}
/* Header */
header {
background: var(--card-bg);
backdrop-filter: blur(20px);
padding: 1.5rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
position: sticky;
top: 0;
z-index: 100;
animation: slideDown 0.5s ease-out;
}
@keyframes slideDown {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.header-content {
max-width: 1400px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
h1 {
font-size: 1.8rem;
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-indicators {
display: flex;
gap: 1rem;
align-items: center;
}
.status-badge {
padding: 0.5rem 1rem;
border-radius: 20px;
font-weight: 600;
font-size: 0.9rem;
display: flex;
align-items: center;
gap: 0.5rem;
animation: pulse 2s infinite;
}
.status-badge.online {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: white;
}
.status-badge.streaming {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
color: white;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.8;
}
}
/* Main container */
.container {
max-width: 1400px;
margin: 2rem auto;
padding: 0 1rem;
}
/* TV Status Grid */
.tv-status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.tv-card {
background: var(--card-bg);
border-radius: 20px;
padding: 1.5rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
animation: fadeInUp 0.6s ease-out;
}
@keyframes fadeInUp {
from {
transform: translateY(30px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.tv-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
}
.tv-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.tv-name {
font-size: 1.2rem;
font-weight: 700;
color: var(--dark);
display: flex;
align-items: center;
gap: 0.5rem;
}
.tv-status {
padding: 0.3rem 0.8rem;
border-radius: 15px;
font-size: 0.85rem;
font-weight: 600;
}
.tv-status.connected {
background: #dcfce7;
color: #16a34a;
}
.tv-status.disconnected {
background: #fee2e2;
color: #dc2626;
}
.tv-status.playing {
background: #fef3c7;
color: #d97706;
}
.tv-info {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
.info-item {
display: flex;
justify-content: space-between;
padding: 0.5rem;
background: var(--light);
border-radius: 10px;
font-size: 0.9rem;
}
.info-label {
font-weight: 600;
color: #6b7280;
}
.info-value {
color: var(--dark);
}
.tv-controls {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
/* Control Panel */
.control-panel {
background: var(--card-bg);
border-radius: 20px;
padding: 2rem;
margin-bottom: 2rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.panel-header {
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 1.5rem;
color: var(--dark);
display: flex;
align-items: center;
gap: 0.5rem;
}
.video-input-section {
margin-bottom: 2rem;
}
.input-group {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
.video-input {
flex: 1;
padding: 1rem;
font-size: 1rem;
border: 2px solid #e5e7eb;
border-radius: 12px;
transition: all 0.3s;
}
.video-input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
/* Buttons */
.btn {
padding: 0.8rem 1.5rem;
font-size: 1rem;
font-weight: 600;
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.btn-primary {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
color: white;
}
.btn-success {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: white;
}
.btn-warning {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
color: white;
}
.btn-danger {
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
color: white;
}
.btn-secondary {
background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);
color: white;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
.btn:active {
transform: translateY(0);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
/* Media Controls */
.media-controls {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 2rem;
}
.control-btn {
width: 60px;
height: 60px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
}
.volume-control {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: var(--light);
border-radius: 12px;
}
.volume-slider {
flex: 1;
height: 6px;
border-radius: 3px;
background: #e5e7eb;
outline: none;
-webkit-appearance: none;
}
.volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--primary);
cursor: pointer;
}
/* Playlist */
.playlist-section {
background: var(--card-bg);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.playlist-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.playlist-items {
display: flex;
flex-direction: column;
gap: 0.5rem;
max-height: 300px;
overflow-y: auto;
}
.playlist-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background: var(--light);
border-radius: 12px;
transition: all 0.3s;
cursor: pointer;
}
.playlist-item:hover {
background: #e5e7eb;
transform: translateX(5px);
}
.playlist-item.active {
background: linear-gradient(135deg, #ddd6fe 0%, #c4b5fd 100%);
color: var(--dark);
}
.playlist-info {
display: flex;
align-items: center;
gap: 1rem;
}
.playlist-thumbnail {
width: 60px;
height: 40px;
border-radius: 8px;
object-fit: cover;
}
.playlist-text h4 {
font-size: 1rem;
margin-bottom: 0.2rem;
}
.playlist-text p {
font-size: 0.85rem;
color: #6b7280;
}
/* Progress bar */
.progress-container {
margin-bottom: 1.5rem;
}
.progress-bar {
width: 100%;
height: 8px;
background: #e5e7eb;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #3b82f6 0%, #2563eb 100%);
border-radius: 4px;
transition: width 0.1s;
position: relative;
}
.progress-time {
display: flex;
justify-content: space-between;
margin-top: 0.5rem;
font-size: 0.85rem;
color: #6b7280;
}
/* Quick actions */
.quick-actions {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.action-card {
background: var(--card-bg);
border-radius: 15px;
padding: 1.5rem;
text-align: center;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.action-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
.action-icon {
font-size: 2.5rem;
margin-bottom: 0.5rem;
}
.action-title {
font-weight: 600;
color: var(--dark);
margin-bottom: 0.3rem;
}
.action-desc {
font-size: 0.85rem;
color: #6b7280;
}
/* Toast notification */
.toast {
position: fixed;
bottom: 2rem;
right: 2rem;
background: white;
padding: 1rem 1.5rem;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
gap: 1rem;
transform: translateX(400px);
transition: transform 0.3s;
z-index: 1000;
}
.toast.show {
transform: translateX(0);
}
.toast-icon {
font-size: 1.5rem;
}
.toast.success {
border-left: 4px solid var(--success);
}
.toast.error {
border-left: 4px solid var(--danger);
}
.toast.info {
border-left: 4px solid var(--primary);
}
/* Footer */
footer {
text-align: center;
padding: 2rem;
color: white;
margin-top: 3rem;
}
.built-with {
color: white;
text-decoration: none;
font-weight: 600;
background: rgba(255, 255, 255, 0.2);
padding: 0.5rem 1rem;
border-radius: 10px;
display: inline-block;
transition: all 0.3s;
}
.built-with:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
/* Responsive */
@media (max-width: 768px) {
h1 {
font-size: 1.3rem;
}
.tv-status-grid {
grid-template-columns: 1fr;
}
.quick-actions {
grid-template-columns: repeat(2, 1fr);
}
.header-content {
flex-direction: column;
text-align: center;
}
.status-indicators {
flex-wrap: wrap;
justify-content: center;
}
}
/* Loading spinner */
.spinner {
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
Modal .modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: none;
justify-content: center;
align-items: center;
z-index: 2000;
}
.modal.show {
display: flex;
}
.modal-content {
background: white;
border-radius: 20px;
padding: 2rem;
max-width: 500px;
width: 90%;
animation: popIn 0.3s ease-out;
}
@keyframes popIn {
from {
transform: scale(0.8);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
</style>
</head>
<body>
<!-- Animated background -->
<div class="bg-animation">
<div class="floating-shape" style="width: 100px; height: 100px; top: 10%; left: 10%; animation-delay: 0s;"></div>
<div class="floating-shape" style="width: 150px; height: 150px; top: 70%; right: 10%; animation-delay: 5s;"></div>
<div class="floating-shape" style="width: 80px; height: 80px; bottom: 20%; left: 50%; animation-delay: 10s;"></div>
</div>
<!-- Header -->
<header>
<div class="header-content">
<h1>
📺 Control Multimedia Chromecast
</h1>
<div class="status-indicators">
<div class="status-badge online">
<span>🟢</span>
<span>3 TVs Conectadas</span>
</div>
<div class="status-badge streaming" id="streamingBadge" style="display: none;">
<span>🔴</span>
<span>Transmitiendo</span>
</div>
</div>
</div>
</header>
<!-- Main container -->
<div class="container">
<!-- Quick Actions -->
<div class="quick-actions">
<div class="action-card" onclick="playAllTvs()">
<div class="action-icon">▶️</div>
<div class="action-title">Reproducir</div>
<div class="action-desc">En todas las TVs</div>
</div>
<div class="action-card" onclick="pauseAllTvs()">
<div class="action-icon">⏸️</div>
<div class="action-title">Pausar</div>
<div class="action-desc">Detener reproducción</div>
</div>
<div class="action-card" onclick="stopAllTvs()">
<div class="action-icon">⏹️</div>
<div class="action-title">Detener</div>
<div class="action-desc">Finalizar transmisión</div>
</div>
<div class="action-card" onclick="muteAllTvs()">
<div class="action-icon">🔇</div>
<div class="action-title">Silenciar</div>
<div class="action-desc">Todas las TVs</div>
</div>
</div>
<!-- TV Status Grid -->
<div class="tv-status-grid">
<div class="tv-card">
<div class="tv-header">
<div class="tv-name">
<span>📺</span>
<span>TV - Sala Principal</span>
</div>
<div class="tv-status connected" id="tv1-status">Conectado</div>
</div>
<div class="tv-info">
<div class="info-item">
<span class="info-label">Dispositivo:</span>
<span class="info-value">Chromecast Ultra</span>
</div>
<div class="info-item">
<span class="info-label">Reproduciendo:</span>
<span class="info-value" id="tv1-content">Esperando...</span>
</div>
<div class="info-item">
<span class="info-label">Volumen:</span>
<span class="info-value" id="tv1-volume">50%</span>
</div>
</div>
<div class="tv-controls">
<button class="btn btn-success control-btn" onclick="controlTv(1, 'play')">▶️</button>
<button class="btn btn-warning control-btn" onclick="controlTv(1, 'pause')">⏸️</button>
<button class="btn btn-danger control-btn" onclick="controlTv(1, 'stop')">⏹️</button>
<button class="btn btn-secondary control-btn" onclick="controlTv(1, 'mute')">🔇</button>
</div>
</div>
<div class="tv-card">
<div class="tv-header">
<div class="tv-name">
<span>📺</span>
<span>TV - Barra</span>
</div>
<div class="tv-status connected" id="tv2-status">Conectado</div>
</div>
<div class="tv-info">
<div class="info-item">
<span class="info-label">Dispositivo:</span>
<span class="info-value">Chromecast 4K</span>
</div>
<div class="info-item">
<span class="info-label">Reproduciendo:</span>
<span class="info-value" id="tv2-content">Esperando...</span>
</div>
<div class="info-item">
<span class="info-label">Volumen:</span>
<span class="info-value" id="tv2-volume">50%</span>
</div>
</div>
<div class="tv-controls">
<button class="btn btn-success control-btn" onclick="controlTv(2, 'play')">▶️</button>
<button class="btn btn-warning control-btn" onclick="controlTv(2, 'pause')">⏸️</button>
<button class="btn btn-danger control-btn" onclick="controlTv(2, 'stop')">⏹️</button>
<button class="btn btn-secondary control-btn" onclick="controlTv(2, 'mute')">🔇</button>
</div>
</div>
<div class="tv-card">
<div class="tv-header">
<div class="tv-name">
<span>📺</span>
<span>TV - Terraza</span>
</div>
<div class="tv-status connected" id="tv3-status">Conectado</div>
</div>
<div class="tv-info">
<div class="info-item">
<span class="info-label">Dispositivo:</span>
<span class="info-value">Chromecast with Google TV</span>
</div>
<div class="info-item">
<span class="info-label">Reproduciendo:</span>
<span class="info-value" id="tv3-content">Esperando...</span>
</div>
<div class="info-item">
<span class="info-label">Volumen:</span>
<span class="info-value" id="tv3-volume">50%</span>
</div>
</div>
<div class="tv-controls">
<button class="btn btn-success control-btn" onclick="controlTv(3, 'play')">▶️</button>
<button class="btn btn-warning control-btn" onclick="controlTv(3, 'pause')">⏸️</button>
<button class="btn btn-danger control-btn" onclick="controlTv(3, 'stop')">⏹️</button>
<button class="btn btn-secondary control-btn" onclick="controlTv(3, 'mute')">🔇</button>
</div>
</div>
</div>
<!-- Control Panel -->
<div class="control-panel">
<h2 class="panel-header">
<span>🎬</span>
<span>Control de Reproducción</span>
</h2>
<!-- Video Input -->
<div class="video-input-section">
<div class="input-group">
<input type="text" class="video-input" id="videoUrl" placeholder="Introduce URL del video (YouTube, Vimeo, URL directa)">
<button class="btn btn-primary" onclick="loadVideo()">
<span>📥</span>
<span>Cargar Video</span>
</button>
</div>
<div class="input-group">
<button class="btn btn-secondary" onclick="loadSampleVideo('youtube')">
<span>📺</span>
<span>YouTube Sample</span>
</button>
<button class="btn btn-secondary" onclick="loadSampleVideo('vimeo')">
<span>🎥</span>
<span>Vimeo Sample</span>
</button>
<button class="btn btn-secondary" onclick="loadSampleVideo('direct')">
<span>🔗</span>
<span>URL Directa</span>
</button>
</div>
</div>
<!-- Progress Bar -->
<div class="progress-container">
<div class="progress-bar" onclick="seekVideo(event)">
<div class="progress-fill" id="progressFill" style="width: 0%"></div>
</div>
<div class="progress-time">
<span id="currentTime">00:00</span>
<span id="duration">00:00</span>
</div>
</div>
<!-- Media Controls -->
<div class="media-controls">
<button class="btn btn-secondary control-btn" onclick="rewind()"></button>
<button class="btn btn-success control-btn" onclick="playAllTvs()">▶️</button>
<button class="btn btn-warning control-btn" onclick="pauseAllTvs()">⏸️</button>
<button class="btn btn-danger control-btn" onclick="stopAllTvs()">⏹️</button>
<button class="btn btn-secondary control-btn" onclick="forward()"></button>
</div>
<!-- Volume Control -->
<div class="volume-control">
<span>🔊</span>
<input type="range" class="volume-slider" id="masterVolume" min="0" max="100" value="50" onchange="changeVolume(this.value)">
<span id="volumePercentage">50%</span>
</div>
</div>
<!-- Playlist -->
<div class="playlist-section">
<div class="playlist-header">
<h2 class="panel-header">
<span>📋</span>
<span>Playlist de Videos</span>
</h2>
<button class="btn btn-primary" onclick="addToPlaylist()">
<span></span>
<span>Agregar a Playlist</span>
</button>
</div>
<div class="playlist-items" id="playlistItems">
<div class="playlist-item active"
onclick="playFromPlaylist(this, 'https://www.youtube.com/watch?v=dQw4w9WgXcQ')">
<div class="playlist-info">
<img src="https://picsum.photos/seed/video1/60/40" alt="Thumbnail" class="playlist-thumbnail">
<div class="playlist-text">
<h4>Video Promocional</h4>
<p>YouTube • 3:45</p>
</div>
</div>
<button class="btn btn-success" onclick="event.stopPropagation(); playVideoNow(this)">▶️</button>
</div>
<div class="playlist-item" onclick="playFromPlaylist(this, 'https://vimeo.com/123456789')">
<div class="playlist-info">
<img src="https://picsum.photos/seed/video2/60/40" alt="Thumbnail" class="playlist-thumbnail">
<div class="playlist-text">
<h4>Video Corporativo</h4>
<p>Vimeo • 2:30</p>
</div>
</div>
<button class="btn btn-success" onclick="event.stopPropagation(); playVideoNow(this)">▶️</button>
</div>
<div class="playlist-item" onclick="playFromPlaylist(this, 'https://example.com/video.mp4')">
<div class="playlist-info">
<img src="https://picsum.photos/seed/video3/60/40" alt="Thumbnail" class="playlist-thumbnail">
<div class="playlist-text">
<h4>Video Evento</h4>
<p>Directo • 5:15</p>
</div>
</div>
<button class="btn btn-success" onclick="event.stopPropagation(); playVideoNow(this)">▶️</button>
</div>
</div>
</div>
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<span class="toast-icon" id="toastIcon"></span>
<div>
<div id="toastTitle">Operación Exitosa</div>
<div id="toastMessage" style="font-size: 0.85rem; color: #6b7280;">Acción completada</div>
</div>
</div>
<!-- Footer -->
<footer>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">
Built with anycoder
</a>
</footer>
<script>
// Global state
let isPlaying = false;
let currentVideo = null;
let tvStates = {
1: { connected: true, playing: false, volume: 50, content: 'Esperando...' },
2: { connected: true, playing: false, volume: 50, content: 'Esperando...' },
3: { connected: true, playing: false, volume: 50, content: 'Esperando...' }
};
// Initialize
document.addEventListener('DOMContentLoaded', function() {
simulateConnection();
updateProgress();
});
// Simulate initial connection
function simulateConnection() {
showToast('Conectando a dispositivos...', 'info');
setTimeout(() => {
showToast('Todos los dispositivos conectados correctamente', 'success');
}, 2000);
}
// Load video
function loadVideo() {
const url = document.getElementById('videoUrl').value;
if (!url) {
showToast('Por favor, introduce una URL válida', 'error');
return;
}
currentVideo = url;
showToast('Cargando video...', 'info');
setTimeout(() => {
updateAllTvsContent(extractVideoName(url));
document.getElementById('streamingBadge').style.display = 'flex';
showToast('Video cargado en todas las TVs', 'success');
}, 1500);
}
// Load sample videos
function loadSampleVideo(type) {
const samples = {
youtube: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
vimeo: 'https://vimeo.com/123456789',
direct: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
};
document.getElementById('videoUrl').value = samples[type];
loadVideo();
}
// Extract video name from URL
function extractVideoName(url) {
if (url.includes('youtube')) return 'Video de YouTube';
if (url.includes('vimeo')) return 'Video de Vimeo';
if (url.includes('.mp4')) return 'Video Directo';
return 'Video Online';
}
// Control individual TV
function controlTv(tvId, action) {
const tv = tvStates[tvId];
switch(action) {
case 'play':
if (currentVideo) {
tv.playing = true;
updateTvStatus(tvId, 'playing');
showToast(`TV ${tvId} reproduciendo`, 'success');
} else {
showToast('No hay video cargado', 'error');
}
break;
case 'pause':
tv.playing = false;
updateTvStatus(tvId, 'connected');
showToast(`TV ${tvId} pausado`, 'info');
break;
case 'stop':
tv.playing = false;
tv.content = 'Esperando...';
updateTvInfo(tvId);
updateTvStatus(tvId, 'connected');
showToast(`TV ${tvId} detenido`, 'info');
break;
case 'mute':
tv.volume = tv.volume > 0 ? 0 : 50;
document.getElementById(`tv${tvId}-volume`).textContent = tv.volume + '%';
showToast(`TV ${tvId} silenciado/activado`, 'info');
break;
}
}
// Control all TVs
function playAllTvs() {
if (!currentVideo) {
showToast('Por favor, carga un video primero', 'error');
return;
}
for (let i = 1; i <= 3; i++) {
tvStates[i].playing = true;
updateTvStatus(i, 'playing');
}
isPlaying = true;
document.getElementById('streamingBadge').style.display = 'flex';
showToast('Reproduciendo en todas las TVs', 'success');
}
function pauseAllTvs() {
for (let i = 1; i <= 3; i++) {
tvStates[i].playing = false;
updateTvStatus(i, 'connected');
}
isPlaying = false;
showToast('Pausado en todas las TVs', 'info');
}
function stopAllTvs() {
for (let i = 1; i <= 3; i++) {
tvStates[i].playing = false;
tvStates[i].content = 'Esperando...';
updateTvInfo(i);
updateTvStatus(i, 'connected');
}
isPlaying = false;
currentVideo = null;
document.getElementById('streamingBadge').style.display = 'none';
document.getElementById('videoUrl').value = '';
showToast('Transmisión detenida', 'info');
}
function muteAllTvs() {
for (let i = 1; i <= 3; i++) {
tvStates[i].volume = tvStates[i].volume > 0 ? 0 : 50;
document.getElementById(`tv${i}-volume`).textContent = tvStates[i].volume + '%';
}
showToast('Silencio toggled en todas las TVs', 'info');
}
// Volume control
function changeVolume(value) {
for (let i = 1; i <= 3; i++) {
tvStates[i].volume = value;
document.getElementById(`tv${i}-volume`).textContent = value + '%';
}
document.getElementById('volumePercentage').textContent = value + '%';
showToast(`Volumen ajustado a ${value}%`, 'info');
}
// Update functions
function updateTvStatus(tvId, status) {
const statusElement = document.getElementById(`tv${tvId}-status`);
statusElement.className = `tv-status ${status}`;
const statusText = {
connected: 'Conectado',
playing: 'Reproduciendo',
disconnected: 'Desconectado'
};
statusElement.textContent = statusText[status];
}
function updateTvInfo(tvId) {
const tv = tvStates[tvId];
document.getElementById(`tv${tvId}-content`).textContent = tv.content;
document.getElementById(`tv${tvId}-volume`).textContent = tv.volume + '%';
}
function updateAllTvsContent(content) {
for (let i = 1; i <= 3; i++) {
tvStates[i].content = content;
updateTvInfo(i);
}
}
// Progress bar simulation
function updateProgress() {
let progress = 0;
setInterval(() => {
if (isPlaying && progress < 100) {
progress += 0.5;
document.getElementById('progressFill').style.width = progress + '%';
// Update time
const current = Math.floor(progress * 2.25);
const minutes = Math.floor(current / 60);
const seconds = current % 60;
document.getElementById('currentTime').textContent =
`${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
}, 1000);
}
// Seek video
function seekVideo(event) {
const progressBar = event.currentTarget;
const clickX = event.offsetX;
const width = progressBar.offsetWidth;
const percentage = (clickX / width) * 100;
document.getElementById('progressFill').style.width = percentage + '%';
showToast(`Buscando: ${Math.round(percentage)}%`, 'info');
}
// Playback controls
function rewind() {
showToast('Rebobinando 10 segundos', 'info');
const currentWidth = parseFloat(document.getElementById('progressFill').style.width) || 0;
const newWidth = Math.max(0, currentWidth - 5);
document.getElementById('progressFill').style.width = newWidth + '%';
}
function forward() {
showToast('Adelantando 10 segundos', 'info');
const currentWidth = parseFloat(document.getElementById('progressFill').style.width) || 0;
const newWidth = Math.min(100, currentWidth + 5);
document.getElementById('progressFill').style.width = newWidth + '%';
}
// Playlist functions
function playFromPlaylist(element, url) {
document.querySelectorAll('.playlist-item').forEach(item => {
item.classList.remove('active');
});
element.classList.add('active');
document.getElementById('videoUrl').value = url;
loadVideo();
}
function playVideoNow(button) {
const item = button.closest('.playlist-item');
item.click();
}
function addToPlaylist() {
const url = document.getElementById('videoUrl').value;
if (!url) {
showToast('Introduce una URL primero', 'error');
return;
}
const playlist = document.getElementById('playlistItems');
const newItem = document.createElement('div');
newItem.className = 'playlist-item';
newItem.innerHTML = `
<div class="playlist-info">
<img src="https://picsum.photos/seed/${Date.now()}/60/40" alt="Thumbnail" class="playlist-thumbnail">
<div class="playlist-text">
<h4>Video Agregado</h4>
<p>Custom • --:--</p>
</div>
</div>
<button class="btn btn-danger" onclick="event.stopPropagation(); this.parentElement.remove()">🗑️</button>
`;
playlist.appendChild(newItem);
showToast('Video agregado a la playlist', 'success');
}
// Toast notification
function showToast(message, type = 'success') {
const toast = document.getElementById('toast');
const icon = document.getElementById('toastIcon');
const title = document.getElementById('toastTitle');
const icons = {
success: '✅',
error: '❌',
info: 'ℹ️'
};
const titles = {
success: 'Operación Exitosa',
error: 'Error',
info: 'Información'
};
toast.className = `toast ${type}`;
icon.textContent = icons[type];
title.textContent = titles[type];
document.getElementById('toastMessage').textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
</script>
</body>
</html>