i’m trying to use typescript in sveltekit to implement a youtube API. I’m using @types/youtube, hoping that I can get better results getting the video to work by passing the URL and get videoDuration. but so far it’s not working.
i was following the template of youtube API, I could get js and videoID version to work but somehow i was having trouble with typescript and passing URL
Any help or experience is appreciated.
<!-- to do:
1) need to handle youtube shorts by replacing short with watch?v=
2) chatbot window on same screen like windows explorer or new page, take some time to reflect
-->
<script lang="ts">
// page function from default app/stores library enables script to get url searchparams from
// url
import { page } from '$app/stores';
import { onMount, onDestroy } from 'svelte';
let subtitles: {id: string, start: number; end: number; text: string} [] = [];
let videoUrl: string = '';
let duration: number = 0;
let currentTime: number = 0;
let player = new YT.Player("id",{
events: {
onReady(event: YT.PlayerEvent) {
const targetPlayer: YT.Player = event.target;
},
onStateChange(event: YT.OnStateChangeEvent) {
const targetPlayer: YT.Player = event.target;
const playerData: YT.PlayerState = event.data;
}
}
});
// function to fetch subtitles from cache, database or AI server.
async function fetchSubtitles() {
subtitles = [
{ id: "1", start: 0, end: 5, text: "Hello, welcome to our video." },
{ id: "2", start: 6, end: 10, text: "Today, we'll discuss Svelte components." },
{ id: "3", start: 11, end: 15, text: "Let's dive right in!" },
{ id: "4", start: 16, end: 20, text: "Svelte makes building UIs a breeze." },
];
}
/***************** onMount() ******************/
onMount(() => {
// I believe that page should be a reactive var, so query is renewed every time
// url changes. But on the other hand, since all vars are reactive,
const query = $page.url.searchParams;
const encodedUrl = query.get('videoUrl') || '';
//const tag: HTMLScriptElement = document.createElement('script');
// Decode the URL before processing it
videoUrl = decodeURIComponent(encodedUrl);
// Load the YouTube iframe API script dynamically
const tag = document.createElement('script');
tag.src = 'https://www.youtube.com/iframe_api';
document.body.appendChild(tag);
// Define a global callback that YouTube API will call once it's ready
(window as any).onYouTubeIframeAPIReady = () => {
player = new YT.Player("id",{
events: {
onReady(event: YT.PlayerEvent) {
const targetPlayer: YT.Player = event.target;
},
onStateChange(event: YT.OnStateChangeEvent) {
const targetPlayer: YT.Player = event.target;
const playerData: YT.PlayerState = event.data;
}
}
})
};
// Ensure that the URL is a valid YouTube URL
if (videoUrl && !videoUrl.includes("youtube.com") && !videoUrl.includes("youtu.be")) {
videoUrl = ''; // Reset if not a valid YouTube URL
}
//insert iframe api onto DOM
//tag.src = "https://www.youtube.com/iframe_api";
//document.body.appendChild(tag);
fetchSubtitles();
});
/************* OnMount ****************/
// call eventlistener function when onReady event fire is received by API.
player.addEventListener("onReady",
(event: YT.PlayerEvent) => {
duration = player.getDuration();
currentTime = player.getCurrentTime();
});
/****
// called when the player is ready
function onPlayerReady(event): void {
duration = player.getDuration();
setInterval((): void => {
currentTime = YT.getCurrentTime();
}, 1000);
}
***/
//$: duration = player ? player.getDuration() : 0;
// Function to construct YouTube URL into embedded form
function getEmbedUrl(url: string): string {
if (!url) return '';
// Handle short links like youtu.be/xyz
const shortLinkMatch = url.match(/youtu.be/([^?]+)/);
if (shortLinkMatch) {
return `https://www.youtube.com/embed/${shortLinkMatch[1]}`;
}
// Handle regular YouTube links like youtube.com/watch?v=xyz
const regularLinkMatch = url.match(/v=([^&]+)/);
if (regularLinkMatch) {
return `https://www.youtube.com/embed/${regularLinkMatch[1]}`;
}
return '';
}
</script>
<main>
<h1>Watch Video</h1>
{#if videoUrl}
<div id="id"></div>
<p> Duration: {duration} seconds </p>
<p> Current Time: {currentTime} seconds </p>
{:else}
<p>No valid video URL provided. Please check the link and try again.</p>
{/if}
</main>
<style>
main {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
}
iframe {
margin-top: 1rem;
}
</style>
<!--
Watch.svelte page is a parent component to subtitleEditor.svelte component in library.
Primary function is to embed youtube video for display, based on the URL that user
submitted in the (tentative) main page.svelte
apparently it is better to have subtitles fetched from parent component.
Then passed assign value to props of SubtitleEditor component.
-->