Files
vrc-ytdlp-resolver/public/index.html
2025-11-09 13:08:23 +01:00

128 lines
4.6 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- /public/index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,viewport-fit=cover"
/>
<title>VRChat YouTube Resolver</title>
<style>
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu;max-width:760px;margin:4rem auto;padding:0 1rem;line-height:1.45}
header{margin-bottom:1rem}
.card{border:1px solid #ddd;border-radius:12px;padding:1rem}
.row{display:flex;gap:.5rem}
input[type="url"]{flex:1;padding:.75rem;border:1px solid #ccc;border-radius:8px}
button{padding:.75rem 1rem;border:0;border-radius:8px;background:#4f46e5;color:white;cursor:pointer}
button.secondary{background:#475569}
pre{white-space:pre-wrap;word-break:break-all;background:#0b1020;color:#e6ecff;padding:1rem;border-radius:8px}
.hint{font-size:.9rem;color:#334155}
.warn{color:#9a3412}
.ok{color:#065f46}
.grid{display:grid;gap:.5rem}
a.buttonlike { text-decoration: none; }
</style>
</head>
<body>
<header>
<h1>VRChat YouTube Resolver</h1>
<p class="hint">
Generates a direct <code>googlevideo.com</code> URL via <code>yt-dlp</code>.
Paste the result into your in-world video player. Note: URLs are time-limited.
</p>
</header>
<div id="ytver" class="hint" style="margin-bottom:1rem; font-size:0.9rem; color:#475569;">
yt-dlp version: loading…
</div>
<section class="card grid">
<form id="f" class="row">
<input id="url" type="url" placeholder="https://www.youtube.com/watch?v=..." required />
<button type="submit">Resolve</button>
</form>
<div id="out"></div>
<p class="hint">
Tip: Prefer a “Direct stream” (single URL). If you only get “Adaptive streams,” many world players
wont accept separate video+audio URLs unless they have a proxy/muxer.
</p>
</section>
<script>
const $ = (s) => document.querySelector(s);
const out = $("#out");
async function showVersion() {
try {
const r = await fetch("/api/version");
const v = await r.json();
const el = $("#ytver");
if (!v.latest) {
el.textContent = `yt-dlp version: ${v.local}`;
return;
}
if (v.updateAvailable) {
el.innerHTML = `
yt-dlp version: <strong>${v.local}</strong> →
<span style="color:#b91c1c;">Update available: ${v.latest}</span><br>
<a class="buttonlike" href="https://github.com/yt-dlp/yt-dlp/releases/latest" target="_blank">Open latest release</a>
`;
} else {
el.innerHTML = `yt-dlp version: <strong>${v.local}</strong> (up to date)`;
}
} catch {
$("#ytver").textContent = "yt-dlp version: (could not be queried)";
}
}
$("#f").addEventListener("submit", async (e) => {
e.preventDefault();
out.innerHTML = "Working…";
const url = $("#url").value.trim();
try {
const r = await fetch("/api/resolve", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ url }),
});
const data = await r.json();
if (!data.ok) throw new Error(data.error || "Unknown error");
const blocks = [];
if (data.url) {
const safe = data.url.replaceAll("'", "\\'");
blocks.push(`
<h3 class="ok">Direct stream</h3>
<pre id="u">${data.url}</pre>
<div class="row">
<button type="button" onclick="navigator.clipboard.writeText('${safe}')">Copy</button>
<a class="buttonlike" href="${data.url}" target="_blank"><button type="button" class="secondary">Open</button></a>
</div>
<p class="hint">${data.note || ""}</p>
`);
}
if (data.audioUrl) {
blocks.push(`
<h3 class="warn">Adaptive streams</h3>
<p class="hint warn">This likely wont work in players that expect a single URL.</p>
<strong>Video:</strong>
<pre>${data.url}</pre>
<strong>Audio:</strong>
<pre>${data.audioUrl}</pre>
`);
}
out.innerHTML = blocks.join("");
} catch (err) {
out.innerHTML = `<p class="warn">${err.message}</p>`;
}
});
showVersion();
</script>
</body>
</html>