mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-25 07:42:11 +00:00
chore: make browser example more complete
See: https://ytjsexample.pages.dev/
This commit is contained in:
@@ -1,20 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<form>
|
||||
<input type="text" name="id" placeholder="Video ID" />
|
||||
<input type="submit" value="Play" />
|
||||
</form>
|
||||
<span id="video_name">
|
||||
Library is loading...
|
||||
</span>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>YouTube.js Example</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form>
|
||||
<input type="text" name="id" placeholder="Video ID or URL" />
|
||||
<input type="submit" value="Play" />
|
||||
</form>
|
||||
<div id="loader"></div>
|
||||
<div id="video_container">
|
||||
<video></video>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
<h2 id="title"></h2>
|
||||
<div id="metadata"></div>
|
||||
<hr />
|
||||
<div id="description"></div>
|
||||
</div>
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/LuanRT/YouTube.js">YouTube.js</a></p>
|
||||
</footer>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -4,13 +4,14 @@ import dashjs from 'dashjs';
|
||||
|
||||
async function main() {
|
||||
const yt = await Innertube.create({
|
||||
generate_session_locally: true,
|
||||
fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
// url
|
||||
const url = typeof input === 'string'
|
||||
? new URL(input)
|
||||
: input instanceof URL
|
||||
? input
|
||||
: new URL(input.url);
|
||||
? input
|
||||
: new URL(input.url);
|
||||
|
||||
// transform the url for use with our proxy
|
||||
url.searchParams.set('__host', url.host);
|
||||
@@ -20,8 +21,8 @@ async function main() {
|
||||
const headers = init?.headers
|
||||
? new Headers(init.headers)
|
||||
: input instanceof Request
|
||||
? input.headers
|
||||
: new Headers();
|
||||
? input.headers
|
||||
: new Headers();
|
||||
|
||||
// now serialize the headers
|
||||
url.searchParams.set('__headers', JSON.stringify([...headers]));
|
||||
@@ -48,29 +49,65 @@ async function main() {
|
||||
cache: new UniversalCache(false),
|
||||
});
|
||||
|
||||
const span = document.getElementById('video_name') as HTMLSpanElement;
|
||||
const description = document.getElementById('description') as HTMLDivElement;
|
||||
const form = document.querySelector('form') as HTMLFormElement;
|
||||
|
||||
span.textContent = 'Library ready';
|
||||
const title = document.getElementById('title') as HTMLHeadingElement;
|
||||
const metadata = document.getElementById('metadata') as HTMLDivElement;
|
||||
const loader = document.getElementById('loader') as HTMLDivElement;
|
||||
const video_container = document.getElementById('video_container') as HTMLDivElement;
|
||||
|
||||
let player: dashjs.MediaPlayerClass | undefined;
|
||||
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
span.textContent = 'Loading...';
|
||||
if (player) {
|
||||
player.reset();
|
||||
}
|
||||
|
||||
const video_id = document.querySelector<HTMLInputElement>(
|
||||
'input[type=text]',
|
||||
)?.value;
|
||||
if (!video_id) {
|
||||
span.textContent = 'No video id';
|
||||
video_container.style.display = 'none';
|
||||
loader.style.display = 'block';
|
||||
|
||||
let video_id;
|
||||
|
||||
const video_id_or_url = document.querySelector<HTMLInputElement>('input[type=text]')?.value;
|
||||
|
||||
if (!video_id_or_url) {
|
||||
title.textContent = 'No video id or URL provided';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (video_id_or_url.match(/(http|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])/)) {
|
||||
const endpoint = await yt.resolveURL(video_id_or_url);
|
||||
|
||||
if (!endpoint.payload.videoId) {
|
||||
title.textContent = 'Could not resolve URL';
|
||||
return;
|
||||
}
|
||||
|
||||
video_id = endpoint.payload.videoId;
|
||||
} else {
|
||||
video_id = video_id_or_url;
|
||||
}
|
||||
|
||||
const video = await yt.getInfo(video_id);
|
||||
console.log(video);
|
||||
span.textContent = video.basic_info.title || null;
|
||||
|
||||
loader.style.display = 'none';
|
||||
|
||||
title.textContent = video.basic_info.title || null;
|
||||
description.innerHTML = video.secondary_info?.description.toHTML() || '';
|
||||
title.textContent = video.basic_info.title || null;
|
||||
|
||||
document.title = video.basic_info.title || '';
|
||||
|
||||
metadata!.innerHTML = '';
|
||||
metadata!.innerHTML += `<div class="metadata_item">${video.primary_info?.published.toHTML()}</div>`;
|
||||
metadata!.innerHTML += `<div class="metadata_item">${video.primary_info?.view_count.toHTML()}</div>`;
|
||||
metadata!.innerHTML += `<div class="metadata_item">${video.basic_info.like_count} likes</div>`;
|
||||
|
||||
video_container.animate({ opacity: [0, 1] }, { duration: 300, easing: 'ease-in-out' });
|
||||
video_container.style.display = 'block';
|
||||
|
||||
const dash = video.toDash((url) => {
|
||||
url.searchParams.set('__host', url.host);
|
||||
@@ -79,20 +116,23 @@ async function main() {
|
||||
return url;
|
||||
});
|
||||
|
||||
const uri = 'data:application/dash+xml;charset=utf-8;base64,' +
|
||||
btoa(dash);
|
||||
const uri = 'data:application/dash+xml;charset=utf-8;base64,' + btoa(dash);
|
||||
|
||||
// create and append video element
|
||||
const video_element = document.querySelector('video') as HTMLVideoElement;
|
||||
video_element.setAttribute('controls', 'true');
|
||||
video_element.poster = video.basic_info.thumbnail![0].url;
|
||||
|
||||
// use dash.js to parse the manifest
|
||||
if (player) {
|
||||
player.destroy();
|
||||
}
|
||||
|
||||
player = dashjs.MediaPlayer().create();
|
||||
player.initialize(video_element, uri, true);
|
||||
player.setInitialMediaSettingsFor('audio', { lang: 'en-US' });
|
||||
} catch (error) {
|
||||
span.textContent = 'An error occurred (see console)';
|
||||
title.textContent = 'An error occurred (see console)';
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,10 +3,87 @@ body {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
background-color: rgb(32, 32, 32);
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border: 1px solid transparent;
|
||||
background-color: rgb(68, 68, 68);
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
#loader {
|
||||
display: none;
|
||||
border: 10px solid rgb(68, 68, 68);
|
||||
border-top: 10px solid rgb(255, 255, 255);
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
align-self: center;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
#video_container {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 70vw !important;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
#metadata {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-self: left;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
#metadata > .metadata_item {
|
||||
margin: 0 0.3rem;
|
||||
background-color: beige;
|
||||
color: black;
|
||||
font: 1em bold;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
|
||||
#video_container > #description {
|
||||
align-self: left;
|
||||
margin-left: 0.5rem;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
video {
|
||||
max-width: calc(100vw - 1rem);
|
||||
width: fit-content;
|
||||
max-height: calc(90vh - 12rem);
|
||||
width: 100%;
|
||||
height: 40vw;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
video {
|
||||
height: auto;
|
||||
}
|
||||
#video_container {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user