From 3c3e7cd64ca0d32c45c8216aa9df6d5943505a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=8C=E8=90=8C=E5=93=92=E8=B5=AB=E8=90=9D?= Date: Mon, 10 Apr 2023 16:06:37 +0800 Subject: [PATCH] :sparkles: Feature: automatically upload when clipboard changes ISSUES CLOSED: #35 --- package.json | 1 + public/i18n/en.yml | 4 +- public/i18n/zh-CN.yml | 5 +- public/i18n/zh-TW.yml | 5 +- src/main/apis/app/system/index.ts | 131 ++++++++++++++++++++++---- src/main/apis/app/uploader/apis.ts | 2 +- src/main/lifeCycle/index.ts | 36 +++---- src/renderer/pages/PicGoSetting.vue | 26 ++++- src/universal/types/i18n.d.ts | 3 + src/universal/types/shims-module.d.ts | 1 + src/universal/types/view.d.ts | 3 +- yarn.lock | 5 + 12 files changed, 173 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index cddf34d..4874251 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "ali-oss": "^6.17.1", "aws-sdk": "^2.1320.0", "axios": "^1.3.4", + "clipboard-event": "^1.6.0", "compare-versions": "^4.1.3", "core-js": "^3.27.1", "cos-nodejs-sdk-v5": "^2.11.19", diff --git a/public/i18n/en.yml b/public/i18n/en.yml index d25bd7f..cca3863 100644 --- a/public/i18n/en.yml +++ b/public/i18n/en.yml @@ -25,6 +25,8 @@ FIND_NEW_VERSION: Find New Version NO_MORE_NOTICE: No More Notice SHOW_DEVTOOLS: Show Devtools CURRENT_PICBED: Current Picbed +START_WATCH_CLIPBOARD: Start Watch Clipboard +STOP_WATCH_CLIPBOARD: Stop Watch Clipboard # ---renderer i18n begin--- @@ -192,7 +194,7 @@ SETTINGS_SYNC_DELETE_CLOUD: Sync delete from cloud storage of gallery SETTINGS_ISHIDEDOCK: Hide Dock Icon SETTINGS_ISHIDEDOCK_TIPS: Not support hide dock and tray at the same time SETTINGS_ENCODE_OUTPUT_URL: Encode Output(or Copyed) URL - +SETTINGS_WATCH_CLIPBOARD: Watch clipboard when software start # shortcut-page BUILTIN_CLIPBOARD_TIPS: Use builtin clipboard function to upload instead of using scripts diff --git a/public/i18n/zh-CN.yml b/public/i18n/zh-CN.yml index 18f1f05..0650d94 100644 --- a/public/i18n/zh-CN.yml +++ b/public/i18n/zh-CN.yml @@ -25,7 +25,8 @@ FIND_NEW_VERSION: 发现新版本 NO_MORE_NOTICE: 以后不再提醒 SHOW_DEVTOOLS: 打开开发者工具 CURRENT_PICBED: 当前图床 - +START_WATCH_CLIPBOARD: 开始监听剪贴板 +STOP_WATCH_CLIPBOARD: 停止监听剪贴板 # ---renderer i18n begin--- CHOOSE_YOUR_DEFAULT_PICBED: 选择 ${d} 作为你默认图床: @@ -193,7 +194,7 @@ SETTINGS_SYNC_DELETE_CLOUD: 相册内删除时同步删除云端文件 SETTINGS_ISHIDEDOCK: 是否隐藏dock图标 SETTINGS_ISHIDEDOCK_TIPS: 不支持同时隐藏dock和托盘 SETTINGS_ENCODE_OUTPUT_URL: 输出(复制) URL 时进行转义 - +SETTINGS_WATCH_CLIPBOARD: 软件启动时自动监听剪贴板上传 # shortcut-page SHORTCUT_NAME: 快捷键名称 diff --git a/public/i18n/zh-TW.yml b/public/i18n/zh-TW.yml index 4f364d0..42e5bc2 100644 --- a/public/i18n/zh-TW.yml +++ b/public/i18n/zh-TW.yml @@ -25,7 +25,8 @@ FIND_NEW_VERSION: 發現新版本 NO_MORE_NOTICE: 以後不再提醒 SHOW_DEVTOOLS: 開啟開發者工具 CURRENT_PICBED: 當前圖床 - +START_WATCH_CLIPBOARD: 開始監聽剪貼簿 +STOP_WATCH_CLIPBOARD: 停止監聽剪貼簿 # ---renderer i18n begin--- CHOOSE_YOUR_DEFAULT_PICBED: 選擇 ${d} 作為你的預設圖床: @@ -193,7 +194,7 @@ SETTINGS_SYNC_DELETE_CLOUD: 從相簿中刪除並同步從雲端刪除 SETTINGS_ISHIDEDOCK: 是否隱藏dock圖示 SETTINGS_ISHIDEDOCK_TIPS: 不支持同時隱藏dock和托盘 SETTINGS_ENCODE_OUTPUT_URL: 輸出(複製) URL 時進行轉義 - +SETTINGS_WATCH_CLIPBOARD: 軟體啟動時自動監聽剪貼簿上傳 # shortcut-page SHORTCUT_NAME: 快捷鍵名稱 diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts index 1c04212..bf8c656 100644 --- a/src/main/apis/app/system/index.ts +++ b/src/main/apis/app/system/index.ts @@ -19,25 +19,59 @@ import { ensureFilePath, handleCopyUrl } from '~/main/utils/common' import { T } from '~/main/i18n' import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion' import { buildPicBedListMenu } from '~/main/events/remotes/menu' +import clipboardListener from 'clipboard-event' +import picgo from '../../core/picgo' +import { uploadClipboardFiles } from '../uploader/apis' let contextMenu: Menu | null let tray: Tray | null +export function setDockMenu () { + const isListeningClipboard = db.get('settings.isListeningClipboard') || false + const dockMenu = Menu.buildFromTemplate([ + { + label: T('OPEN_MAIN_WINDOW'), + click () { + const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) + settingWindow!.show() + settingWindow!.focus() + if (windowManager.has(IWindowList.MINI_WINDOW)) { + windowManager.get(IWindowList.MINI_WINDOW)!.hide() + } + } + }, + { + label: T('START_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', true) + clipboardListener.startListening() + clipboardListener.on('change', () => { + picgo.log.info('clipboard changed') + uploadClipboardFiles() + }) + setDockMenu() + }, + enabled: !isListeningClipboard + }, + { + label: T('STOP_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', false) + clipboardListener.stopListening() + setDockMenu() + }, + enabled: isListeningClipboard + } + ]) + app.dock.setMenu(dockMenu) +} + export function createMenu () { const submenu = buildPicBedListMenu() + const isListeningClipboard = db.get('settings.isListeningClipboard') || false const appMenu = Menu.buildFromTemplate([ { label: 'PicList', submenu: [ - { - label: T('ABOUT'), - click () { - dialog.showMessageBox({ - title: 'PicList', - message: 'PicList', - detail: `Version: ${pkg.version}\nAuthor: Kuingsmile\nGithub: https://github.com/Kuingsmile/PicList` - }) - } - }, { label: T('OPEN_MAIN_WINDOW'), click () { @@ -49,6 +83,28 @@ export function createMenu () { } } }, + { + label: T('START_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', true) + clipboardListener.startListening() + clipboardListener.on('change', () => { + picgo.log.info('clipboard changed') + uploadClipboardFiles() + }) + createMenu() + }, + enabled: !isListeningClipboard + }, + { + label: T('STOP_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', false) + clipboardListener.stopListening() + createMenu() + }, + enabled: isListeningClipboard + }, { label: T('RELOAD_APP'), click () { @@ -78,19 +134,10 @@ export function createMenu () { } export function createContextMenu () { + const isListeningClipboard = db.get('settings.isListeningClipboard') || false if (process.platform === 'darwin' || process.platform === 'win32') { const submenu = buildPicBedListMenu() const template = [ - { - label: T('ABOUT'), - click () { - dialog.showMessageBox({ - title: 'PicList', - message: 'PicList', - detail: `Version: ${pkg.version}\nAuthor: Kuingsmile\nGithub: https://github.com/Kuingsmile/PicList` - }) - } - }, { label: T('OPEN_MAIN_WINDOW'), click () { @@ -108,6 +155,28 @@ export function createContextMenu () { // @ts-ignore submenu }, + { + label: T('START_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', true) + clipboardListener.startListening() + clipboardListener.on('change', () => { + picgo.log.info('clipboard changed') + uploadClipboardFiles() + }) + createContextMenu() + }, + enabled: !isListeningClipboard + }, + { + label: T('STOP_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', false) + clipboardListener.stopListening() + createContextMenu() + }, + enabled: isListeningClipboard + }, { label: T('RELOAD_APP'), click () { @@ -200,6 +269,28 @@ export function createContextMenu () { miniWindow.focus() } }, + { + label: T('START_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', true) + clipboardListener.startListening() + clipboardListener.on('change', () => { + picgo.log.info('clipboard changed') + uploadClipboardFiles() + }) + createContextMenu() + }, + enabled: !isListeningClipboard + }, + { + label: T('STOP_WATCH_CLIPBOARD'), + click () { + db.set('settings.isListeningClipboard', false) + clipboardListener.stopListening() + createContextMenu() + }, + enabled: isListeningClipboard + }, { label: T('ABOUT'), click () { diff --git a/src/main/apis/app/uploader/apis.ts b/src/main/apis/app/uploader/apis.ts index 85d973c..7812287 100644 --- a/src/main/apis/app/uploader/apis.ts +++ b/src/main/apis/app/uploader/apis.ts @@ -15,7 +15,7 @@ import picgo from '@core/picgo' import GuiApi from '../../gui' const handleClipboardUploading = async (): Promise => { - const useBuiltinClipboard = !!db.get('settings.useBuiltinClipboard') + const useBuiltinClipboard = db.get('settings.useBuiltinClipboard') === undefined ? true : !!db.get('settings.useBuiltinClipboard') const win = windowManager.getAvailableWindow() if (useBuiltinClipboard) { return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard() diff --git a/src/main/lifeCycle/index.ts b/src/main/lifeCycle/index.ts index 7544622..fc1d694 100644 --- a/src/main/lifeCycle/index.ts +++ b/src/main/lifeCycle/index.ts @@ -4,7 +4,6 @@ import { globalShortcut, protocol, Notification, - Menu, dialog, screen } from 'electron' @@ -26,7 +25,7 @@ import { uploadClipboardFiles } from 'apis/app/uploader/apis' import { - createTray + createTray, setDockMenu } from 'apis/app/system' import server from '~/main/server/index' import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler' @@ -45,6 +44,10 @@ import UpDownTaskQueue from '../manage/datastore/upDownTaskQueue' import { T } from '~/main/i18n' import { UpdateInfo, autoUpdater } from 'electron-updater' import updateChecker from '../utils/updateChecker' +import clipboardListener from 'clipboard-event' +import path from 'path' +import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static' +import fs from 'fs-extra' const isDevelopment = process.env.NODE_ENV !== 'production' const handleStartUpFiles = (argv: string[], cwd: string) => { @@ -138,21 +141,7 @@ class LifeCycle { windowManager.create(IWindowList.TRAY_WINDOW) windowManager.create(IWindowList.SETTING_WINDOW) if (process.platform === 'darwin') { - app.dock.setMenu( - Menu.buildFromTemplate([ - { - label: T('OPEN_MAIN_WINDOW'), - click () { - const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) - settingWindow!.show() - settingWindow!.focus() - if (windowManager.has(IWindowList.MINI_WINDOW)) { - windowManager.get(IWindowList.MINI_WINDOW)!.hide() - } - } - } - ]) - ) + setDockMenu() } const startMode = db.get('settings.startMode') || 'quiet' if (startMode !== 'no-tray' && process.platform === 'darwin') { @@ -213,6 +202,19 @@ class LifeCycle { settingWindow.show() settingWindow.focus() } + const isAutoListenClipboard = db.get('settings.isAutoListenClipboard') || false + if (isAutoListenClipboard) { + db.set('settings.isListeningClipboard', true) + clipboardListener.startListening() + clipboardListener.on('change', () => { + picgo.log.info('clipboard changed') + uploadClipboardFiles() + }) + } else { + db.set('settings.isListeningClipboard', false) + } + const clipboardDir = path.join(picgo.baseDir, CLIPBOARD_IMAGE_FOLDER) + fs.ensureDir(clipboardDir) } app.whenReady().then(readyFunction) } diff --git a/src/renderer/pages/PicGoSetting.vue b/src/renderer/pages/PicGoSetting.vue index 95b7b16..443f22c 100644 --- a/src/renderer/pages/PicGoSetting.vue +++ b/src/renderer/pages/PicGoSetting.vue @@ -345,6 +345,16 @@ @change="handleEncodeOutputURL" /> + + + vo } const $router = useRouter() const form = reactive({ - updateHelper: false, + updateHelper: true, showPicBedList: [], autoStart: false, rename: false, @@ -1044,14 +1054,15 @@ const form = reactive({ logLevel: ['all'], autoCopyUrl: true, checkBetaUpdate: true, - useBuiltinClipboard: false, + useBuiltinClipboard: true, language: 'zh-CN', logFileSizeLimit: 10, deleteCloudFile: false, isCustomMiniIcon: false, customMiniIcon: '', isHideDock: false, - encodeOutputURL: true + encodeOutputURL: true, + isAutoListenClipboard: false }) const languageList = i18nManager.languageList.map(item => ({ @@ -1132,7 +1143,7 @@ async function initData () { if (config !== undefined) { const settings = config.settings || {} const picBed = config.picBed - form.updateHelper = settings.showUpdateTip || false + form.updateHelper = settings.showUpdateTip === undefined ? true : settings.showUpdateTip form.autoStart = settings.autoStart || false form.rename = settings.rename || false form.autoRename = settings.autoRename || false @@ -1141,7 +1152,8 @@ async function initData () { form.logLevel = initLogLevel(settings.logLevel || []) form.autoCopyUrl = settings.autoCopy === undefined ? true : settings.autoCopy form.checkBetaUpdate = settings.checkBetaUpdate === undefined ? true : settings.checkBetaUpdate - form.useBuiltinClipboard = settings.useBuiltinClipboard === undefined ? false : settings.useBuiltinClipboard + form.useBuiltinClipboard = settings.useBuiltinClipboard === undefined ? true : settings.useBuiltinClipboard + form.isAutoListenClipboard = settings.isAutoListenClipboard || false form.language = settings.language ?? 'zh-CN' form.encodeOutputURL = settings.encodeOutputURL === undefined ? true : settings.encodeOutputURL form.deleteCloudFile = settings.deleteCloudFile || false @@ -1277,6 +1289,10 @@ function useBuiltinClipboardChange (val: ICheckBoxValueType) { saveConfig('settings.useBuiltinClipboard', val) } +function handleIsAutoListenClipboard (val: ICheckBoxValueType) { + saveConfig('settings.isAutoListenClipboard', val) +} + function handleShowPicBedListChange (val: ICheckBoxValueType[]) { const list = picBed.value.map(item => { if (!val.includes(item.name)) { diff --git a/src/universal/types/i18n.d.ts b/src/universal/types/i18n.d.ts index 1c88e2d..f6795bb 100644 --- a/src/universal/types/i18n.d.ts +++ b/src/universal/types/i18n.d.ts @@ -26,6 +26,8 @@ interface ILocales { NO_MORE_NOTICE: string SHOW_DEVTOOLS: string CURRENT_PICBED: string + START_WATCH_CLIPBOARD: string + STOP_WATCH_CLIPBOARD: string CHOOSE_YOUR_DEFAULT_PICBED: string UPLOAD_AREA: string UPLOAD_VIEW_HINT: string @@ -187,6 +189,7 @@ interface ILocales { SETTINGS_ISHIDEDOCK: string SETTINGS_ISHIDEDOCK_TIPS: string SETTINGS_ENCODE_OUTPUT_URL: string + SETTINGS_WATCH_CLIPBOARD: string SHORTCUT_NAME: string SHORTCUT_BIND: string SHORTCUT_STATUS: string diff --git a/src/universal/types/shims-module.d.ts b/src/universal/types/shims-module.d.ts index 6f68334..0be1f4b 100644 --- a/src/universal/types/shims-module.d.ts +++ b/src/universal/types/shims-module.d.ts @@ -8,3 +8,4 @@ declare module '*.vue' { // function fixPath(): void // export default fixPath // } +declare module 'clipboard-event' diff --git a/src/universal/types/view.d.ts b/src/universal/types/view.d.ts index 0ba96c3..58feca1 100644 --- a/src/universal/types/view.d.ts +++ b/src/universal/types/view.d.ts @@ -16,7 +16,8 @@ interface ISettingForm { isCustomMiniIcon: boolean, customMiniIcon: string, isHideDock: boolean, - encodeOutputURL: boolean + encodeOutputURL: boolean, + isAutoListenClipboard: boolean } interface IShortKeyMap { diff --git a/yarn.lock b/yarn.lock index fbcf632..26f6f92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5297,6 +5297,11 @@ cli-width@^2.0.0: resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== +clipboard-event@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/clipboard-event/-/clipboard-event-1.6.0.tgz#2cd6c6d469b635e3d9be73e2d0cc554cdf17f3d5" + integrity sha512-a69QYimd43xM+5hcHkucs0V/QoiZz1fqEFRTnewOITVQOtypRLbCx76Q91Djn6h7O24817dQw44sFUxRYWIuYA== + clipboardy@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290"