-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpopup.js
More file actions
413 lines (357 loc) · 12.9 KB
/
Copy pathpopup.js
File metadata and controls
413 lines (357 loc) · 12.9 KB
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
document.addEventListener('DOMContentLoaded', function () {
const apiKeyInput = document.getElementById('apiKeyInput');
const submitButton = document.getElementById('submitButton');
const addWatchListButton = document.getElementById('addWatchList');
const watchListInput = document.getElementById('watchListInput');
const submitWatchListButton = document.getElementById('submitWatchListButton');
const bearerTokenLabel = document.getElementById('bearerTokenLabel');
const bearerTokenInput = document.getElementById('bearerTokenInput');
const responseElement = document.getElementById('responseMessage');
const messageElement = document.querySelector('.message');
// Store the accountId once retrieved.
let accountId;
function showSpinner(element) {
const spinner = document.createElement('span');
spinner.classList.add('spinner');
if (element == document.querySelector('.message')) {
spinner.style.marginTop = '20px';
}
element.insertAdjacentElement('afterend', spinner);
}
// Function to hide the spinner
function hideSpinner() {
const spinner = document.querySelector('.spinner');
if (spinner) {
spinner.remove();
}
}
submitButton.addEventListener('click', function () {
showSpinner(messageElement);
const apiKey = apiKeyInput.value.trim();
if (apiKey) {
// Check the validity of the API key
verifyApiKey(apiKey).then((isValid) => {
if (isValid) {
// Store the API key in Chrome storage
chrome.storage.sync.set({ apiKey }, function () {
console.log('API key:', apiKey);
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
const activeTab = tabs[0];
chrome.tabs.reload(activeTab.id);
showApiMessage('API key submitted successfully.', 'success');
hideSpinner();
});
});
} else {
hideSpinner();
showApiMessage('Invalid API key. Please enter a valid API key.', 'error');
}
});
} else {
hideSpinner();
showApiMessage('Please enter a valid API key.', 'error');
}
});
async function verifyApiKey(apiKey) {
// Simple test request to verify the validity of the API key
const testUrl = `https://api.themoviedb.org/3/configuration?api_key=${apiKey}`;
try {
const response = await fetch(testUrl);
const data = await response.json();
return data.status_code !== 7;
} catch {
return false;
}
}
// Function to show messages
function showApiMessage(message, type) {
messageElement.textContent = message;
messageElement.classList.remove('success', 'error');
messageElement.classList.add(type);
messageElement.style.display = 'block';
// Hide the message after 3 seconds
setTimeout(function () {
messageElement.style.display = 'none';
}, 3000);
}
// Function to retrieve the API key from the background script
function getApiKey() {
return new Promise((resolve) => {
chrome.runtime.sendMessage({ type: 'getApiKey' }, (apiKey) => {
if (apiKey) {
resolve(apiKey);
} else {
resolve(null);
}
});
});
}
addWatchListButton.addEventListener('click', async function () {
document.getElementById('initialContent').style.display = 'none';
document.getElementById('watchListContent').style.display = 'flex';
await bearerInputField();
});
function getBearerToken() {
return new Promise((resolve) => {
chrome.runtime.sendMessage({ type: 'getBearerToken' }, (bearerToken) => {
if (bearerToken) {
resolve(bearerToken);
} else {
resolve(null);
}
});
});
}
async function getAccountDetails(bearerToken) {
// Fetch account details from the API
const accountDetails = await fetchAccountDetails(bearerToken);
if (accountDetails && accountDetails.id) {
const accountId = accountDetails.id;
console.log('Account ID:', accountId);
return accountId;
}
else {
console.error('Account details not found or invalid bearer token.');
return null;
}
}
async function fetchAccountDetails(bearerToken) {
const url = 'https://api.themoviedb.org/3/account';
const headers = {
Authorization: bearerToken,
};
const response = await fetch(url, { headers });
if (response.ok) {
const data = await response.json();
return data;
} else {
console.error('Failed to fetch account details:', response.status);
return null;
}
}
submitWatchListButton.addEventListener('click', async function () {
showSpinner(responseElement);
resetMessageDisplay();
const bearerToken = bearerTokenInput.value.trim();
if (bearerToken) {
// Store the API key in Chrome storage
chrome.storage.sync.set({ bearerToken }, function () {
console.log('bearerToken :', bearerToken);
});
} else {
}
await main();
hideSpinner();
});
async function bearerInputField() {
let bearerToken = await getBearerToken();
if (!bearerToken) {
// Bearer token not found in input field, show the input field
bearerTokenLabel.style.display = 'block';
bearerTokenInput.style.display = 'block';
}
}
async function main() {
const apiKey = await getApiKey();
let bearerToken = await getBearerToken();
bearerToken = `Bearer ${bearerToken}`;
// Retrieve the movie list from the input field
const movieList = watchListInput.value.trim();
if (movieList) {
const movies = movieList.split(',');
if (apiKey && bearerToken) {
await addMoviesToWatchlist(movies, apiKey, bearerToken);
} else {
console.error('API key or bearer token not found');
}
} else {
console.log('No movie list provided');
}
}
// Global cache object to store search results
const movieCache = new Map();
async function searchMovie(title, year = null) {
const apiKey = await getApiKey();
const params = { api_key: apiKey, query: title };
if (year) {
params.primary_release_year = year;
}
// Check if the movie is already in the cache
const cacheKey = JSON.stringify(params);
if (movieCache.has(cacheKey)) {
return movieCache.get(cacheKey);
}
const url = 'https://api.themoviedb.org/3/search/movie';
const response = await fetch(url + '?' + new URLSearchParams(params));
if (response.ok) {
const data = await response.json();
const results = data.results;
if (results.length > 0) {
// Cache the search results for future use
movieCache.set(cacheKey, results[0]);
return results[0]; // Return the first result
} else {
return null;
}
} else {
console.error('Error:', response.status);
return null;
}
}
// Function to show response messages
function showResponseMessage(message, type) {
const newMessageElement = document.createElement('p');
newMessageElement.textContent = message;
newMessageElement.classList.add(type);
responseElement.appendChild(newMessageElement);
responseElement.style.display = 'grid';
responseElement.style.textAlign = 'center';
return newMessageElement;
}
function resetMessageDisplay() {
if (!responseElement) {
console.error('Error: responseMessage element not found.');
return;
}
// Clear the message content
responseElement.textContent = '';
responseElement.style.display = 'none';
}
async function checkMovieInWatchlist(movieId, apiKey, bearerToken) {
const headers = {
"Content-Type": "application/json;charset=utf-8",
Authorization: bearerToken,
};
if (!accountId) {
// Retrieve the accountId if it's not available
accountId = await getAccountDetails(bearerToken);
if (!accountId) {
console.error('Failed to get the accountId. Please check the bearer token.');
return false;
}
}
const response = await fetch(
`https://api.themoviedb.org/3/account/${accountId}/watchlist/movies?api_key=${apiKey}`,
{
method: "GET",
headers,
}
);
if (response.ok) {
const data = await response.json();
const watchlistMovies = data.results;
// Check if the movie with the given movieId is in the watchlist
const isInWatchlist = watchlistMovies.some((movie) => movie.id === movieId);
if (!isInWatchlist && data.total_pages > 1) {
// Fetch remaining pages of the watchlist in parallel
const pagePromises = [];
for (let page = 2; page <= data.total_pages; page++) {
pagePromises.push(
fetch(
`https://api.themoviedb.org/3/account/${accountId}/watchlist/movies?api_key=${apiKey}&page=${page}`,
{
method: "GET",
headers,
}
)
);
}
const pageResponses = await Promise.all(pagePromises);
const pageData = await Promise.all(pageResponses.map((res) => res.json()));
// Check if the movie is in any of the fetched pages
for (const pageMovies of pageData) {
if (pageMovies.results.some((movie) => movie.id === movieId)) {
return true;
}
}
}
return isInWatchlist;
} else {
throw new Error(`Failed to check watchlist: ${response.status}`);
}
}
async function addMoviesToWatchlist(movies, apiKey, bearerToken) {
if (!accountId) {
accountId = await getAccountDetails(bearerToken);
if (!accountId) {
console.error('Failed to get the account_id. Please check the bearer token.');
return;
}
}
const moviesAdded = [];
const errorMovies = [];
const notFoundMovies = [];
const invalidEntry = [];
const alreadyInWatchlistMovies = [];
const watchlistAPI = `https://api.themoviedb.org/3/account/${accountId}/watchlist?api_key=${apiKey}`;
const headers = {
"Content-Type": "application/json;charset=utf-8",
Authorization: bearerToken,
};
for (const movieEntry of movies) {
const trimmedEntry = movieEntry.trim();
const regex = /^(.*?)\s\((\d+)\)$/; // Regex pattern to extract movie title and year
if (!regex.test(trimmedEntry)) {
invalidEntry.push(movieEntry);
continue;
}
const [, movieTitle, movieYear] = trimmedEntry.match(regex);
const movie = await searchMovie(movieTitle, movieYear);
if (!movie) {
notFoundMovies.push(movieEntry);
continue;
}
const movieId = movie.id;
const isInWatchlist = await checkMovieInWatchlist(movieId, apiKey, bearerToken);
if (isInWatchlist) {
alreadyInWatchlistMovies.push(movieEntry);
} else {
const payload = {
media_type: "movie",
media_id: movieId,
watchlist: true,
};
const response = await fetch(watchlistAPI, {
method: "POST",
headers,
body: JSON.stringify(payload),
});
if (response.ok) {
console.log(`Added ${movieTitle} (${movieYear}) to watchlist`);
moviesAdded.push(`${movieTitle} (${movieYear})`);
} else {
console.error(`Error adding ${movieTitle} (${movieYear}) to watchlist:`, response.status);
errorMovies.push(`${movieTitle} (${movieYear})`);
}
}
}
// Show messages for already in watchlist, added, error, not found, and invalid entries
if (errorMovies.length > 0) {
const errorMessages = errorMovies.map((movie) => `${movie.title} (${movie.year})`);
const errorMessage = `Failed to add ${errorMovies.length} movies: ${errorMessages.join(', ')}.`;
showResponseMessage(errorMessage, 'error');
}
if (notFoundMovies.length > 0) {
const notFoundMessages = notFoundMovies.map((movieEntry) => `${movieEntry}`);
const notFoundMessage = `Failed to find ${notFoundMovies.length} movies: ${notFoundMessages.join(', ')}.`;
showResponseMessage(notFoundMessage, 'error');
}
if (invalidEntry.length > 0) {
const invalidMessages = invalidEntry.map((movieEntry) => `${movieEntry}`);
const invalidMessage = `Invalid Entry of ${invalidEntry.length} movies: ${invalidMessages.join(', ')}.`;
showResponseMessage(invalidMessage, 'error');
}
if (moviesAdded.length > 0) {
if (errorMovies.length === 0) {
showResponseMessage(`Added ${moviesAdded.length} movies successfully.`, 'success');
} else {
showResponseMessage(`Added ${moviesAdded.length} movies successfully, but some movies failed to be added.`, 'warning');
}
}
if (alreadyInWatchlistMovies.length > 0) {
const warningMessages = alreadyInWatchlistMovies.map((movie) => `${movie}`);
const warningMessage = `Warning: ${alreadyInWatchlistMovies.length} movies already in watchlist: ${warningMessages.join(', ')}.`;
showResponseMessage(warningMessage, 'warning');
}
}
});