|
<!DOCTYPE html> |
|
<html lang="es"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>DaddyTV - Panel de Administración</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<script> |
|
tailwind.config = { |
|
theme: { |
|
extend: { |
|
colors: { |
|
primary: { |
|
500: '#3b82f6', |
|
600: '#2563eb', |
|
700: '#1d4ed8' |
|
} |
|
} |
|
} |
|
} |
|
} |
|
</script> |
|
</head> |
|
<body class="bg-gray-900 text-white min-h-screen"> |
|
<div class="container mx-auto px-4 py-8"> |
|
<div class="max-w-4xl mx-auto"> |
|
<h1 class="text-3xl font-bold mb-8 text-center">🔧 Panel de Administración DaddyTV</h1> |
|
|
|
|
|
<div id="loginSection" class="bg-gray-800 rounded-lg p-6 mb-6"> |
|
<h2 class="text-xl font-semibold mb-4">Autenticación</h2> |
|
<div class="flex space-x-4"> |
|
<input |
|
type="password" |
|
id="adminCode" |
|
placeholder="Código de administrador" |
|
class="flex-1 bg-gray-700 border border-gray-600 rounded px-3 py-2" |
|
> |
|
<button |
|
onclick="authenticate()" |
|
class="bg-primary-600 hover:bg-primary-700 px-6 py-2 rounded font-medium" |
|
> |
|
Conectar |
|
</button> |
|
</div> |
|
<div id="authStatus" class="mt-2 text-sm"></div> |
|
</div> |
|
|
|
|
|
<div id="adminPanel" class="hidden space-y-6"> |
|
|
|
<div class="bg-gray-800 rounded-lg p-6"> |
|
<h2 class="text-xl font-semibold mb-4">📊 Estado del Sistema</h2> |
|
<div id="systemStatus" class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
|
|
|
</div> |
|
<button |
|
onclick="refreshStatus()" |
|
class="mt-4 bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded" |
|
> |
|
🔄 Actualizar |
|
</button> |
|
</div> |
|
|
|
|
|
<div class="bg-gray-800 rounded-lg p-6"> |
|
<h2 class="text-xl font-semibold mb-4">⚡ Acciones</h2> |
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
<button |
|
onclick="clearCache()" |
|
class="bg-yellow-600 hover:bg-yellow-700 px-4 py-3 rounded font-medium" |
|
> |
|
🗑️ Limpiar Caché |
|
</button> |
|
<button |
|
onclick="downloadLogs()" |
|
class="bg-green-600 hover:bg-green-700 px-4 py-3 rounded font-medium" |
|
> |
|
📥 Descargar Logs |
|
</button> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-gray-800 rounded-lg p-6"> |
|
<h2 class="text-xl font-semibold mb-4">⚙️ Configuración</h2> |
|
<div class="space-y-4"> |
|
<div> |
|
<label class="block text-sm font-medium mb-2">URL de Playlist M3U</label> |
|
<input |
|
type="url" |
|
id="m3uUrl" |
|
placeholder="https://ejemplo.com/playlist.m3u8" |
|
class="w-full bg-gray-700 border border-gray-600 rounded px-3 py-2" |
|
> |
|
</div> |
|
<button |
|
onclick="updatePlaylist()" |
|
class="bg-primary-600 hover:bg-primary-700 px-4 py-2 rounded font-medium" |
|
> |
|
💾 Actualizar Playlist |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
let adminToken = ''; |
|
const API_BASE = '/api'; |
|
|
|
async function authenticate() { |
|
const code = document.getElementById('adminCode').value; |
|
const statusDiv = document.getElementById('authStatus'); |
|
|
|
if (!code) { |
|
statusDiv.innerHTML = '<span class="text-red-400">Por favor ingresa el código</span>'; |
|
return; |
|
} |
|
|
|
try { |
|
const response = await fetch(`${API_BASE}/admin/status`, { |
|
headers: { |
|
'Authorization': `Bearer ${code}` |
|
} |
|
}); |
|
|
|
if (response.ok) { |
|
adminToken = code; |
|
statusDiv.innerHTML = '<span class="text-green-400">✅ Autenticado correctamente</span>'; |
|
document.getElementById('loginSection').classList.add('hidden'); |
|
document.getElementById('adminPanel').classList.remove('hidden'); |
|
await refreshStatus(); |
|
} else { |
|
statusDiv.innerHTML = '<span class="text-red-400">❌ Código incorrecto</span>'; |
|
} |
|
} catch (error) { |
|
statusDiv.innerHTML = '<span class="text-red-400">❌ Error de conexión</span>'; |
|
} |
|
} |
|
|
|
async function refreshStatus() { |
|
try { |
|
const response = await fetch(`${API_BASE}/admin/status`, { |
|
headers: { |
|
'Authorization': `Bearer ${adminToken}` |
|
} |
|
}); |
|
|
|
if (response.ok) { |
|
const data = await response.json(); |
|
displaySystemStatus(data); |
|
} |
|
} catch (error) { |
|
console.error('Error refreshing status:', error); |
|
} |
|
} |
|
|
|
function displaySystemStatus(data) { |
|
const statusDiv = document.getElementById('systemStatus'); |
|
statusDiv.innerHTML = ` |
|
<div class="bg-gray-700 p-4 rounded"> |
|
<h3 class="font-semibold mb-2">📺 Canales</h3> |
|
<p>Cacheados: ${data.cache_status.m3u_cached ? '✅' : '❌'}</p> |
|
<p>Total: ${data.cache_status.channels_count}</p> |
|
<p class="text-xs text-gray-400">Última actualización: ${data.cache_status.cache_timestamp || 'Nunca'}</p> |
|
</div> |
|
<div class="bg-gray-700 p-4 rounded"> |
|
<h3 class="font-semibold mb-2">👥 Visualizadores</h3> |
|
<p>Usuarios activos: ${data.viewers_status.active_users}</p> |
|
<p>Canales activos: ${data.viewers_status.active_channels}</p> |
|
<p>Total viewers: ${data.viewers_status.total_viewers}</p> |
|
</div> |
|
<div class="bg-gray-700 p-4 rounded"> |
|
<h3 class="font-semibold mb-2">⚙️ Configuración</h3> |
|
<p>M3U URL: ${data.config.m3u_url_configured ? '✅' : '❌'}</p> |
|
<p>Admin Code: ${data.config.admin_code_configured ? '✅' : '❌'}</p> |
|
<p class="text-xs text-gray-400">Base URL: ${data.config.base_url}</p> |
|
</div> |
|
`; |
|
} |
|
|
|
async function clearCache() { |
|
try { |
|
const response = await fetch(`${API_BASE}/admin/update`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Authorization': `Bearer ${adminToken}` |
|
}, |
|
body: JSON.stringify({ |
|
action: 'clear_cache' |
|
}) |
|
}); |
|
|
|
if (response.ok) { |
|
const data = await response.json(); |
|
alert('✅ ' + data.message); |
|
await refreshStatus(); |
|
} else { |
|
alert('❌ Error al limpiar caché'); |
|
} |
|
} catch (error) { |
|
alert('❌ Error de conexión'); |
|
} |
|
} |
|
|
|
async function updatePlaylist() { |
|
const url = document.getElementById('m3uUrl').value; |
|
if (!url) { |
|
alert('Por favor ingresa una URL válida'); |
|
return; |
|
} |
|
|
|
try { |
|
const response = await fetch(`${API_BASE}/admin/update`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Authorization': `Bearer ${adminToken}` |
|
}, |
|
body: JSON.stringify({ |
|
action: 'update_playlist', |
|
m3u_url: url |
|
}) |
|
}); |
|
|
|
if (response.ok) { |
|
const data = await response.json(); |
|
alert('✅ ' + data.message); |
|
} else { |
|
alert('❌ Error al actualizar playlist'); |
|
} |
|
} catch (error) { |
|
alert('❌ Error de conexión'); |
|
} |
|
} |
|
|
|
function downloadLogs() { |
|
alert('📥 Función de descarga de logs no implementada aún'); |
|
} |
|
|
|
|
|
document.getElementById('adminCode').focus(); |
|
|
|
|
|
document.getElementById('adminCode').addEventListener('keypress', function(e) { |
|
if (e.key === 'Enter') { |
|
authenticate(); |
|
} |
|
}); |
|
</script> |
|
</body> |
|
</html> |