1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <title>🎮 Magnet Streamer</title> 7 <script src="https://cdn.socket.io/4.6.1/socket.io.min.js"></script> 8 <style> 9 body { 10 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 11 background: linear-gradient(to right, #141e30, #243b55); 12 color: white; 13 text-align: center; 14 padding: 40px 20px; 15 } 16 h1 { 17 font-size: 2.5em; 18 margin-bottom: 20px; 19 } 20 form { 21 margin-bottom: 30px; 22 } 23 input[type="text"] { 24 width: 70%; 25 padding: 16px; 26 font-size: 16px; 27 border: none; 28 border-radius: 8px; 29 margin-bottom: 16px; 30 box-shadow: 0 0 12px rgba(0,0,0,0.3); 31 } 32 button { 33 padding: 14px 32px; 34 font-size: 16px; 35 background-color: #00c853; 36 color: white; 37 border: none; 38 border-radius: 8px; 39 cursor: pointer; 40 } 41 #status { 42 margin-top: 30px; 43 font-size: 16px; 44 } 45 #log { 46 background: rgba(0, 0, 0, 0.5); 47 border-radius: 6px; 48 padding: 14px; 49 max-width: 900px; 50 margin: 30px auto; 51 font-family: monospace; 52 font-size: 14px; 53 text-align: left; 54 white-space: pre-line; 55 max-height: 350px; 56 overflow-y: auto; 57 overflow-x: auto; 58 box-shadow: inset 0 0 6px rgba(255,255,255,0.1); 59 } 60 video { 61 margin-top: 30px; 62 width: 80%; 63 max-width: 900px; 64 border-radius: 10px; 65 box-shadow: 0 0 20px rgba(0, 0, 0, 0.4); 66 } 67 </style> 68 </head> 69 <body> 70 <h1>🎮 Stream a Magnet Link</h1> 71 <form id="magnetForm"> 72 <input type="text" id="magnetInput" name="magnet" placeholder="Paste magnet link here" required /> 73 <br /> 74 <button type="submit">▶️ Play</button> 75 </form> 76 <div id="status">⏳ Preparing...</div> 77 <div id="log"></div> 78 <div id="videoContainer"></div> 79 <script> 80 const form = document.getElementById('magnetForm'); 81 const input = document.getElementById('magnetInput'); 82 const statusEl = document.getElementById("status"); 83 const logEl = document.getElementById("log"); 84 const videoContainer = document.getElementById("videoContainer"); 85 let magnet = null; 86 const socket = io(); 87 88 socket.on("log_update", (data) => { 89 if (data.magnet === magnet && logEl) { 90 logEl.textContent += "\n" + data.message; 91 logEl.scrollTop = logEl.scrollHeight; 92 } 93 }); 94 95 form.addEventListener('submit', async function (e) { 96 e.preventDefault(); 97 magnet = input.value.trim(); 98 if (!magnet.startsWith("magnet:?")) { 99 alert("Please enter a valid magnet link"); 100 return; 101 } 102 const res = await fetch('/', { 103 method: 'POST', 104 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 105 body: new URLSearchParams({ magnet }) 106 }); 107 if (!res.ok) { 108 statusEl.textContent = "❌ Failed to submit magnet link."; 109 return; 110 } 111 window.history.pushState({}, '', `/player?magnet=${encodeURIComponent(magnet)}`); 112 statusEl.textContent = "⏳ Download started..."; 113 pollStatus(); 114 }); 115 116 window.addEventListener('DOMContentLoaded', () => { 117 const params = new URLSearchParams(window.location.search); 118 if (params.has("magnet")) { 119 magnet = params.get("magnet"); 120 statusEl.textContent = "⏳ Checking torrent status..."; 121 pollStatus(); 122 } 123 }); 124 125 async function pollStatus() { 126 try { 127 const res = await fetch(`/status?magnet=${encodeURIComponent(magnet)}`); 128 const data = await res.json(); 129 130 const pct = data.progress ?? 0; 131 const peers = data.peers ?? 0; 132 const rate = data.downloadRate ?? 0; 133 statusEl.textContent = `📦 ${pct}% complete | Peers: ${peers} | DL: ${rate} KB/s`; 134 135 if (data.ready && data.meta && Array.isArray(data.meta.files) && !document.querySelector("video")) { 136 const fileName = data.meta.files.find(f => f.name.endsWith('.mp4') || f.name.endsWith('.mkv') || f.name.endsWith('.avi'))?.name; 137 if (fileName) { 138 const video = document.createElement("video"); 139 video.src = `/stream?magnet=${encodeURIComponent(magnet)}&file=${encodeURIComponent(fileName)}`; 140 video.controls = true; 141 video.autoplay = true; 142 videoContainer.appendChild(video); 143 video.scrollIntoView({ behavior: 'smooth' }); 144 } 145 } else { 146 setTimeout(pollStatus, 2000); 147 } 148 } catch (err) { 149 statusEl.textContent = "⚠️ Error checking download status."; 150 } 151 } 152 </script> 153 </body> 154 </html> 155