From f2be37f2f9edfd6dcf70252bc07bd71c7823b023 Mon Sep 17 00:00:00 2001 From: Kasper Date: Sun, 23 Jun 2024 06:30:03 +0200 Subject: [PATCH] Manifest v3 --- src/background.ts | 131 ------------------------------------------ src/manifest.json | 99 +++++++++++++++---------------- src/service_worker.ts | 130 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 183 deletions(-) delete mode 100644 src/background.ts create mode 100644 src/service_worker.ts diff --git a/src/background.ts b/src/background.ts deleted file mode 100644 index 979ce6b..0000000 --- a/src/background.ts +++ /dev/null @@ -1,131 +0,0 @@ -function action(tabId, options) { - injectIfNotAlready(tabId, () => { - chrome.tabs.sendMessage(tabId, options); - }); -} - -function actionInCurrentTab(options) { - chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { - action(tabs[0].id, options); - }); -} - -chrome.browserAction.onClicked.addListener(function (tab) { - action(tab.id, { type: 'open' }); -}); - -chrome.runtime.onMessage.addListener(function (msg, _sender, _sendResponse) { - if (msg.type === 'options') { - chrome.runtime.openOptionsPage(); - } else if (msg.type === 'copyblob') { - try { - browser.clipboard.setImageData(msg.arrayBuffer, msg.imageType); - return Promise.resolve({ success: true }); - } catch (_error) { - return Promise.resolve({ success: false }); - } - } -}); - -chrome.commands.onCommand.addListener(function (command) { - if (['open', 'download', 'copy'].includes(command)) { - actionInCurrentTab({ type: command }); - } -}); - -function createContextMenus() { - chrome.storage.local.get( - { - grabMethod: 'Open', - cxOpen: false, - cxDownload: true, - cxCopy: false, - }, - function (items) { - if (chrome.runtime.lastError) { - console.warn( - `Error retrieving options:${chrome.runtime.lastError.message}`, - ); - } else { - if (items.cxOpen === true) { - chrome.contextMenus.create({ - id: 'open', - title: 'Open thumbnail', - contexts: ['page', 'video'], - }); - chrome.contextMenus.create({ - id: 'open-link', - title: 'Open thumbnail', - contexts: ['link'], - }); - } - if (items.cxDownload === true) { - chrome.contextMenus.create({ - id: 'download', - title: 'Download thumbnail', - contexts: ['page', 'video'], - }); - chrome.contextMenus.create({ - id: 'download-link', - title: 'Download thumbnail', - contexts: ['link'], - }); - } - if (items.cxCopy === true) { - chrome.contextMenus.create({ - id: 'copy', - title: 'Copy thumbnail', - contexts: ['page', 'video'], - }); - chrome.contextMenus.create({ - id: 'copy-link', - title: 'Copy thumbnail', - contexts: ['link'], - }); - } - } - }, - ); -} - -function injectIfNotAlready(tabId, callback) { - chrome.tabs.sendMessage(tabId, { type: 'existance-check' }, (response) => { - if (chrome.runtime.lastError) { - // handle error by do nothing - } - if (response && response.injected) { - // already injected - callback(true); - } else { - // not yet injected, so do that - chrome.tabs.executeScript(tabId, { file: 'content-script.js' }, () => { - chrome.tabs.insertCSS(tabId, { file: 'content-script.css' }, () => { - callback(); - }); - }); - } - }); -} - -chrome.contextMenus.onClicked.addListener((info, _tab) => { - let actionType = String(info.menuItemId); - if (actionType.endsWith('-link')) { - actionType = actionType.slice(0, -'-link'.length); - } - let url = info.linkUrl || info.pageUrl; - // if the url is incorrect, that error will be handled by the content script - if (info.linkUrl) { - actionInCurrentTab({ type: actionType, externalUrl: url }); - } else { - actionInCurrentTab({ type: actionType }); - } -}); - -chrome.runtime.onInstalled.addListener(function () { - createContextMenus(); -}); -chrome.storage.onChanged.addListener(function (_changes, _areaName) { - chrome.contextMenus.removeAll(() => { - createContextMenus(); - }); -}); diff --git a/src/manifest.json b/src/manifest.json index faf1473..370e357 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,54 +1,49 @@ { - "manifest_version": 2, - "name": "Thumbnail Grabber", - "version": "1.4.1", - "description": "Download thumbnails and covers from YouTube, SoundCloud, Spotify, YouTube Music and more", - "background": { - "scripts": [ - "background.ts" - ], - "persistent": false - }, - "options_ui": { - "page": "options.html", - "open_in_tab": false - }, - "icons": { - "16": "icon16.png", - "48": "icon48.png", - "128": "icon128.png" - }, - "browser_action": { - "default_icon": { - "16": "icon16.png", - "48": "icon48.png", - "128": "icon128.png" - } - }, - "web_accessible_resources": [ - "icon48.png", - "content-script.ts", - "content-script.css" - ], - "permissions": [ - "storage", - "contextMenus", - "activeTab", - "clipboardWrite", - "", - "*://i.ytimg.com/*", - "*://img.youtube.com/*", - "*://i1.sndcdn.com/*" - ], - "commands": { - "open": { - "description": "Open the Thumbnail Grabber popup on the current page" - }, - "download": { - "description": "Download the thumbnail of the current page" - }, - "copy": { - "description": "Copy the thumbnail of the current page to clipboard" - } - } + "manifest_version": 3, + "name": "Thumbnail Grabber", + "version": "1.4.1", + "description": "Download thumbnails and covers from YouTube, SoundCloud, Spotify, YouTube Music and more", + "background": { + "service_worker": "service_worker.ts" + }, + "options_ui": { + "page": "options.html", + "open_in_tab": false + }, + "icons": { + "16": "icon16.44e93582.png", + "48": "icon48.png", + "128": "icon128.8fd729f4.png" + }, + "action": { + "default_icon": { + "16": "icon16.44e93582.png", + "48": "icon48.png", + "128": "icon128.8fd729f4.png" + } + }, + "web_accessible_resources": [ + { + "resources": ["icon48.png", "content-script.ts", "content-script.css"], + "matches": [""] + } + ], + "permissions": ["storage", "contextMenus", "activeTab", "clipboardWrite"], + "host_permissions": [ + "", + "*://i.ytimg.com/*", + "*://img.youtube.com/*", + "*://i1.sndcdn.com/*" + ], + "commands": { + "open": { + "description": "Open the Thumbnail Grabber popup on the current page" + }, + "download": { + "description": "Download the thumbnail of the current page" + }, + "copy": { + "description": "Copy the thumbnail of the current page to clipboard" + } + } } diff --git a/src/service_worker.ts b/src/service_worker.ts new file mode 100644 index 0000000..8e376b1 --- /dev/null +++ b/src/service_worker.ts @@ -0,0 +1,130 @@ +async function action(tabId, options) { + await injectIfNotAlready(tabId); + chrome.tabs.sendMessage(tabId, options); +} + +async function actionInCurrentTab(options) { + const tabs = await chrome.tabs.query({ active: true, currentWindow: true }); + await action(tabs[0].id, options); +} + +chrome.action.onClicked.addListener(async (tab) => { + await action(tab.id, { type: 'open' }); +}); + +chrome.runtime.onMessage.addListener((msg, _sender, _sendResponse) => { + if (msg.type === 'options') { + chrome.runtime.openOptionsPage(); + } else if (msg.type === 'copyblob') { + try { + browser.clipboard.setImageData(msg.arrayBuffer, msg.imageType); + return Promise.resolve({ success: true }); + } catch (_error) { + return Promise.resolve({ success: false }); + } + } +}); + +chrome.commands.onCommand.addListener((command) => { + if (['open', 'download', 'copy'].includes(command)) { + actionInCurrentTab({ type: command }); + } +}); + +async function createContextMenus() { + const items = await chrome.storage.local.get({ + grabMethod: 'Open', + cxOpen: false, + cxDownload: true, + cxCopy: false, + }); + if (chrome.runtime.lastError) { + console.warn( + `Error retrieving options:${chrome.runtime.lastError.message}`, + ); + } else { + if (items.cxOpen === true) { + chrome.contextMenus.create({ + id: 'open', + title: 'Open thumbnail', + contexts: ['page', 'video'], + }); + chrome.contextMenus.create({ + id: 'open-link', + title: 'Open thumbnail', + contexts: ['link'], + }); + } + if (items.cxDownload === true) { + chrome.contextMenus.create({ + id: 'download', + title: 'Download thumbnail', + contexts: ['page', 'video'], + }); + chrome.contextMenus.create({ + id: 'download-link', + title: 'Download thumbnail', + contexts: ['link'], + }); + } + if (items.cxCopy === true) { + chrome.contextMenus.create({ + id: 'copy', + title: 'Copy thumbnail', + contexts: ['page', 'video'], + }); + chrome.contextMenus.create({ + id: 'copy-link', + title: 'Copy thumbnail', + contexts: ['link'], + }); + } + } +} + +async function injectIfNotAlready(tabId) { + const response = await chrome.tabs.sendMessage(tabId, { + type: 'existance-check', + }); + if (chrome.runtime.lastError) { + // handle error by do nothing + } + if (response && response.injected) { + // already injected + return true; + } else { + // not yet injected, so do that + await chrome.scripting.executeScript({ + target: { tabId: tabId }, + files: ['content-script.js'], + }); + await chrome.scripting.insertCSS({ + target: { tabId: tabId }, + files: ['content-script.css'], + }); + return false; + } +} + +chrome.contextMenus.onClicked.addListener((info, _tab) => { + let actionType = String(info.menuItemId); + if (actionType.endsWith('-link')) { + actionType = actionType.slice(0, -'-link'.length); + } + let url = info.linkUrl || info.pageUrl; + // if the url is incorrect, that error will be handled by the content script + if (info.linkUrl) { + actionInCurrentTab({ type: actionType, externalUrl: url }); + } else { + actionInCurrentTab({ type: actionType }); + } +}); + +chrome.runtime.onInstalled.addListener(async () => { + await createContextMenus(); +}); +chrome.storage.onChanged.addListener((_changes, _areaName) => { + chrome.contextMenus.removeAll(async () => { + await createContextMenus(); + }); +});