From 222cb797e53ed3cdf435664f798c19a5efef83b0 Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Wed, 8 Mar 2023 16:24:03 -0800 Subject: [PATCH 1/8] test version of youglish (done in flask) --- ComSemApp/student/app.py | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 ComSemApp/student/app.py diff --git a/ComSemApp/student/app.py b/ComSemApp/student/app.py new file mode 100644 index 000000000..ae6573e67 --- /dev/null +++ b/ComSemApp/student/app.py @@ -0,0 +1,44 @@ +from flask import Flask, request, jsonify +import requests + +#Currently setup with flask +#use flask run and go to http://localhost:5000/search_videos?query=replace_with_search + +app = Flask(__name__) + +API_KEY = "1330c216-9f26-4c1f-813c-4665a8918c30" + +@app.route('/search_videos') +def search_videos(): + query = request.args.get('query') + if not query: + return jsonify({'error': 'Please provide a query parameter'}), 400 + + headers = {'Authorization': 'Bearer ' + API_KEY} + url = f"https://youglish.com/api/v1/videos/search?key={API_KEY}&query={query}&lg=english" + + response = requests.get(url, headers=headers) + if response.status_code != 200: + return jsonify({'error': 'Failed to search videos'}), response.status_code + + videos = response.json() + return jsonify(videos) + +@app.route('/get_video') +def get_video(): + video_id = request.args.get('video_id') + if not video_id: + return jsonify({'error': 'Please provide a video_id parameter'}), 400 + + headers = {'Authorization': 'Bearer ' + API_KEY} + url = f"https://youglish.com/api/v1/videos/{video_id}" + + response = requests.get(url, headers=headers) + if response.status_code != 200: + return jsonify({'error': 'Failed to get video'}), response.status_code + + video = response.json() + return jsonify(video) + +if __name__ == '__main__': + app.run(debug=True) From 5a0870fa31cb4b88e66464ab06a4078822650657 Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Sat, 18 Mar 2023 15:52:14 -0700 Subject: [PATCH 2/8] Runs on a local nodejs server. not completed still testing Will not run and requires other local files to work. Currently only used for sandbox testing not for actual use. --- ComSemApp/student/youglish-api-sandbox.js | 217 ++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 ComSemApp/student/youglish-api-sandbox.js diff --git a/ComSemApp/student/youglish-api-sandbox.js b/ComSemApp/student/youglish-api-sandbox.js new file mode 100644 index 000000000..b57868e63 --- /dev/null +++ b/ComSemApp/student/youglish-api-sandbox.js @@ -0,0 +1,217 @@ +/* +This code is an implementation of the Youglish API that allows a user to search for a word and retrieve relevant YouTube videos containing the word. +The code fetches video details from the YouTube API, displays the videos in a player, and allows the user to navigate through the videos. + +Youglish API - Receives requests from the client and sends them to the Youglish API. It then returns the response to the client-side code. +YouTube API - A set of RESTful APIs that provides functionality to search for videos, retrieve video details, and play videos from youtube. +jQuery - A JavaScript library that simplifies DOM manipulation, event handling, and Ajax interactions. +Ajax - A technique used to make asynchronous HTTP requests from the client-side code to the server-side code. +*/ + +$(document).ready(function() { + + // Define the URL for the Youglish proxy API and the query string + const apiUrl = 'http://localhost:3000/youglish-proxy'; + const query = 'explaining'; //replace with searched for word + + const youtubeApiKey = 'AIzaSyDQoynj7T6sa77hqlheFTgIIuuGTb1dQng'; + + // Initialize empty arrays and variables to hold video data + let videos = []; + let player; + let currentVideoIndex = 0; + + // Function to fetch video details from the YouTube API + function fetchVideoDetails(videoId, onSuccess, onFailure) { + // Make an AJAX request to the YouTube API using jQuery + $.ajax({ + url: 'https://www.googleapis.com/youtube/v3/videos', + type: 'GET', + dataType: 'json', + data: { + key: youtubeApiKey, + id: videoId, + part: 'snippet,contentDetails,statistics,status', + }, + success: onSuccess, + error: function (jqXHR, textStatus, errorThrown) { + console.error('YouTube Data API request failed:', textStatus, errorThrown); + console.error('Response:', jqXHR.responseText); + console.error('Video id: ',videoId); + if (onFailure) { + onFailure(jqXHR, textStatus, errorThrown); // If the request fails, call the onFailure function (if provided) + } + }, + }); + } + + // Function to request additional Youglish data from the API + function requestAdditionalYouglishData() { + // Make an AJAX request to the Youglish proxy API using jQuery + $.ajax({ + url: apiUrl, + type: 'GET', + dataType: 'json', + data: { + 'q': query, + 'skip': videos.length, + 'max': 3, + }, + success: function (response) { + console.log(response); + // Add the new results to the existing videos array, slicing to the first 3 + videos = videos.concat(response.results.slice(0, 3)); + // Update the total number of videos in the UI + $('#total-videos').text(videos.length); + // Display the current video + displayVideo(currentVideoIndex); + }, + error: function (jqXHR, textStatus, errorThrown) { + console.error('Error:', textStatus, errorThrown); + }, + }); + } + + //Function displays the video at the specified index. + function displayVideo(videoIndex) { + if (videoIndex >= videos.length) { + console.warn('No more available videos.'); + return; + } + + // Get the video ID, start time, and end time of the video at the specified index + const videoId = videos[videoIndex].vid; + const startTime = videos[videoIndex].start; + const endTime = videos[videoIndex].end; + + // Calculate the buffered start and end times (2 seconds before and after the specified times) + const bufferedStartTime = parseInt(startTime) - 2; + const bufferedEndTime = parseInt(endTime) + 2; + + console.log("Extracted video ID:", videoId); + + // Call the fetchVideoDetails function to get details about the video + fetchVideoDetails( + videoId, + function (response) { + // Check if the response contains any items and if the video is embeddable and public + if (response.items.length > 0 && response.items[0].status.embeddable && response.items[0].status.privacyStatus === "public") { + // If the player already exists, load the video + if (player) { + player.loadVideoById({ videoId: videoId, startSeconds: startTime, endSeconds: endTime }); + } else { // Otherwise, create a new player + player = new YT.Player('video-container', { + height: '270', + width: '480', + videoId: videoId, + playerVars: { + 'autoplay': 1, + 'start': bufferedStartTime, + 'end': bufferedEndTime, + }, + events: { + 'onStateChange': onPlayerStateChange, + }, + }); + } + // Update the video index and the current video index + $('#video-index').text(videoIndex + 1); + currentVideoIndex = videoIndex; + } else { + console.warn('Video is not available:', videoId); + // If the video is not available, skip it and try the next one + displayVideo(videoIndex + 1); + } + }, + function (jqXHR, textStatus, errorThrown) { + console.error('Error fetching video details:', textStatus, errorThrown); + } + ); + } + + + /** + * This function handles changes to the state of the YouTube player. + * It seeks to the start time of the current video when the player starts playing, + * and reloads the video or moves to the next one when it ends. + */ + function onPlayerStateChange(event) { + const startTime = videos[currentVideoIndex].start; + const endTime = videos[currentVideoIndex].end; + + if (event.data === YT.PlayerState.ENDED) { + const duration = endTime - startTime; + + if (player.getCurrentTime() < endTime - 1) { + // If the video ends prematurely, attempt to reload it + setTimeout(() => { + player.loadVideoById({ videoId: player.getVideoData().video_id, startSeconds: startTime, endSeconds: endTime }); + }, 1000); + } else { + if (currentVideoIndex < videos.length - 1) { + setTimeout(() => { + currentVideoIndex++; + displayVideo(currentVideoIndex); + }, 3000); // 3-second buffer + } else { + requestAdditionalYouglishData(); + } + } + } else if (event.data === YT.PlayerState.PLAYING) { + const currentTime = player.getCurrentTime(); + + // Check if the current time is within 1 second of the start time + if (Math.abs(currentTime - startTime) > 1) { + player.seekTo(startTime, true); + } + } + } + + function displayVideos(results) { + videos = results; + // Update the total number of videos displayed + $('#total-videos').text(videos.length); + displayVideo(currentVideoIndex); + } + + // Set a click event for the 'Previous Video' button + $('#prev-video').on('click', function() { + if (currentVideoIndex > 0) { + currentVideoIndex--; + displayVideo(currentVideoIndex); + } + }); + + // Set a click event for the 'Next Video' button + $('#next-video').on('click', function() { + if (currentVideoIndex < videos.length - 1) { + currentVideoIndex++; + displayVideo(currentVideoIndex); + } + }); + + function getYouglishData() { + // Make a GET request to the Youglish API to retrieve data + $.ajax({ + url: apiUrl, + type: 'GET', + dataType: 'json', + data: { + 'q': query, + 'max': 3, + }, + success: function(response) { + console.log(response); + displayVideos(response.results); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.error('Error:', textStatus, errorThrown); + }, + }); + } + + // Retrieve Youglish data when the page loads + getYouglishData(); +}); + + \ No newline at end of file From 8aa809887b524f13413130b009785ff6742aedae Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Sat, 18 Mar 2023 15:52:48 -0700 Subject: [PATCH 3/8] Delete app.py new version uses nodejs instead of flask --- ComSemApp/student/app.py | 44 ---------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 ComSemApp/student/app.py diff --git a/ComSemApp/student/app.py b/ComSemApp/student/app.py deleted file mode 100644 index ae6573e67..000000000 --- a/ComSemApp/student/app.py +++ /dev/null @@ -1,44 +0,0 @@ -from flask import Flask, request, jsonify -import requests - -#Currently setup with flask -#use flask run and go to http://localhost:5000/search_videos?query=replace_with_search - -app = Flask(__name__) - -API_KEY = "1330c216-9f26-4c1f-813c-4665a8918c30" - -@app.route('/search_videos') -def search_videos(): - query = request.args.get('query') - if not query: - return jsonify({'error': 'Please provide a query parameter'}), 400 - - headers = {'Authorization': 'Bearer ' + API_KEY} - url = f"https://youglish.com/api/v1/videos/search?key={API_KEY}&query={query}&lg=english" - - response = requests.get(url, headers=headers) - if response.status_code != 200: - return jsonify({'error': 'Failed to search videos'}), response.status_code - - videos = response.json() - return jsonify(videos) - -@app.route('/get_video') -def get_video(): - video_id = request.args.get('video_id') - if not video_id: - return jsonify({'error': 'Please provide a video_id parameter'}), 400 - - headers = {'Authorization': 'Bearer ' + API_KEY} - url = f"https://youglish.com/api/v1/videos/{video_id}" - - response = requests.get(url, headers=headers) - if response.status_code != 200: - return jsonify({'error': 'Failed to get video'}), response.status_code - - video = response.json() - return jsonify(video) - -if __name__ == '__main__': - app.run(debug=True) From 5548a8738c91751495cef623fcf77a9e3c1b96b6 Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:29:05 -0700 Subject: [PATCH 4/8] Added youglish and youtube api requests added youglish_proxy which uses youglish and youtube API keys which are pulled from a file called api_keys --- ComSemApp/views.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/ComSemApp/views.py b/ComSemApp/views.py index c12268f98..31660b0c5 100644 --- a/ComSemApp/views.py +++ b/ComSemApp/views.py @@ -15,6 +15,9 @@ from .models import Admin, Teacher, Student from ComSemApp.administrator.forms import SignupForm, ContactForm +from django.http import JsonResponse +from .api_keys import API_KEY, YOUTUBE_API_KEY + # TODO - these are the sort of extra views that don't exactly fit into one of the existing "apps" # and should be reorganized and tested @@ -89,3 +92,33 @@ def initiate_roles(request): if Student.objects.filter(user=request.user).exists(): return redirect('/student/') + + +def youglish_proxy(request): + if request.method == 'GET': + query = request.GET.get('q') + skip = request.GET.get('skip', 0) + max = request.GET.get('max', 10) + + youglish_url = f'https://youglish.com/api/v1/videos/search?key={API_KEY}&query={query}&lg=english&max={max}&skip={skip}' + + try: + # Make a GET request to the Youglish API using requests + response = requests.get(youglish_url) + data = response.json() + + # Add YouTube video details to each video result + for video in data['results']: + video_id = video['vid'] + video_url = f'https://www.googleapis.com/youtube/v3/videos?id={video_id}&key={YOUTUBE_API_KEY}&part=snippet' + youtube_response = requests.get(video_url).json() + video['title'] = youtube_response['items'][0]['snippet']['title'] + video['thumbnail'] = youtube_response['items'][0]['snippet']['thumbnails']['default']['url'] + + # Return the response data as a JSON object to the client + return JsonResponse(data) + except Exception as e: + print(e) + return JsonResponse({'error': 'An error occurred while fetching data from Youglish API'}) + + return JsonResponse({'error': 'Invalid Request'}) From 1be7c907108b5029c6baca8ae4f04bfad872e8fd Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:31:15 -0700 Subject: [PATCH 5/8] added youglish_proxy url --- ComSemApp/urls.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ComSemApp/urls.py b/ComSemApp/urls.py index 739539193..fe9b8a486 100644 --- a/ComSemApp/urls.py +++ b/ComSemApp/urls.py @@ -1,8 +1,11 @@ from django.conf.urls import url, include +from django.urls import path from . import views from ComSemApp.utils import transcribe +from .views import youglish_proxy + urlpatterns = [ url(r'^$', views.About.as_view(), name='about'), url(r'^about/teacher/$', views.AboutTeacher.as_view(), name='about_teacher'), @@ -14,4 +17,5 @@ url(r'^student/', include('ComSemApp.student.urls', namespace='student')), url(r'^corpus/', include('ComSemApp.corpus.urls', namespace='corpus')), url(r'^transcribe_audio/', transcribe, name='transcribe_audio'), + path('youglish-proxy/', youglish_proxy, name='youglish_proxy'), ] From 4343113852a1933c4cfcaf7004762b29482be496 Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:36:10 -0700 Subject: [PATCH 6/8] Update youglish-api-sandbox.js --- ComSemApp/student/youglish-api-sandbox.js | 61 ++++++++++++++--------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/ComSemApp/student/youglish-api-sandbox.js b/ComSemApp/student/youglish-api-sandbox.js index b57868e63..ad751495e 100644 --- a/ComSemApp/student/youglish-api-sandbox.js +++ b/ComSemApp/student/youglish-api-sandbox.js @@ -11,10 +11,15 @@ Ajax - A technique used to make asynchronous HTTP requests from the client-side $(document).ready(function() { // Define the URL for the Youglish proxy API and the query string - const apiUrl = 'http://localhost:3000/youglish-proxy'; + + //use this for node server + //const apiUrl = 'http://localhost:3000/youglish-proxy'; + //use this apiUrl if using Django + const apiUrl = '/youglish-proxy'; + const query = 'explaining'; //replace with searched for word - const youtubeApiKey = 'AIzaSyDQoynj7T6sa77hqlheFTgIIuuGTb1dQng'; + const youtubeApiKey = 'AIzaSyCWqdb9QDYo2Z6P_WqWwXF-s3-38_UnbaE'; // Initialize empty arrays and variables to hold video data let videos = []; @@ -72,54 +77,56 @@ $(document).ready(function() { }); } + // Function to display the sentence with highlighting + function displaySentence(sentence, query) { + const highlightedSentence = sentence.replace( + new RegExp(`\\b${query}\\b`, 'gi'), + (match) => `${match}` + ); + $('#sentence-container').html(highlightedSentence); + } + //Function displays the video at the specified index. - function displayVideo(videoIndex) { + async function displayVideo(videoIndex, sentences = 2) { if (videoIndex >= videos.length) { console.warn('No more available videos.'); return; } - - // Get the video ID, start time, and end time of the video at the specified index + const videoId = videos[videoIndex].vid; const startTime = videos[videoIndex].start; - const endTime = videos[videoIndex].end; - - // Calculate the buffered start and end times (2 seconds before and after the specified times) - const bufferedStartTime = parseInt(startTime) - 2; - const bufferedEndTime = parseInt(endTime) + 2; - + const sentenceDuration = videos[videoIndex].dur; + const endTime = startTime + (sentences * sentenceDuration); + console.log("Extracted video ID:", videoId); - - // Call the fetchVideoDetails function to get details about the video + fetchVideoDetails( videoId, - function (response) { - // Check if the response contains any items and if the video is embeddable and public + async function (response) { if (response.items.length > 0 && response.items[0].status.embeddable && response.items[0].status.privacyStatus === "public") { - // If the player already exists, load the video if (player) { player.loadVideoById({ videoId: videoId, startSeconds: startTime, endSeconds: endTime }); - } else { // Otherwise, create a new player + } else { player = new YT.Player('video-container', { height: '270', width: '480', videoId: videoId, playerVars: { - 'autoplay': 1, - 'start': bufferedStartTime, - 'end': bufferedEndTime, + 'autoplay': 0, + 'start': startTime, + 'end': endTime, }, events: { 'onStateChange': onPlayerStateChange, }, }); } - // Update the video index and the current video index $('#video-index').text(videoIndex + 1); currentVideoIndex = videoIndex; + + displaySentence(videos[videoIndex].display, query); } else { console.warn('Video is not available:', videoId); - // If the video is not available, skip it and try the next one displayVideo(videoIndex + 1); } }, @@ -128,7 +135,13 @@ $(document).ready(function() { } ); } - + + function playNextVideo() { + if (currentVideoIndex < videos.length - 1) { + currentVideoIndex++; + displayVideo(currentVideoIndex); + } + } /** * This function handles changes to the state of the YouTube player. @@ -214,4 +227,4 @@ $(document).ready(function() { getYouglishData(); }); - \ No newline at end of file + From 7a58cb65414896a7cabf1c7ac2e274d403aa31b2 Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:39:35 -0700 Subject: [PATCH 7/8] independent html file for youglish testing doesn't work with current ComSem --- .../templates/ComSemApp/youglish-test.html | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 ComSemApp/templates/ComSemApp/youglish-test.html diff --git a/ComSemApp/templates/ComSemApp/youglish-test.html b/ComSemApp/templates/ComSemApp/youglish-test.html new file mode 100644 index 000000000..1437e2a6a --- /dev/null +++ b/ComSemApp/templates/ComSemApp/youglish-test.html @@ -0,0 +1,85 @@ + + + + + + + + + API Test + + + + + + +

Youglish API Test

+
+ + +
+ + / + +
+ + +
+
+ + + + + + + + + + From aac3112de894226f021c5f789a808bfd20566e4c Mon Sep 17 00:00:00 2001 From: Jared-Torii <59457233+Jared-Torii@users.noreply.github.com> Date: Wed, 12 Apr 2023 10:30:37 -0700 Subject: [PATCH 8/8] switching youtube api for embedded iframe --- ComSemApp/student/youglish-api-sandbox.js | 151 +++------------------- 1 file changed, 17 insertions(+), 134 deletions(-) diff --git a/ComSemApp/student/youglish-api-sandbox.js b/ComSemApp/student/youglish-api-sandbox.js index ad751495e..b7cbf745c 100644 --- a/ComSemApp/student/youglish-api-sandbox.js +++ b/ComSemApp/student/youglish-api-sandbox.js @@ -6,6 +6,8 @@ Youglish API - Receives requests from the client and sends them to the Youglish YouTube API - A set of RESTful APIs that provides functionality to search for videos, retrieve video details, and play videos from youtube. jQuery - A JavaScript library that simplifies DOM manipulation, event handling, and Ajax interactions. Ajax - A technique used to make asynchronous HTTP requests from the client-side code to the server-side code. + +C:/Users/Jared/GonzagaCPSC/YouglishAPI_JQuery-AJAX/youglish-test.html */ $(document).ready(function() { @@ -13,69 +15,16 @@ $(document).ready(function() { // Define the URL for the Youglish proxy API and the query string //use this for node server - //const apiUrl = 'http://localhost:3000/youglish-proxy'; + const apiUrl = 'http://localhost:3000/youglish-proxy'; //use this apiUrl if using Django - const apiUrl = '/youglish-proxy'; + //const apiUrl = '/youglish-proxy'; const query = 'explaining'; //replace with searched for word - const youtubeApiKey = 'AIzaSyCWqdb9QDYo2Z6P_WqWwXF-s3-38_UnbaE'; - // Initialize empty arrays and variables to hold video data let videos = []; - let player; let currentVideoIndex = 0; - // Function to fetch video details from the YouTube API - function fetchVideoDetails(videoId, onSuccess, onFailure) { - // Make an AJAX request to the YouTube API using jQuery - $.ajax({ - url: 'https://www.googleapis.com/youtube/v3/videos', - type: 'GET', - dataType: 'json', - data: { - key: youtubeApiKey, - id: videoId, - part: 'snippet,contentDetails,statistics,status', - }, - success: onSuccess, - error: function (jqXHR, textStatus, errorThrown) { - console.error('YouTube Data API request failed:', textStatus, errorThrown); - console.error('Response:', jqXHR.responseText); - console.error('Video id: ',videoId); - if (onFailure) { - onFailure(jqXHR, textStatus, errorThrown); // If the request fails, call the onFailure function (if provided) - } - }, - }); - } - - // Function to request additional Youglish data from the API - function requestAdditionalYouglishData() { - // Make an AJAX request to the Youglish proxy API using jQuery - $.ajax({ - url: apiUrl, - type: 'GET', - dataType: 'json', - data: { - 'q': query, - 'skip': videos.length, - 'max': 3, - }, - success: function (response) { - console.log(response); - // Add the new results to the existing videos array, slicing to the first 3 - videos = videos.concat(response.results.slice(0, 3)); - // Update the total number of videos in the UI - $('#total-videos').text(videos.length); - // Display the current video - displayVideo(currentVideoIndex); - }, - error: function (jqXHR, textStatus, errorThrown) { - console.error('Error:', textStatus, errorThrown); - }, - }); - } // Function to display the sentence with highlighting function displaySentence(sentence, query) { @@ -96,88 +45,24 @@ $(document).ready(function() { const videoId = videos[videoIndex].vid; const startTime = videos[videoIndex].start; const sentenceDuration = videos[videoIndex].dur; - const endTime = startTime + (sentences * sentenceDuration); + const endTime = startTime + sentences * sentenceDuration; - console.log("Extracted video ID:", videoId); + console.log('Extracted video ID:', videoId); - fetchVideoDetails( - videoId, - async function (response) { - if (response.items.length > 0 && response.items[0].status.embeddable && response.items[0].status.privacyStatus === "public") { - if (player) { - player.loadVideoById({ videoId: videoId, startSeconds: startTime, endSeconds: endTime }); - } else { - player = new YT.Player('video-container', { - height: '270', - width: '480', - videoId: videoId, - playerVars: { - 'autoplay': 0, - 'start': startTime, - 'end': endTime, - }, - events: { - 'onStateChange': onPlayerStateChange, - }, - }); - } - $('#video-index').text(videoIndex + 1); - currentVideoIndex = videoIndex; + const iframe = document.createElement('iframe'); + iframe.width = '480'; + iframe.height = '270'; + iframe.src = `https://www.youtube.com/embed/${videoId}?start=${startTime}&end=${endTime}&autoplay=1&enablejsapi=1`; + iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'; - displaySentence(videos[videoIndex].display, query); - } else { - console.warn('Video is not available:', videoId); - displayVideo(videoIndex + 1); - } - }, - function (jqXHR, textStatus, errorThrown) { - console.error('Error fetching video details:', textStatus, errorThrown); - } - ); - } + const videoContainer = document.getElementById('video-container'); + videoContainer.innerHTML = ''; // Clear the previous iframe + videoContainer.appendChild(iframe); - function playNextVideo() { - if (currentVideoIndex < videos.length - 1) { - currentVideoIndex++; - displayVideo(currentVideoIndex); - } - } + $('#video-index').text(videoIndex + 1); + currentVideoIndex = videoIndex; - /** - * This function handles changes to the state of the YouTube player. - * It seeks to the start time of the current video when the player starts playing, - * and reloads the video or moves to the next one when it ends. - */ - function onPlayerStateChange(event) { - const startTime = videos[currentVideoIndex].start; - const endTime = videos[currentVideoIndex].end; - - if (event.data === YT.PlayerState.ENDED) { - const duration = endTime - startTime; - - if (player.getCurrentTime() < endTime - 1) { - // If the video ends prematurely, attempt to reload it - setTimeout(() => { - player.loadVideoById({ videoId: player.getVideoData().video_id, startSeconds: startTime, endSeconds: endTime }); - }, 1000); - } else { - if (currentVideoIndex < videos.length - 1) { - setTimeout(() => { - currentVideoIndex++; - displayVideo(currentVideoIndex); - }, 3000); // 3-second buffer - } else { - requestAdditionalYouglishData(); - } - } - } else if (event.data === YT.PlayerState.PLAYING) { - const currentTime = player.getCurrentTime(); - - // Check if the current time is within 1 second of the start time - if (Math.abs(currentTime - startTime) > 1) { - player.seekTo(startTime, true); - } - } + displaySentence(videos[videoIndex].display, query); } function displayVideos(results) { @@ -226,5 +111,3 @@ $(document).ready(function() { // Retrieve Youglish data when the page loads getYouglishData(); }); - -