ytdl-server/public/index.html

130 lines
4.1 KiB
HTML

<!DOCTYPE html><html><head>
<meta name="og:title" content="Quest VRChat Video Server" />
<meta name="og:description" content="Import YouTube videos and get short link for Quest VRChat" />
<title>Quest VRChat Video Server</title>
<style>
#url_input {
width: 320px;
}
#alias_input {
width: 64px;
}
#server_output {
max-height: 160px;
white-space: pre;
overflow-y: scroll;
font-family: monospace;
border: 1px gray solid;
padding: 3px;
}
table, th, td {
border: 1px black solid;
border-collapse: collapse;
padding: 3px;
}
</style>
</head><body>
<h1>Quest VRChat Video Server</h1>
<div>Import YouTube videos onto this server to...</div>
<ul>
<li>Make the videos work for your friends on Quest (allow untrusted URLs)</li>
<li><b>NEW:</b> Get memorable short URLs that you can type in Quest!</li>
</ul>
<p>
<div>Just paste a YouTube video URL here: <input id="url_input" type="text" placeholder="https://www.youtube.com/watch?v=dQw4w9WgXcQ" /></label></div>
<div>and optionally type a short memorable alias for it: <input id="alias_input" type="text" placeholder="rick" maxlength="32" /></div>
<div>and click <input id="submit_button" type="submit" />!</div>
</p>
<p id="server_output"></p>
<p><b>NEW:</b> Watch YouTube on Quest WITHOUT PC friends or memorized URLs with <a href="https://www.u2b.cx/">u2b.cx</a>!</p>
<script>
var url_input = document.getElementById("url_input");
var alias_input = document.getElementById("alias_input");
var submit_button = document.getElementById("submit_button");
var server_output = document.getElementById("server_output");
submit_button.onclick = function() {
url_input.disabled = true;
alias_input.disabled = true;
submit_button.disabled = true;
server_output.innerText = '';
var ws = new WebSocket(`${location.protocol.replace('http','ws')}//${location.host}/w?url=${encodeURIComponent(url_input.value)}&alias=${encodeURIComponent(alias_input.value)}`);
function print(html) {
server_output.innerHTML += html + '\n';
server_output.scrollTop = server_output.scrollHeight;
}
ws.onerror = function (event) {
print(`<span style="color: red">WebSocket connection failed</span>`);
};
ws.onmessage = function (evt) {
console.log(evt.data)
print(evt.data);
};
ws.onclose = function () {
url_input.value = "";
alias_input.value = "";
url_input.disabled = false;
alias_input.disabled = false;
submit_button.disabled = false;
loadList();
}
}
</script>
<h2>Videos</h2>
<table>
<thead>
<tr>
<th>Short links</th>
<th></th>
<th>File name</th>
<th>Duration</th>
<th>Size</th>
<th>Date added</th>
</tr>
</thead>
<tbody id="tbody">
</tbody>
</table>
<script>
var tbody = document.getElementById("tbody");
function loadList() {
fetch("/api/list").then(res => res.json()).then(list => {
tbody.innerHTML = '';
list.forEach((file, index) => {
var url = `${location.origin}/v/${encodeURIComponent(file.name)}`;
var row = tbody.insertRow(0);
row.insertCell().innerText = [index, ...file.aliases||[]].map(x => `${location.origin}/${x}`).join('\n');
row.insertCell().innerHTML = `<button title="Copy URL" onclick="navigator.clipboard.writeText('${url}')">📋</button>`;
row.insertCell().innerHTML = `<a href="${url}">${file.name}</a>`;
row.insertCell().innerHTML = `<span title="${file.duration} seconds">${formatDuration(file.duration)}</span>`;
row.insertCell().innerHTML = `<span title="${file.size} bytes">${formatBytes(file.size)}</span>`
row.insertCell().innerHTML = `<span title="${file.mtime}">${new Date(file.mtime).toLocaleString()}</span>`;
});
});
}
loadList();
function formatDuration(seconds) {
var d = new Date(0);
d.setSeconds(seconds);
var hms = d.toISOString().substring(11, 19);
if (hms.startsWith("00:")) hms = hms.substring(3);
return hms;
}
function formatBytes(bytes) {
if (bytes == 0) return "0 B";
var e = Math.floor(Math.log(bytes) / Math.log(1000));
return (bytes / Math.pow(1000, e)).toFixed(2) + ' ' + ' KMGTP'.charAt(e) + 'B';
}
</script>
</body></html>