From ad0d8b673a1c7b90cb25ea81c762664a9e89d7b7 Mon Sep 17 00:00:00 2001 From: krau <71133316+krau@users.noreply.github.com> Date: Fri, 19 Jul 2024 23:08:39 +0800 Subject: [PATCH] feat: add content script to show floating notification BREAKING CHANGE: remove enable Notification checkbox --- config/webpack.config.js | 1 + public/manifest.json | 11 +++++ public/popup.html | 37 ++++----------- public/popup.js | 11 +---- src/background.js | 98 ++++++++++++++++++++-------------------- src/content.js | 88 ++++++++++++++++++++++++++++++++++++ 6 files changed, 160 insertions(+), 86 deletions(-) create mode 100644 src/content.js diff --git a/config/webpack.config.js b/config/webpack.config.js index 109dd92..607359c 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -9,6 +9,7 @@ const PATHS = require('./paths'); const config = merge(common, { entry: { background: PATHS.src + '/background.js', + content: PATHS.src + '/content.js', }, }); diff --git a/public/manifest.json b/public/manifest.json index 9374d47..2891710 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -21,5 +21,16 @@ "storage", "notifications", "contextMenus" + ], + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "content.js" + ], + "run_at": "document_end" + } ] } \ No newline at end of file diff --git a/public/popup.html b/public/popup.html index 20dc99a..bfb15a0 100644 --- a/public/popup.html +++ b/public/popup.html @@ -76,24 +76,17 @@ transition: opacity 0.5s ease; } - .checkbox-group { - display: flex; - flex-direction: column; - margin-bottom: 15px; - } - - /* 现代化的复选框样式 */ - .modern-checkbox { + .custom-checkbox { display: flex; align-items: center; margin-bottom: 10px; } - .modern-checkbox input[type="checkbox"] { + .custom-checkbox input[type="checkbox"] { display: none; } - .modern-checkbox label { + .custom-checkbox label { position: relative; padding-left: 30px; cursor: pointer; @@ -101,7 +94,7 @@ color: #333; } - .modern-checkbox label:before { + .custom-checkbox label:before { content: ""; position: absolute; left: 0; @@ -114,11 +107,11 @@ transition: all 0.3s ease; } - .modern-checkbox input[type="checkbox"]:checked + label:before { + .custom-checkbox input[type="checkbox"]:checked + label:before { background-color: #4caf50; } - .modern-checkbox label:after { + .custom-checkbox label:after { content: "\2714"; position: absolute; top: 0; @@ -129,7 +122,7 @@ opacity: 0; } - .modern-checkbox input[type="checkbox"]:checked + label:after { + .custom-checkbox input[type="checkbox"]:checked + label:after { opacity: 1; } @@ -143,19 +136,9 @@

Gopeed Settings

-
-
- - -
-
- - -
+
+ +
diff --git a/public/popup.js b/public/popup.js index bb27060..c478e9d 100644 --- a/public/popup.js +++ b/public/popup.js @@ -1,13 +1,7 @@ document.addEventListener('DOMContentLoaded', function () { const saveButton = document.getElementById('saveButton'); const successMessage = document.getElementById('successMessage'); - chrome.storage.local.get(['enableNotification', 'enabled'], function (result) { - if (result.enableNotification === undefined) { - chrome.storage.local.set({ enableNotification: true }); - document.getElementById('enableNotification').checked = true; - } else { - document.getElementById('enableNotification').checked = result.enableNotification; - } + chrome.storage.local.get(['enabled'], function (result) { if (result.enabled === undefined) { chrome.storage.local.set({ enabled: true }); document.getElementById('enabled').checked = true; @@ -18,9 +12,8 @@ document.addEventListener('DOMContentLoaded', function () { saveButton.addEventListener('click', function () { const host = document.getElementById('host').value; const token = document.getElementById('token').value; - const enableNotification = document.getElementById('enableNotification').checked; const enabled = document.getElementById('enabled').checked; - chrome.storage.local.set({ host: host, token: token, enableNotification: enableNotification, enabled: enabled }, function () { + chrome.storage.local.set({ host: host, token: token, enabled: enabled }, function () { successMessage.style.display = 'block'; setTimeout(function () { successMessage.style.opacity = '1'; diff --git a/src/background.js b/src/background.js index 0730442..b0bca1e 100644 --- a/src/background.js +++ b/src/background.js @@ -5,7 +5,6 @@ import { Client } from "../node_modules/@gopeed/rest"; const Settings = { host: 'http://localhost:39666', token: 'qwqowo', - enableNotification: true, enabled: true, } @@ -19,25 +18,6 @@ const initStorage = chrome.storage.local.get().then((items) => { }); }); -const sendSuccessNotification = (message) => { - chrome.notifications.create({ - type: 'basic', - iconUrl: "icons/icon_48.png", - title: '已创建下载任务', - message: message, - }); -} - -const sendErrorNotification = (message) => { - chrome.notifications.create({ - type: 'basic', - iconUrl: "icons/icon_48.png", - title: '创建下载任务失败', - message: message, - }); -} - - chrome.storage.onChanged.addListener((changes) => { if (changes.host) { Settings.host = changes.host.newValue; @@ -45,9 +25,6 @@ chrome.storage.onChanged.addListener((changes) => { if (changes.token) { Settings.token = changes.token.newValue; } - if (changes.enableNotification) { - Settings.enableNotification = changes.enableNotification.newValue; - } if (changes.enabled) { Settings.enabled = changes.enabled.newValue; } @@ -57,8 +34,12 @@ chrome.storage.onChanged.addListener((changes) => { }); }); +const INFOCOLOR = '#6699FF'; +const ERRORCOLOR = '#FF3366'; + chrome.downloads.onDeterminingFilename.addListener(async function (item) { - if (item.mime === "application/octet-stream") { + console.log(item); + if (item.mime === "application/octet-stream" && item.finalUrl.startsWith("blob:")) { return; } await initStorage; @@ -81,11 +62,21 @@ chrome.downloads.onDeterminingFilename.addListener(async function (item) { name: item.filename, } }); - if (Settings.enableNotification) { - sendSuccessNotification('文件大小: ' + (item.fileSize / (1024 * 1024)).toFixed(2) + 'MB'); - } + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + chrome.tabs.sendMessage(tabs[0].id, { + action: 'showNotification', + message: `正在下载: ${item.filename}, 文件大小: ${(item.fileSize / (1024 * 1024)).toFixed(2)}MB`, + }) + }); } catch (error) { - sendErrorNotification('错误信息: ' + error.message); + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + chrome.tabs.sendMessage(tabs[0].id, { + action: 'showNotification', + message: `下载${item.filename}失败: ${error.message}`, + color: ERRORCOLOR, + timeout: 4000, + }) + }); } }); @@ -98,22 +89,26 @@ chrome.contextMenus.create({ chrome.contextMenus.onClicked.addListener(async function (info, tab) { await initStorage; + + let downloadUrl = info.linkUrl || info.srcUrl || info.frameUrl; + if (info.mediaType) { + downloadUrl = info.frameUrl || downloadUrl; + } + if (!downloadUrl) { + chrome.tabs.sendMessage(tab.id, { + action: 'showNotification', + message: '下载失败, 无法获取下载链接', + color: ERRORCOLOR, + }) + return; + } + chrome.tabs.sendMessage(tab.id, { + action: 'showNotification', + message: '正在获取下载链接...', + color: INFOCOLOR, + timeout: 1500, + }) try { - let downloadUrl = info.linkUrl || info.srcUrl || info.frameUrl; - if (info.mediaType) { - downloadUrl = info.frameUrl || downloadUrl; - } - if (!downloadUrl) { - chrome.notifications.create({ - type: 'basic', - iconUrl: "icons/icon_48.png", - title: '创建下载任务失败', - message: '无法获取下载链接', - }); - } - chrome.action.setBadgeText({ - text: '🔗', - }); const resolveResult = await client.resolve({ url: downloadUrl, extra: { @@ -128,13 +123,16 @@ chrome.contextMenus.onClicked.addListener(async function (info, tab) { name: resolveResult.res.files[0].name } }) - chrome.action.setBadgeText({ - text: '', - }); - if (Settings.enableNotification) { - sendSuccessNotification('文件大小: ' + (resolveResult.res.files[0].size / (1024 * 1024)).toFixed(2) + 'MB'); - } + chrome.tabs.sendMessage(tab.id, { + action: 'showNotification', + message: `正在下载: ${resolveResult.res.files[0].name}, 文件大小: ${(resolveResult.res.files[0].size / (1024 * 1024)).toFixed(2)}MB`, + }) } catch (error) { - sendErrorNotification('错误信息: ' + error.message); + chrome.tabs.sendMessage(tab.id, { + action: 'showNotification', + message: `下载${downloadUrl}失败: ${error.message}`, + color: ERRORCOLOR, + timeout: 4000, + }) } }); \ No newline at end of file diff --git a/src/content.js b/src/content.js new file mode 100644 index 0000000..e6e769d --- /dev/null +++ b/src/content.js @@ -0,0 +1,88 @@ +const notificationContainer = document.createElement('div'); +notificationContainer.style.cssText = ` + position: fixed; + bottom: 30px; + right: 30px; + z-index: 999999; +`; +document.body.appendChild(notificationContainer); + +let notificationCount = 0; +const maxNotifications = 5; + +function createNotification(message, color) { + const notification = document.createElement('div'); + notification.style.cssText = ` + padding: 12px 24px; + color: #fff; + border-radius: 10px; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); + transition: all 0.3s ease; + opacity: 0; + transform: translateY(20px); + font-family: Arial, sans-serif; + min-width: 250px; + max-width: 400px; + margin-top: 10px; + `; + notification.style.background = color || '#4CAF50'; + const title = document.createElement('div'); + title.textContent = 'Gopeed Extension'; + title.style.cssText = ` + font-size: 12px; + font-weight: normal; + opacity: 0.8; + margin-bottom: 8px; + text-transform: uppercase; + letter-spacing: 0.5px; + `; + + const content = document.createElement('div'); + content.textContent = message; + content.style.cssText = ` + font-size: 16px; + font-weight: bold; + `; + + notification.appendChild(title); + notification.appendChild(content); + return notification; +} + +function showNotification(message, color, timeout) { + const notification = createNotification(message, color); + notificationContainer.insertBefore(notification, notificationContainer.firstChild); + notificationCount++; + + while (notificationContainer.children.length > maxNotifications) { + notificationContainer.removeChild(notificationContainer.lastChild); + notificationCount--; + } + + Array.from(notificationContainer.children).forEach((notif, index) => { + notif.style.transform = `translateY(${(notificationCount - index - 1) * 100}%)`; + }); + + setTimeout(() => { + notification.style.opacity = '1'; + notification.style.transform = 'translateY(0)'; + }, 10); + + setTimeout(() => { + notification.style.opacity = '0'; + notification.style.transform = 'translateY(20px)'; + setTimeout(() => { + notificationContainer.removeChild(notification); + notificationCount--; + Array.from(notificationContainer.children).forEach((notif, index) => { + notif.style.transform = `translateY(${(notificationCount - index - 1) * 100}%)`; + }); + }, 300); + }, timeout || 3000); +} + +chrome.runtime.onMessage.addListener(function (message, _sender, _sendResponse) { + if (message.action === 'showNotification') { + showNotification(message.message, message.color, message.timeout); + } +}); \ No newline at end of file