Spaces:
Paused
Paused
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>TorchFlix API Dashboard</title> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg-color: #0f172a; | |
| --panel-bg: #1e293b; | |
| --text-color: #f8fafc; | |
| --accent-color: #3b82f6; | |
| --accent-hover: #2563eb; | |
| --border-color: #334155; | |
| --success: #10b981; | |
| --error: #ef4444; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background-color: var(--bg-color); | |
| color: var(--text-color); | |
| margin: 0; | |
| padding: 20px; | |
| line-height: 1.6; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| display: grid; | |
| grid-template-columns: 300px 1fr; | |
| gap: 20px; | |
| } | |
| .header { | |
| grid-column: 1 / -1; | |
| display: flex; | |
| align-items: center; | |
| padding: 20px; | |
| background: var(--panel-bg); | |
| border-radius: 12px; | |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); | |
| } | |
| .header h1 { | |
| margin: 0; | |
| font-size: 24px; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .header h1 i { | |
| color: var(--success); | |
| } | |
| .sidebar { | |
| background: var(--panel-bg); | |
| padding: 20px; | |
| border-radius: 12px; | |
| height: fit-content; | |
| } | |
| .api-key-section { | |
| margin-bottom: 20px; | |
| padding-bottom: 20px; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .api-key-input { | |
| width: 100%; | |
| padding: 10px; | |
| margin-top: 10px; | |
| background: var(--bg-color); | |
| border: 1px solid var(--border-color); | |
| color: var(--text-color); | |
| border-radius: 6px; | |
| box-sizing: border-box; | |
| } | |
| .endpoint-btn { | |
| width: 100%; | |
| padding: 12px 15px; | |
| margin-bottom: 8px; | |
| background: transparent; | |
| border: 1px solid var(--border-color); | |
| color: var(--text-color); | |
| border-radius: 8px; | |
| cursor: pointer; | |
| text-align: left; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .endpoint-btn:hover, .endpoint-btn.active { | |
| background: var(--accent-color); | |
| border-color: var(--accent-color); | |
| } | |
| .main-content { | |
| background: var(--panel-bg); | |
| padding: 25px; | |
| border-radius: 12px; | |
| } | |
| .request-config { | |
| background: var(--bg-color); | |
| padding: 20px; | |
| border-radius: 8px; | |
| margin-bottom: 20px; | |
| } | |
| .input-group { | |
| margin-bottom: 15px; | |
| } | |
| .input-group label { | |
| display: block; | |
| margin-bottom: 5px; | |
| color: #94a3b8; | |
| font-size: 14px; | |
| } | |
| .input-group input, .input-group select { | |
| width: 100%; | |
| padding: 10px; | |
| background: var(--panel-bg); | |
| border: 1px solid var(--border-color); | |
| color: var(--text-color); | |
| border-radius: 6px; | |
| box-sizing: border-box; | |
| } | |
| .execute-btn { | |
| background: var(--success); | |
| color: white; | |
| border: none; | |
| padding: 12px 24px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| font-size: 16px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| transition: background 0.2s; | |
| } | |
| .execute-btn:hover { | |
| background: #059669; | |
| } | |
| .response-area { | |
| background: #000; | |
| border-radius: 8px; | |
| overflow: hidden; | |
| margin-top: 20px; | |
| } | |
| .response-header { | |
| background: #1a1a1a; | |
| padding: 10px 15px; | |
| border-bottom: 1px solid #333; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .status-badge { | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| font-weight: bold; | |
| } | |
| .status-200 { background: #064e3b; color: #34d399; } | |
| .status-error { background: #7f1d1d; color: #f87171; } | |
| pre { | |
| margin: 0; | |
| padding: 15px; | |
| overflow-x: auto; | |
| color: #a78bfa; | |
| font-size: 14px; | |
| } | |
| .hidden { | |
| display: none ; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1><i class="fas fa-server"></i> TorchFlix API Dashboard</h1> | |
| </div> | |
| <div class="sidebar"> | |
| <div class="api-key-section"> | |
| <label><i class="fas fa-key"></i> API Key</label> | |
| <input type="password" id="apiKey" class="api-key-input" value="elijah2909_secret_key" placeholder="Enter API Key"> | |
| </div> | |
| <h3>Movie APIs</h3> | |
| <button class="endpoint-btn" onclick="selectEndpoint('search')"> | |
| <i class="fas fa-search"></i> Search Movies | |
| </button> | |
| <button class="endpoint-btn" onclick="selectEndpoint('trending')"> | |
| <i class="fas fa-fire"></i> Trending | |
| </button> | |
| <button class="endpoint-btn active" onclick="selectEndpoint('media-files')"> | |
| <i class="fas fa-film"></i> Media Files | |
| </button> | |
| <button class="endpoint-btn" onclick="selectEndpoint('homepage')"> | |
| <i class="fas fa-home"></i> Homepage | |
| </button> | |
| <button class="endpoint-btn" onclick="selectEndpoint('details')"> | |
| <i class="fas fa-info-circle"></i> Movie Details | |
| </button> | |
| <button class="endpoint-btn" onclick="selectEndpoint('recommend')"> | |
| <i class="fas fa-star"></i> Recommendations | |
| </button> | |
| <button class="endpoint-btn" onclick="selectEndpoint('popular')"> | |
| <i class="fas fa-chart-line"></i> Popular Searches | |
| </button> | |
| <button class="endpoint-btn" onclick="selectEndpoint('hot')"> | |
| <i class="fas fa-pepper-hot"></i> Hot Content | |
| </button> | |
| </div> | |
| <div class="main-content"> | |
| <div class="request-config"> | |
| <h3 id="endpointTitle" style="margin-top: 0;">Configure Request</h3> | |
| <div id="queryInput" class="input-group"> | |
| <label>Search Query / Title</label> | |
| <input type="text" id="query" value="Avatar" placeholder="e.g. Iron Man"> | |
| </div> | |
| <div id="typeInput" class="input-group"> | |
| <label>Content Type</label> | |
| <select id="mediaType"> | |
| <option value="movie">Movie</option> | |
| <option value="series">TV Series</option> | |
| </select> | |
| </div> | |
| <div id="seriesInputs" class="hidden"> | |
| <div class="input-group"> | |
| <label>Season</label> | |
| <input type="number" id="season" value="1" min="1"> | |
| </div> | |
| <div class="input-group"> | |
| <label>Episode</label> | |
| <input type="number" id="episode" value="1" min="1"> | |
| </div> | |
| </div> | |
| <button class="execute-btn" onclick="executeRequest()"> | |
| <i class="fas fa-play"></i> Execute Request | |
| </button> | |
| </div> | |
| <div class="response-area"> | |
| <div class="response-header"> | |
| <span>Response</span> | |
| <span id="statusBadge" class="status-badge hidden"></span> | |
| </div> | |
| <pre id="jsonOutput">// Response will appear here...</pre> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| let currentEndpoint = 'media-files'; | |
| document.getElementById('mediaType').addEventListener('change', function(e) { | |
| const seriesInputs = document.getElementById('seriesInputs'); | |
| if (e.target.value === 'series' && currentEndpoint === 'media-files') { | |
| seriesInputs.classList.remove('hidden'); | |
| } else { | |
| seriesInputs.classList.add('hidden'); | |
| } | |
| }); | |
| function selectEndpoint(endpoint) { | |
| currentEndpoint = endpoint; | |
| document.querySelectorAll('.endpoint-btn').forEach(btn => btn.classList.remove('active')); | |
| event.currentTarget.classList.add('active'); | |
| const queryInput = document.getElementById('queryInput'); | |
| const typeInput = document.getElementById('typeInput'); | |
| const seriesInputs = document.getElementById('seriesInputs'); | |
| // Reset visibility | |
| queryInput.classList.remove('hidden'); | |
| typeInput.classList.add('hidden'); | |
| seriesInputs.classList.add('hidden'); | |
| const titles = { | |
| 'search': 'Search Query', | |
| 'media-files': 'Extract Stream URLs', | |
| 'details': 'Get Movie Metadata', | |
| 'recommend': 'Get Recommendations' | |
| }; | |
| document.getElementById('endpointTitle').innerText = titles[endpoint] || 'No Parameters Required'; | |
| if (['trending', 'homepage', 'popular', 'hot'].includes(endpoint)) { | |
| queryInput.classList.add('hidden'); | |
| } | |
| if (['search', 'media-files', 'details', 'recommend'].includes(endpoint)) { | |
| typeInput.classList.remove('hidden'); | |
| } | |
| if (endpoint === 'media-files' && document.getElementById('mediaType').value === 'series') { | |
| seriesInputs.classList.remove('hidden'); | |
| } | |
| } | |
| async function executeRequest() { | |
| const btn = document.querySelector('.execute-btn'); | |
| const output = document.getElementById('jsonOutput'); | |
| const badge = document.getElementById('statusBadge'); | |
| const apiKey = document.getElementById('apiKey').value; | |
| const query = encodeURIComponent(document.getElementById('query').value); | |
| const type = document.getElementById('mediaType').value; | |
| const season = document.getElementById('season').value; | |
| const episode = document.getElementById('episode').value; | |
| btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Executing...'; | |
| output.innerText = 'Loading...'; | |
| badge.classList.add('hidden'); | |
| // Base URL relative to wherever it is hosted | |
| let url = `/api/${currentEndpoint}?api_key=${apiKey}`; | |
| if (['search', 'media-files', 'details', 'recommend'].includes(currentEndpoint)) { | |
| url += `&query=${query}&type=${type}`; | |
| } | |
| if (currentEndpoint === 'media-files' && type === 'series') { | |
| url += `&season=${season}&episode=${episode}`; | |
| } | |
| try { | |
| // Ensure headers are sent properly | |
| const response = await fetch(url, { | |
| method: 'GET', | |
| headers: { | |
| 'Accept': 'application/json', | |
| 'X-API-Key': apiKey | |
| } | |
| }); | |
| const data = await response.json(); | |
| badge.innerText = `Status: ${response.status}`; | |
| badge.className = `status-badge ${response.ok ? 'status-200' : 'status-error'}`; | |
| output.innerText = JSON.stringify(data, null, 2); | |
| } catch (error) { | |
| badge.innerText = 'Network Error'; | |
| badge.className = 'status-badge status-error'; | |
| output.innerText = error.toString(); | |
| } finally { | |
| btn.innerHTML = '<i class="fas fa-play"></i> Execute Request'; | |
| } | |
| } | |
| // Initialize UI | |
| selectEndpoint('media-files'); | |
| </script> | |
| </body> | |
| </html> |