|
|
@@ -1,101 +1,153 @@
|
|
|
// Background script for the extension
|
|
|
|
|
|
+browser.storage.local.get("playlists").then(function (data) {
|
|
|
+ if (!data.playlists) {
|
|
|
+ console.log("pre-populating playlists");
|
|
|
+ browser.storage.local.set({
|
|
|
+ playlists: {
|
|
|
+ "listening-1": [],
|
|
|
+ "listening-2": [],
|
|
|
+ "listening-3": [],
|
|
|
+ "watching-1": [],
|
|
|
+ "watching-2": [],
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log("no need to pre-populate playlists");
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+browser.storage.local.get("history").then(function (data) {
|
|
|
+ if (!data.history) {
|
|
|
+ console.log("pre-populating history");
|
|
|
+ browser.storage.local.set({
|
|
|
+ history: {},
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log("no need to pre-populate history");
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
// Create context menu items when the extension is installed
|
|
|
browser.runtime.onInstalled.addListener(() => {
|
|
|
// Parent menu item
|
|
|
browser.contextMenus.create({
|
|
|
- id: "my-extension-menu",
|
|
|
- title: "My Firefox Extension",
|
|
|
- contexts: ["all"]
|
|
|
+ id: "my-playlist-menu",
|
|
|
+ title: "Add to Playlist",
|
|
|
+ contexts: ["link"],
|
|
|
+ targetUrlPatterns: ["https://*.youtube.com/watch*"],
|
|
|
});
|
|
|
-
|
|
|
+
|
|
|
// Sub-menu items
|
|
|
browser.contextMenus.create({
|
|
|
- id: "inject-script",
|
|
|
- parentId: "my-extension-menu",
|
|
|
- title: "Inject Script",
|
|
|
- contexts: ["all"]
|
|
|
+ id: "listening-1",
|
|
|
+ parentId: "my-playlist-menu",
|
|
|
+ title: "Listening - 1",
|
|
|
+ contexts: ["link"],
|
|
|
});
|
|
|
-
|
|
|
+
|
|
|
browser.contextMenus.create({
|
|
|
- id: "save-selection",
|
|
|
- parentId: "my-extension-menu",
|
|
|
- title: "Save Selection",
|
|
|
- contexts: ["selection"]
|
|
|
+ id: "listening-2",
|
|
|
+ parentId: "my-playlist-menu",
|
|
|
+ title: "Listening - 2",
|
|
|
+ contexts: ["link"],
|
|
|
});
|
|
|
-
|
|
|
+
|
|
|
browser.contextMenus.create({
|
|
|
- id: "navigate-to-homepage",
|
|
|
- parentId: "my-extension-menu",
|
|
|
- title: "Go to Homepage",
|
|
|
- contexts: ["all"]
|
|
|
+ id: "listening-3",
|
|
|
+ parentId: "my-playlist-menu",
|
|
|
+ title: "Listening - 3",
|
|
|
+ contexts: ["link"],
|
|
|
});
|
|
|
|
|
|
// Separator
|
|
|
browser.contextMenus.create({
|
|
|
id: "separator-1",
|
|
|
- parentId: "my-extension-menu",
|
|
|
+ parentId: "my-playlist-menu",
|
|
|
type: "separator",
|
|
|
- contexts: ["all"]
|
|
|
+ contexts: ["link"],
|
|
|
});
|
|
|
-
|
|
|
+
|
|
|
browser.contextMenus.create({
|
|
|
- id: "custom-action",
|
|
|
- parentId: "my-extension-menu",
|
|
|
- title: "Custom Action",
|
|
|
- contexts: ["link", "image"]
|
|
|
+ id: "watching-1",
|
|
|
+ parentId: "my-playlist-menu",
|
|
|
+ title: "Watching - 1",
|
|
|
+ contexts: ["link"],
|
|
|
});
|
|
|
+
|
|
|
+ browser.contextMenus.create({
|
|
|
+ id: "watching-2",
|
|
|
+ parentId: "my-playlist-menu",
|
|
|
+ title: "Watching - 2",
|
|
|
+ contexts: ["link"],
|
|
|
+ });
|
|
|
+
|
|
|
+ // test message
|
|
|
+ //browser.tabs.sendMessage(tab.id, payload);
|
|
|
});
|
|
|
|
|
|
-// Context menu click handler
|
|
|
-browser.contextMenus.onClicked.addListener((info, tab) => {
|
|
|
- switch (info.menuItemId) {
|
|
|
- case "inject-script":
|
|
|
- browser.tabs.sendMessage(tab.id, { command: 'injectCode' })
|
|
|
- .catch(error => {
|
|
|
- // If content script isn't loaded yet, inject it first
|
|
|
- browser.tabs.executeScript(tab.id, { file: '/content_scripts/content.js' })
|
|
|
- .then(() => {
|
|
|
- browser.tabs.sendMessage(tab.id, { command: 'injectCode' });
|
|
|
- });
|
|
|
- });
|
|
|
- break;
|
|
|
-
|
|
|
- case "save-selection":
|
|
|
- if (info.selectionText) {
|
|
|
- browser.storage.local.set({
|
|
|
- 'lastSelection': info.selectionText,
|
|
|
- 'selectionTime': Date.now()
|
|
|
- }).then(() => {
|
|
|
- // Optional: Show a notification
|
|
|
- browser.notifications.create({
|
|
|
- type: "basic",
|
|
|
- iconUrl: browser.runtime.getURL("icons/icon-48.png"),
|
|
|
- title: "Selection Saved",
|
|
|
- message: "Text has been saved to extension storage"
|
|
|
- });
|
|
|
- });
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case "navigate-to-homepage":
|
|
|
- const homepage = "https://example.com";
|
|
|
- browser.tabs.update(tab.id, { url: homepage });
|
|
|
- break;
|
|
|
-
|
|
|
- case "custom-action":
|
|
|
- // Handle different context types
|
|
|
- if (info.linkUrl) {
|
|
|
- // Custom action for links
|
|
|
- console.log("Link URL:", info.linkUrl);
|
|
|
- // For example, copy link to clipboard or open in new tab with modifications
|
|
|
- } else if (info.srcUrl) {
|
|
|
- // Custom action for images
|
|
|
- console.log("Image URL:", info.srcUrl);
|
|
|
- // For example, save image or process it
|
|
|
+function findMatchingUrlKey(current, inputUrl) {
|
|
|
+ // Extract the "v" query parameter from input URL
|
|
|
+ let inputVParam;
|
|
|
+ try {
|
|
|
+ const urlObj = new URL(inputUrl);
|
|
|
+ inputVParam = urlObj.searchParams.get("v");
|
|
|
+ } catch (e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If no "v" parameter found, return false
|
|
|
+ if (!inputVParam) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check each key in the current object
|
|
|
+ for (const key in current) {
|
|
|
+ const items = current[key];
|
|
|
+
|
|
|
+ // Check each item in the array
|
|
|
+ for (const item of items) {
|
|
|
+ try {
|
|
|
+ const itemUrl = new URL(item.url);
|
|
|
+ const itemVParam = itemUrl.searchParams.get("v");
|
|
|
+
|
|
|
+ // If the "v" parameters match, return this key
|
|
|
+ if (itemVParam === inputVParam) {
|
|
|
+ return key;
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ // Skip malformed URLs
|
|
|
+ continue;
|
|
|
}
|
|
|
- break;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ // No match found
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+async function addLinkToPlaylist(plName, item) {
|
|
|
+ const { playlists: currentPlaylists } =
|
|
|
+ await browser.storage.local.get("playlists");
|
|
|
+
|
|
|
+ const alreadyHave = findMatchingUrlKey(currentPlaylists, item.linkUrl);
|
|
|
+
|
|
|
+ if (alreadyHave) {
|
|
|
+ console.log("already have that link in", alreadyHave);
|
|
|
+ } else {
|
|
|
+ const { [plName]: playlist, ...others } = currentPlaylists;
|
|
|
+ await browser.storage.local.set({
|
|
|
+ playlists: {
|
|
|
+ [plName]: [...playlist, { url: item.linkUrl, title: item.linkText }],
|
|
|
+ ...others,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Context menu click handler
|
|
|
+browser.contextMenus.onClicked.addListener(async (item, _tab) => {
|
|
|
+ addLinkToPlaylist(item.menuItemId, item);
|
|
|
});
|
|
|
|
|
|
// Function to navigate a tab to a new URL
|
|
|
@@ -103,33 +155,89 @@ function navigateTab(tabId, url) {
|
|
|
return browser.tabs.update(tabId, { url: url });
|
|
|
}
|
|
|
|
|
|
+async function updateHistory(message) {
|
|
|
+ const { history: currentHistory } =
|
|
|
+ await browser.storage.local.get("history");
|
|
|
+ console.log("currentHistory", currentHistory);
|
|
|
+ const q = new URL(message.url);
|
|
|
+ const v = q.searchParams.get("v");
|
|
|
+ console.log("v??", message.url, q, q.searchParams.get("v"));
|
|
|
+ console.log("history?", currentHistory[v]);
|
|
|
+ if (currentHistory[v]) {
|
|
|
+ const { [v]: existing, ...rest } = currentHistory;
|
|
|
+ await browser.storage.local.set({
|
|
|
+ history: {
|
|
|
+ [v]: {
|
|
|
+ ...existing,
|
|
|
+ duration:
|
|
|
+ !isNaN(existing.duration) && isFinite(existing.duration)
|
|
|
+ ? Math.max(message.duration, existing.duration)
|
|
|
+ : message.duration,
|
|
|
+ history: [
|
|
|
+ ...existing.history,
|
|
|
+ {
|
|
|
+ action: message.type,
|
|
|
+ position: message.timestamp,
|
|
|
+ timestamp: Date.now(),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ...rest,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ await browser.storage.local.set({
|
|
|
+ history: {
|
|
|
+ [v]: {
|
|
|
+ url: message.url,
|
|
|
+ title: message.title,
|
|
|
+ duration: message.duration,
|
|
|
+ history: [
|
|
|
+ {
|
|
|
+ action: message.type,
|
|
|
+ position: message.timestamp,
|
|
|
+ timestamp: Date.now(),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ...currentHistory,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ console.log("proposed:", {
|
|
|
+ url: message.url,
|
|
|
+ title: message.title,
|
|
|
+ duration: message.duration,
|
|
|
+ history: [
|
|
|
+ {
|
|
|
+ action: message.type,
|
|
|
+ position: message.timestamp,
|
|
|
+ timestamp: Date.now(),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
// Listen for messages from popup or content scripts
|
|
|
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
- if (message.command === 'navigate') {
|
|
|
+ console.log("MESSAGE", message);
|
|
|
+ switch (message.type) {
|
|
|
+ case "ended":
|
|
|
+ console.log("ENDED");
|
|
|
+ case "play":
|
|
|
+ case "playing":
|
|
|
+ case "pause":
|
|
|
+ updateHistory(message);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (message.command === "navigate") {
|
|
|
if (message.tabId && message.url) {
|
|
|
navigateTab(message.tabId, message.url)
|
|
|
- .then(() => sendResponse({ status: 'success' }))
|
|
|
- .catch(error => sendResponse({ status: 'error', message: error.message }));
|
|
|
+ .then(() => sendResponse({ status: "success" }))
|
|
|
+ .catch((error) =>
|
|
|
+ sendResponse({ status: "error", message: error.message }),
|
|
|
+ );
|
|
|
return true; // Required for async sendResponse
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
-
|
|
|
-// Listen for tab updates to potentially inject scripts on certain URLs
|
|
|
-browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
|
|
- if (changeInfo.status === 'complete' && tab.url) {
|
|
|
- // Check if the URL matches your patterns and inject scripts as needed
|
|
|
- const urlPatterns = [
|
|
|
- /example\.com/,
|
|
|
- /another-site\.org/
|
|
|
- // Add more URL patterns as needed
|
|
|
- ];
|
|
|
-
|
|
|
- const shouldInject = urlPatterns.some(pattern => pattern.test(tab.url));
|
|
|
-
|
|
|
- if (shouldInject) {
|
|
|
- browser.tabs.executeScript(tabId, { file: '/content_scripts/content.js' })
|
|
|
- .catch(error => console.error('Error injecting script:', error));
|
|
|
- }
|
|
|
- }
|
|
|
-});
|