ytm / test.html
veltrixcode's picture
Upload 15 files
51e4fb5 verified
Raw
History Blame Contribute Delete
7.06 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Music API - Endpoint Tester</title>
<style>
body { font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica Neue, Arial; margin: 24px; }
h1 { margin: 0 0 4px; }
.subtitle { color: #666; margin: 0 0 16px; }
.card { border: 1px solid #ddd; border-radius: 10px; padding: 16px; margin-bottom: 16px; }
.row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.row > * { margin: 4px 0; }
label { font-size: 12px; color: #333; }
input, select, button, textarea { font-size: 14px; padding: 8px 10px; }
input, select, textarea { border: 1px solid #ccc; border-radius: 8px; }
button { border: 1px solid #333; background: #111; color: #fff; border-radius: 8px; cursor: pointer; }
button.secondary { background: #fff; color: #111; }
code.url { display: block; background: #f7f7f7; padding: 8px; border-radius: 8px; overflow: auto; }
pre { background: #0b1020; color: #d7e8ff; padding: 12px; border-radius: 10px; overflow: auto; }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 900px) { .two { grid-template-columns: 1fr; } }
</style>
<script>
const base = 'https://veltrixcode-ytm.hf.space';
function $(id) { return document.getElementById(id); }
function setJSON(id, value) { $(id).textContent = JSON.stringify(value, null, 2); }
function setText(id, value) { $(id).textContent = value || ''; }
function buildUrl(path, params) {
const url = new URL(path, base);
Object.entries(params || {}).forEach(([k, v]) => {
if (v !== undefined && v !== null && v !== '') url.searchParams.set(k, v);
});
return url.toString();
}
async function doFetch({ path, params, outUrlId, outJsonId, onAfter }) {
const url = buildUrl(path, params);
setText(outUrlId, url);
try {
const res = await fetch(url);
const json = await res.json();
setJSON(outJsonId, json);
if (typeof onAfter === 'function') onAfter(json);
} catch (e) {
setJSON(outJsonId, { error: e.message });
}
}
// Shared continuation helpers
function applyContinuation(fromJson, toInputIdList = []) {
const token = fromJson?.continuationToken
|| fromJson?.results?.continuationToken
|| null;
toInputIdList.forEach(id => { $(id).value = token || ''; });
return token;
}
// Handlers
async function ytmSearch(initial = true) {
const q = $('ytm_q').value.trim();
const filter = $('ytm_filter').value;
const continuationToken = initial ? '' : $('ytm_ct').value.trim();
await doFetch({
path: '/api/search',
params: { q, filter, continuationToken },
outUrlId: 'ytm_url',
outJsonId: 'ytm_json',
onAfter: (json) => {
// autofill continuation
applyContinuation(json, ['ytm_ct']);
}
});
}
async function ytSearch(initial = true) {
const q = $('yt_q').value.trim();
const filter = $('yt_filter').value;
const continuationToken = initial ? '' : $('yt_ct').value.trim();
await doFetch({
path: '/api/yt_search',
params: { q, filter, continuationToken },
outUrlId: 'yt_url',
outJsonId: 'yt_json',
onAfter: (json) => {
applyContinuation(json, ['yt_ct']);
}
});
}
async function ytPlaylists(initial = true) {
const q = $('ytp_q').value.trim();
const continuationToken = initial ? '' : $('ytp_ct').value.trim();
await doFetch({
path: '/api/yt_playlists',
params: { q, continuationToken },
outUrlId: 'ytp_url',
outJsonId: 'ytp_json',
onAfter: (json) => {
applyContinuation(json, ['ytp_ct']);
}
});
}
// Quick presets
function presetPhonk() {
['ytm_q','yt_q','ytp_q'].forEach(id => { $(id).value = 'phonk'; });
}
window.addEventListener('DOMContentLoaded', presetPhonk);
</script>
</head>
<body>
<h1>Music API - Endpoint Tester</h1>
<p class="subtitle">Run requests against the local API, inspect JSON, and page with continuation tokens.</p>
<div class="card">
<h2>YouTube Music: /api/search</h2>
<div class="row">
<label>Query <input id="ytm_q" placeholder="e.g. phonk"></label>
<label>Filter
<select id="ytm_filter">
<option value="songs">songs</option>
<option value="videos">videos</option>
<option value="albums">albums</option>
<option value="artists">artists</option>
<option value="playlists">playlists</option>
<option value="community_playlists">community_playlists</option>
<option value="profiles">profiles</option>
<option value="podcasts">podcasts</option>
<option value="episodes">episodes</option>
</select>
</label>
<label>Continuation <input id="ytm_ct" placeholder="continuationToken"></label>
<button onclick="ytmSearch(true)">Search</button>
<button class="secondary" onclick="ytmSearch(false)">Next page ▶</button>
</div>
<code class="url" id="ytm_url"></code>
<pre id="ytm_json">{}</pre>
</div>
<div class="card">
<h2>YouTube: /api/yt_search</h2>
<div class="row">
<label>Query <input id="yt_q" placeholder="e.g. phonk"></label>
<label>Filter
<select id="yt_filter">
<option value="videos">videos</option>
<option value="all">all</option>
<option value="channels">channels</option>
<option value="playlists">playlists</option>
</select>
</label>
<label>Continuation <input id="yt_ct" placeholder="continuationToken"></label>
<button onclick="ytSearch(true)">Search</button>
<button class="secondary" onclick="ytSearch(false)">Next page ▶</button>
</div>
<code class="url" id="yt_url"></code>
<pre id="yt_json">{}</pre>
</div>
<div class="card">
<h2>YouTube: /api/yt_playlists</h2>
<div class="row">
<label>Query <input id="ytp_q" placeholder="e.g. phonk"></label>
<label>Continuation <input id="ytp_ct" placeholder="continuationToken"></label>
<button onclick="ytPlaylists(true)">Search</button>
<button class="secondary" onclick="ytPlaylists(false)">Next page ▶</button>
</div>
<code class="url" id="ytp_url"></code>
<pre id="ytp_json">{}</pre>
</div>
<div class="card">
<h2>Notes</h2>
<ul>
<li>Continuation tokens are auto-populated into the input after a response. Click "Next page" to fetch the next page.</li>
<li>This page targets the API served by the current origin (location.origin).</li>
<li>Open DevTools (Network tab) if you need to inspect raw requests.</li>
</ul>
</div>
</body>
</html>