-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcontent.js
185 lines (160 loc) · 5.8 KB
/
content.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// YouTube API Key - Replace with your own
const YOUTUBE_API_KEY = 'Replace with your own YouTube API key';
// Create and inject the UI
function createUI() {
const container = document.createElement('div');
container.id = 'leetcode-youtube-helper';
container.innerHTML = `
<div class="lc-yt-header">
<button id="toggleVideos" class="lc-yt-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-play"><polygon points="5 3 19 12 5 21 5 3"/></svg>
Watch Solutions
</button>
</div>
<div id="videoContainer" class="lc-yt-container hidden">
<div class="lc-yt-carousel">
<button class="carousel-btn prev">‹</button>
<div class="lc-yt-videos"></div>
<button class="carousel-btn next">›</button>
</div>
<div id="activeVideo" class="lc-yt-active-video hidden">
<div class="video-wrapper">
<iframe
id="player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen"
></iframe>
</div>
<button id="minimizeVideo" class="lc-yt-minimize-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-minimize-2"><polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/><line x1="14" y1="10" x2="21" y2="3"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
</button>
</div>
</div>
`;
document.body.appendChild(container);
setupEventListeners();
}
// Get problem title and search YouTube
async function searchYouTubeVideos() {
try {
const titleElement = document.querySelector(".text-title-large");
if (!titleElement) {
throw new Error('Could not find problem title');
}
const problemTitle = titleElement.textContent;
const searchQuery = `${problemTitle} leetcode solution`;
const response = await fetch(
`https://www.googleapis.com/youtube/v3/search?part=snippet&q=${encodeURIComponent(searchQuery)}&type=video&maxResults=10&key=${YOUTUBE_API_KEY}`
);
if (!response.ok) {
throw new Error(`YouTube API error: ${response.status}`);
}
const data = await response.json();
if (!data.items || !Array.isArray(data.items)) {
throw new Error('Invalid response from YouTube API');
}
return data.items;
} catch (error) {
console.error('Error fetching YouTube videos:', error);
showError('Failed to load videos. Please try again later.');
return [];
}
}
// Show error message
function showError(message) {
const videosContainer = document.querySelector('.lc-yt-videos');
if (videosContainer) {
videosContainer.innerHTML = `
<div class="lc-yt-error">
<p>${message}</p>
</div>
`;
}
}
// Create video thumbnails
function createVideoThumbnails(videos) {
const videosContainer = document.querySelector('.lc-yt-videos');
if (!videosContainer) return;
if (!videos || videos.length === 0) {
videosContainer.innerHTML = `
<div class="lc-yt-error">
<p>No videos found for this problem.</p>
</div>
`;
return;
}
videosContainer.innerHTML = '';
videos.forEach(video => {
const thumbnail = document.createElement('div');
thumbnail.className = 'lc-yt-thumbnail';
thumbnail.innerHTML = `
<img src="${video.snippet.thumbnails.medium.url}" alt="${video.snippet.title}">
<div class="lc-yt-thumbnail-info">
<h3>${video.snippet.title}</h3>
<p>${video.snippet.channelTitle}</p>
</div>
`;
thumbnail.addEventListener('click', () => playVideo(video.id.videoId));
videosContainer.appendChild(thumbnail);
});
}
// Play selected video
function playVideo(videoId) {
const player = document.getElementById('player');
const activeVideo = document.getElementById('activeVideo');
if (player && activeVideo) {
player.src = `https://www.youtube.com/embed/${videoId}?autoplay=1&modestbranding=1`;
activeVideo.classList.remove('hidden');
}
}
// Setup event listeners
function setupEventListeners() {
const toggleBtn = document.getElementById('toggleVideos');
const videoContainer = document.getElementById('videoContainer');
const minimizeBtn = document.getElementById('minimizeVideo');
const prevBtn = document.querySelector('.carousel-btn.prev');
const nextBtn = document.querySelector('.carousel-btn.next');
if (toggleBtn) {
toggleBtn.addEventListener('click', async () => {
if (videoContainer) {
videoContainer.classList.toggle('hidden');
if (!videoContainer.classList.contains('hidden')) {
const videos = await searchYouTubeVideos();
createVideoThumbnails(videos);
}
}
});
}
if (minimizeBtn) {
minimizeBtn.addEventListener('click', () => {
const activeVideo = document.getElementById('activeVideo');
if (activeVideo) {
activeVideo.classList.toggle('minimized');
}
});
}
if (prevBtn && nextBtn) {
prevBtn.addEventListener('click', () => {
const container = document.querySelector('.lc-yt-videos');
if (container) {
container.scrollBy({ left: -300, behavior: 'smooth' });
}
});
nextBtn.addEventListener('click', () => {
const container = document.querySelector('.lc-yt-videos');
if (container) {
container.scrollBy({ left: 300, behavior: 'smooth' });
}
});
}
}
// Initialize the extension
function init() {
createUI();
}
// Start the extension when the page is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}