Skip to content

Commit 8d8dbf9

Browse files
committed
Added Generate Quiz from Youtube Video Feature
1 parent 21c07b2 commit 8d8dbf9

File tree

3 files changed

+153
-23
lines changed

3 files changed

+153
-23
lines changed

backend/server.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from flask_cors import CORS
33
from pprint import pprint
44
import nltk
5+
import subprocess
6+
import os
7+
import glob
58

69
from sklearn.metrics.pairwise import cosine_similarity
710
from sklearn.feature_extraction.text import TfidfVectorizer
@@ -406,6 +409,65 @@ def upload_file():
406409
def hello():
407410
return "The server is working fine"
408411

412+
def clean_transcript(file_path):
413+
"""Extracts and cleans transcript from a VTT file."""
414+
with open(file_path, "r", encoding="utf-8") as file:
415+
lines = file.readlines()
416+
417+
transcript_lines = []
418+
skip_metadata = True # Skip lines until we reach actual captions
419+
420+
for line in lines:
421+
line = line.strip()
422+
423+
# Skip metadata lines like "Kind: captions" or "Language: en"
424+
if line.lower().startswith(("kind:", "language:", "webvtt")):
425+
continue
426+
427+
# Detect timestamps like "00:01:23.456 --> 00:01:25.789"
428+
if "-->" in line:
429+
skip_metadata = False # Now real captions start
430+
continue
431+
432+
if not skip_metadata:
433+
# Remove formatting tags like <c>...</c> and <00:00:00.000>
434+
line = re.sub(r"<[^>]+>", "", line)
435+
transcript_lines.append(line)
436+
437+
return " ".join(transcript_lines).strip()
438+
439+
@app.route('/getTranscript', methods=['GET'])
440+
def get_transcript():
441+
video_id = request.args.get('videoId')
442+
if not video_id:
443+
return jsonify({"error": "No video ID provided"}), 400
444+
445+
video_url = f"https://www.youtube.com/watch?v={video_id}"
446+
command = [
447+
"yt-dlp",
448+
"--write-auto-sub",
449+
"--sub-lang", "en",
450+
"--skip-download",
451+
"--sub-format", "vtt",
452+
"-o", "subtitles/%(title)s [%(id)s].%(ext)s",
453+
video_url
454+
]
455+
456+
subprocess.run(command, capture_output=True, text=True)
457+
458+
# Find the latest .vtt file in the "subtitles" folder
459+
subtitle_files = glob.glob("subtitles/*.vtt")
460+
if not subtitle_files:
461+
return jsonify({"error": "No subtitles found"}), 404
462+
463+
latest_subtitle = max(subtitle_files, key=os.path.getctime)
464+
transcript_text = clean_transcript(latest_subtitle)
465+
466+
# Optional: Clean up the file after reading
467+
os.remove(latest_subtitle)
468+
469+
return jsonify({"transcript": transcript_text})
409470

410471
if __name__ == "__main__":
472+
os.makedirs("subtitles", exist_ok=True)
411473
app.run()

extension/public/background.js

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
// Create context menu on installation
2-
chrome.runtime.onInstalled.addListener(() => {
3-
chrome.contextMenus.create({
4-
id: "askExtension",
5-
title: "Generate Quiz with Selected Text",
6-
contexts: ["selection"]
7-
});
1+
// Create context menus
2+
chrome.contextMenus.create({
3+
id: "askExtension",
4+
title: "Generate Quiz with Selected Text",
5+
contexts: ["selection"]
86
});
9-
10-
// Handle context menu clicks
11-
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
7+
8+
// YouTube-specific quiz generator
9+
chrome.contextMenus.create({
10+
id: "generateQuizFromYouTube",
11+
title: "Generate Quiz from YouTube Video",
12+
contexts: ["page"],
13+
documentUrlPatterns: ["*://www.youtube.com/watch?v=*"]
14+
});
15+
16+
// Handle context menu clicks
17+
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
1218
if (info.menuItemId === "askExtension" && info.selectionText) {
1319
try {
1420
// Store the selected text first
@@ -51,10 +57,43 @@ chrome.runtime.onInstalled.addListener(() => {
5157
console.error("Error in context menu handler:", error);
5258
}
5359
}
54-
});
55-
56-
// Listen for messages from content script
57-
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
60+
61+
if (info.menuItemId === "generateQuizFromYouTube") {
62+
try {
63+
// Check if script has already been injected
64+
const [{ result }] = await chrome.scripting.executeScript({
65+
target: { tabId: tab.id },
66+
func: () => window.youtubeScriptLoaded || false
67+
});
68+
69+
if (!result) {
70+
await chrome.scripting.executeScript({
71+
target: { tabId: tab.id },
72+
files: ["youtubeContentScript.js"]
73+
});
74+
} else {
75+
console.log("YouTube script already loaded");
76+
}
77+
// Add badge notification
78+
chrome.action.setBadgeText({
79+
text: "!"
80+
});
81+
chrome.action.setBadgeBackgroundColor({
82+
color: "#FF005C"
83+
});
84+
85+
// Clear the badge after 2 seconds
86+
setTimeout(() => {
87+
chrome.action.setBadgeText({ text: "" });
88+
}, 2000);
89+
} catch (error) {
90+
console.error("Error in YouTube quiz generation handler:", error);
91+
}
92+
}
93+
});
94+
95+
// Listen for messages from content script
96+
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
5897
if (request.type === "TEXT_SELECTED") {
5998
chrome.storage.local.set({
6099
selectedText: request.text
@@ -89,12 +128,3 @@ chrome.storage.onChanged.addListener((changes, namespace) => {
89128
}
90129
});
91130

92-
93-
// Optional: Handle extension install/update
94-
chrome.runtime.onInstalled.addListener((details) => {
95-
if (details.reason === "install") {
96-
console.log("Extension installed");
97-
} else if (details.reason === "update") {
98-
console.log("Extension updated");
99-
}
100-
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Function to extract YouTube video ID from the URL
2+
function getYouTubeVideoId() {
3+
const urlParams = new URLSearchParams(window.location.search);
4+
return urlParams.get("v");
5+
}
6+
7+
(() => {
8+
const videoId = getYouTubeVideoId();
9+
10+
if (videoId) {
11+
console.log("Extracted YouTube Video ID:", videoId);
12+
13+
fetch(`http://localhost:5000/getTranscript?videoId=${videoId}`)
14+
.then(response => response.json())
15+
.then(data => {
16+
if (data.transcript) {
17+
console.log("Transcript received:", data.transcript);
18+
chrome.storage.local.set({ videoTranscript: data.transcript }, () => {
19+
console.log("Transcript saved in storage.");
20+
});
21+
generateQuestions(data.transcript);
22+
} else {
23+
console.error("Failed to fetch transcript:", data.error);
24+
}
25+
})
26+
.catch(error => {
27+
console.error("Error fetching transcript:", error);
28+
});
29+
}
30+
})();
31+
32+
// Function to generate quiz questions from transcript
33+
function generateQuestions(transcript) {
34+
console.log("Generating questions from transcript...");
35+
chrome.storage.local.set({ "selectedText": transcript }, () => {
36+
console.log("Transcript stored for quiz generation.");
37+
});
38+
}

0 commit comments

Comments
 (0)