diff --git a/package.json b/package.json
index 50ffb7c3..da0cd34e 100644
--- a/package.json
+++ b/package.json
@@ -60,7 +60,6 @@
"got": "^12.6.0",
"highlight.js": "^11.9.0",
"hpagent": "^1.2.0",
- "keycode": "^2.2.0",
"lowdb": "^1.0.0",
"marked": "^9.1.5",
"mime-types": "^2.1.35",
diff --git a/public/i18n/en.yml b/public/i18n/en.yml
index 45e5f579..e7ba04d2 100644
--- a/public/i18n/en.yml
+++ b/public/i18n/en.yml
@@ -2,6 +2,7 @@ LANG_DISPLAY_LABEL: 'English'
ABOUT: About
OPEN_MAIN_WINDOW: Open Main Window
OPEN_MINI_WINDOW: Open Mini Window
+HIDE_MINI_WINDOW: Hide Mini Window
CHOOSE_DEFAULT_PICBED: Choose Default Picbed
OPEN_UPDATE_HELPER: Open Update Helper
RELOAD_APP: Reload App
@@ -311,7 +312,7 @@ SETTINGS_SYNC_MANAGE_CONFIG: Manage configuration
SETTINGS_AUTO_IMPORT: Auto import config in manage page
SETTINGS_AUTO_IMPORT_SELECT_PICBED: Select picbed
SETTINGS_TAB_SYSTEM: System
-SETTINGS_TAB_SYNC_CONFIG: Sync and Configuration
+SETTINGS_TAB_SYNC_CONFIG: Configuration
SETTINGS_TAB_UPLOAD: Upload
SETTINGS_TAB_ADVANCED: Advanced
SETTINGS_TAB_UPDATE: Update
diff --git a/public/i18n/zh-CN.yml b/public/i18n/zh-CN.yml
index 9e7d199d..0ca38feb 100644
--- a/public/i18n/zh-CN.yml
+++ b/public/i18n/zh-CN.yml
@@ -2,6 +2,7 @@ LANG_DISPLAY_LABEL: 中文
ABOUT: 关于
OPEN_MAIN_WINDOW: 打开主窗口
OPEN_MINI_WINDOW: 打开mini窗口
+HIDE_MINI_WINDOW: 隐藏mini窗口
CHOOSE_DEFAULT_PICBED: 选择默认图床
OPEN_UPDATE_HELPER: 打开更新助手
RELOAD_APP: 重启应用
diff --git a/public/i18n/zh-TW.yml b/public/i18n/zh-TW.yml
index 1adf2790..83793d0a 100644
--- a/public/i18n/zh-TW.yml
+++ b/public/i18n/zh-TW.yml
@@ -2,6 +2,7 @@ LANG_DISPLAY_LABEL: 繁體中文
ABOUT: 關於
OPEN_MAIN_WINDOW: 打開主視窗
OPEN_MINI_WINDOW: 打開mini視窗
+HIDE_MINI_WINDOW: 隱藏mini視窗
CHOOSE_DEFAULT_PICBED: 選擇預設圖床
OPEN_UPDATE_HELPER: 開啟更新助手
RELOAD_APP: 重啟程式
diff --git a/src/main.ts b/src/main.ts
index 1ec9f80f..4fc3204f 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -19,10 +19,9 @@ import db from '@/utils/db'
import { T } from '@/i18n/index'
import { store } from '@/store'
import { initTalkingData } from '@/utils/analytic'
-import { getConfig, saveConfig, triggerRPC } from '@/utils/dataSender'
import { mainMixin } from '@/utils/mainMixin'
import { dragMixin } from '@/utils/mixin'
-import { sendToMain } from '@/utils/common'
+import { sendRPC, sendToMain, triggerRPC } from '@/utils/common'
webFrame.setVisualZoomLevelLimits(1, 1)
@@ -30,16 +29,14 @@ const app = createApp(App)
app.config.globalProperties.$$db = db
app.config.globalProperties.$T = T
-app.config.globalProperties.getConfig = getConfig
app.config.globalProperties.triggerRPC = triggerRPC
-app.config.globalProperties.saveConfig = saveConfig
+app.config.globalProperties.sendRPC = sendRPC
app.config.globalProperties.sendToMain = sendToMain
app.mixin(mainMixin)
app.mixin(dragMixin)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
-
app.use(VueLazyLoad, {
error: `file://${__static.replace(/\\/g, '/')}/unknown-file-type.svg`
})
@@ -52,5 +49,4 @@ console.log(hljsCommon.highlightAuto('
Highlight.js has been registered succe
app.use(hljsVuePlugin)
app.use(VueVideoPlayer)
app.mount('#app')
-
initTalkingData()
diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts
index 31a564b1..f315bac6 100644
--- a/src/main/apis/app/system/index.ts
+++ b/src/main/apis/app/system/index.ts
@@ -3,9 +3,10 @@ import {
clipboard,
dialog,
Menu,
+ MenuItem,
+ MenuItemConstructorOptions,
nativeTheme,
Notification,
- screen,
Tray
} from 'electron'
import fs from 'fs-extra'
@@ -29,23 +30,16 @@ import { configPaths } from '#/utils/configPaths'
import { IPasteStyle, IWindowList } from '#/types/enum'
import pkg from 'root/package.json'
+import { hideMiniWindow, openMainWindow, openMiniWindow } from '~/utils/windowHelper'
let contextMenu: Menu | null
export function setDockMenu () {
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
- const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || 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) && autoCloseMiniWindow) {
- windowManager.get(IWindowList.MINI_WINDOW)!.hide()
- }
- }
+ click: openMainWindow
},
{
label: T('START_WATCH_CLIPBOARD'),
@@ -58,7 +52,7 @@ export function setDockMenu () {
})
setDockMenu()
},
- enabled: !isListeningClipboard
+ visible: !isListeningClipboard
},
{
label: T('STOP_WATCH_CLIPBOARD'),
@@ -68,7 +62,7 @@ export function setDockMenu () {
clipboardPoll.removeAllListeners()
setDockMenu()
},
- enabled: isListeningClipboard
+ visible: isListeningClipboard
}
])
app.dock.setMenu(dockMenu)
@@ -80,59 +74,27 @@ export function createMenu () {
{
label: 'PicList',
submenu: [
- {
- label: T('OPEN_MAIN_WINDOW'),
- click () {
- const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
- const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
- settingWindow!.show()
- settingWindow!.focus()
- if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
- windowManager.get(IWindowList.MINI_WINDOW)!.hide()
- }
- }
- },
- {
- label: T('RELOAD_APP'),
- click () {
- app.relaunch()
- app.exit(0)
- }
- }
+ { label: T('OPEN_MAIN_WINDOW'), click: openMainWindow },
+ { label: T('RELOAD_APP'), click () { app.relaunch(); app.exit(0) } }
]
},
- {
- label: T('CHOOSE_DEFAULT_PICBED'),
- type: 'submenu',
- // @ts-ignore
- submenu
- },
+ { label: T('CHOOSE_DEFAULT_PICBED'), type: 'submenu', submenu },
{
label: 'Edit',
- // @ts-ignore
submenu: [
- // @ts-ignore
- { label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
- // @ts-ignore
- { label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
+ { label: 'Undo', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
+ { label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' },
{ type: 'separator' },
- // @ts-ignore
- { label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
- // @ts-ignore
- { label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
- // @ts-ignore
- { label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
- // @ts-ignore
- { label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' }
+ { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' },
+ { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
+ { label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' },
+ { label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' }
]
},
{
label: T('QUIT'),
submenu: [
- {
- label: T('QUIT'),
- role: 'quit'
- }
+ { label: T('QUIT'), role: 'quit' }
]
}
])
@@ -142,94 +104,39 @@ export function createMenu () {
export function createContextMenu () {
const ClipboardWatcher = clipboardPoll
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
+ const isMiniWindowVisible = windowManager.has(IWindowList.MINI_WINDOW) && windowManager.get(IWindowList.MINI_WINDOW)!.isVisible()
+
+ const startWatchClipboard = () => {
+ db.set(configPaths.settings.isListeningClipboard, true)
+ ClipboardWatcher.startListening()
+ ClipboardWatcher.on('change', () => {
+ picgo.log.info('clipboard changed')
+ uploadClipboardFiles()
+ })
+ createContextMenu()
+ }
+
+ const stopWatchClipboard = () => {
+ db.set(configPaths.settings.isListeningClipboard, false)
+ ClipboardWatcher.stopListening()
+ ClipboardWatcher.removeAllListeners()
+ createContextMenu()
+ }
+
if (process.platform === 'darwin' || process.platform === 'win32') {
const submenu = buildPicBedListMenu()
- const template = [
- {
- label: T('OPEN_MAIN_WINDOW'),
- click () {
- const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
- const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
- settingWindow!.show()
- settingWindow!.focus()
- if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
- windowManager.get(IWindowList.MINI_WINDOW)!.hide()
- }
- }
- },
- {
- label: T('CHOOSE_DEFAULT_PICBED'),
- type: 'submenu',
- // @ts-ignore
- submenu
- },
- {
- label: T('START_WATCH_CLIPBOARD'),
- click () {
- db.set(configPaths.settings.isListeningClipboard, true)
- ClipboardWatcher.startListening()
- ClipboardWatcher.on('change', () => {
- picgo.log.info('clipboard changed')
- uploadClipboardFiles()
- })
- createContextMenu()
- },
- enabled: !isListeningClipboard
- },
- {
- label: T('STOP_WATCH_CLIPBOARD'),
- click () {
- db.set(configPaths.settings.isListeningClipboard, false)
- ClipboardWatcher.stopListening()
- ClipboardWatcher.removeAllListeners()
- createContextMenu()
- },
- enabled: isListeningClipboard
- },
- {
- label: T('RELOAD_APP'),
- click () {
- app.relaunch()
- app.exit(0)
- }
- },
- // @ts-ignore
- {
- role: 'quit',
- label: T('QUIT')
- }
- ] as any
+ const template: Array<(MenuItemConstructorOptions) | (MenuItem)> = [
+ { label: T('OPEN_MAIN_WINDOW'), click: openMainWindow },
+ { label: T('CHOOSE_DEFAULT_PICBED'), type: 'submenu', submenu },
+ { label: T('START_WATCH_CLIPBOARD'), click: startWatchClipboard, visible: !isListeningClipboard },
+ { label: T('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, visible: isListeningClipboard },
+ { label: T('RELOAD_APP'), click () { app.relaunch(); app.exit(0) } },
+ { label: T('QUIT'), role: 'quit' }
+ ]
if (process.platform === 'win32') {
template.splice(2, 0,
- {
- label: T('OPEN_MINI_WINDOW'),
- click () {
- const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
- miniWindow.removeAllListeners()
- if (db.get(configPaths.settings.miniWindowOntop)) {
- miniWindow.setAlwaysOnTop(true)
- }
- const { width, height } = screen.getPrimaryDisplay().workAreaSize
- const lastPosition = db.get(configPaths.settings.miniWindowPosition)
- if (lastPosition) {
- miniWindow.setPosition(lastPosition[0], lastPosition[1])
- } else {
- miniWindow.setPosition(width - 100, height - 100)
- }
- const setPositionFunc = () => {
- const position = miniWindow.getPosition()
- db.set(configPaths.settings.miniWindowPosition, position)
- }
- miniWindow.on('close', setPositionFunc)
- miniWindow.on('move', setPositionFunc)
- miniWindow.show()
- miniWindow.focus()
- const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
- if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
- windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
- }
- }
- }
+ { label: T('OPEN_MINI_WINDOW'), click () { openMiniWindow(false) }, visible: !isMiniWindowVisible },
+ { label: T('HIDE_MINI_WINDOW'), click: hideMiniWindow, visible: isMiniWindowVisible }
)
}
contextMenu = Menu.buildFromTemplate(template)
@@ -242,70 +149,11 @@ export function createContextMenu () {
// 目前的实现无法正常工作
contextMenu = Menu.buildFromTemplate([
- {
- label: T('OPEN_MAIN_WINDOW'),
- click () {
- const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
- const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
- settingWindow!.show()
- settingWindow!.focus()
- if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
- windowManager.get(IWindowList.MINI_WINDOW)!.hide()
- }
- }
- },
- {
- label: T('OPEN_MINI_WINDOW'),
- click () {
- const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
- miniWindow.removeAllListeners()
- if (db.get(configPaths.settings.miniWindowOntop)) {
- miniWindow.setAlwaysOnTop(true)
- }
- const { width, height } = screen.getPrimaryDisplay().workAreaSize
- const lastPosition = db.get(configPaths.settings.miniWindowPosition)
- if (lastPosition) {
- miniWindow.setPosition(lastPosition[0], lastPosition[1])
- } else {
- miniWindow.setPosition(width - 100, height - 100)
- }
- const setPositionFunc = () => {
- const position = miniWindow.getPosition()
- db.set(configPaths.settings.miniWindowPosition, position)
- }
- miniWindow.on('close', setPositionFunc)
- miniWindow.on('move', setPositionFunc)
- miniWindow.show()
- miniWindow.focus()
- const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
- if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
- windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
- }
- }
- },
- {
- label: T('START_WATCH_CLIPBOARD'),
- click () {
- db.set(configPaths.settings.isListeningClipboard, true)
- ClipboardWatcher.startListening()
- ClipboardWatcher.on('change', () => {
- picgo.log.info('clipboard changed')
- uploadClipboardFiles()
- })
- createContextMenu()
- },
- enabled: !isListeningClipboard
- },
- {
- label: T('STOP_WATCH_CLIPBOARD'),
- click () {
- db.set(configPaths.settings.isListeningClipboard, false)
- ClipboardWatcher.stopListening()
- ClipboardWatcher.removeAllListeners()
- createContextMenu()
- },
- enabled: isListeningClipboard
- },
+ { label: T('OPEN_MAIN_WINDOW'), click: openMainWindow },
+ { label: T('OPEN_MINI_WINDOW'), click () { openMiniWindow(false) }, visible: !isMiniWindowVisible },
+ { label: T('HIDE_MINI_WINDOW'), click: hideMiniWindow, visible: isMiniWindowVisible },
+ { label: T('START_WATCH_CLIPBOARD'), click: startWatchClipboard, visible: !isListeningClipboard },
+ { label: T('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, visible: isListeningClipboard },
{
label: T('ABOUT'),
click () {
@@ -317,11 +165,7 @@ export function createContextMenu () {
})
}
},
- // @ts-ignore
- {
- role: 'quit',
- label: T('QUIT')
- }
+ { label: T('QUIT'), role: 'quit' }
])
}
}
diff --git a/src/main/apis/app/uploader/apis.ts b/src/main/apis/app/uploader/apis.ts
index ee94f63c..d24f3cbc 100644
--- a/src/main/apis/app/uploader/apis.ts
+++ b/src/main/apis/app/uploader/apis.ts
@@ -4,26 +4,18 @@ import {
} from 'electron'
import fs from 'fs-extra'
import { cloneDeep } from 'lodash'
-import path from 'path'
-import { ISftpPlistConfig } from 'piclist'
import picgo from '@core/picgo'
import db, { GalleryDB } from '@core/datastore'
-import GuiApi from 'apis/gui'
import uploader from 'apis/app/uploader'
import windowManager from 'apis/app/window/windowManager'
import { T } from '~/i18n/index'
import { handleCopyUrl, handleUrlEncodeWithSetting } from '~/utils/common'
import pasteTemplate from '~/utils/pasteTemplate'
-import SSHClient from '~/utils/sshClient'
-
-import ALLApi from '@/apis/allApi'
-import { getRawData } from '@/utils/common'
import { IPasteStyle, IWindowList } from '#/types/enum'
-import { picBedsCanbeDeleted } from '#/utils/static'
import { configPaths } from '#/utils/configPaths'
const handleClipboardUploading = async (): Promise => {
@@ -129,62 +121,3 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
return []
}
}
-
-async function deleteSFTPFile (config: ISftpPlistConfig, fileName: string) {
- try {
- const client = SSHClient.instance
- await client.connect(config)
- const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/')
- const remote = path.join(uploadPath, fileName)
- const deleteResult = await client.deleteFileSFTP(config, remote)
- client.close()
- return deleteResult
- } catch (err: any) {
- picgo.log.error(err)
- return false
- }
-}
-
-export const deleteChoosedFiles = async (list: ImgInfo[]): Promise => {
- const result = []
- for (const item of list) {
- if (item.id) {
- try {
- const dbStore = GalleryDB.getInstance()
- const file = await dbStore.getById(item.id)
- await dbStore.removeById(item.id)
- if (await picgo.getConfig(configPaths.settings.deleteCloudFile)) {
- if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
- const noteFunc = (value: boolean) => {
- const notification = new Notification({
- title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
- body: T(value ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED' : 'GALLERY_SYNC_DELETE_NOTICE_FAILED')
- })
- notification.show()
- }
- if (item.type === 'sftpplist') {
- const { fileName, config } = item
- setTimeout(() => {
- deleteSFTPFile(getRawData(config), fileName || '').then(noteFunc)
- }, 0)
- } else {
- setTimeout(() => {
- ALLApi.delete(item).then(noteFunc)
- }, 0)
- }
- }
- }
- setTimeout(() => {
- picgo.emit('remove', [file], GuiApi.getInstance())
- }, 500)
- result.push(true)
- } catch (e) {
- result.push(false)
- }
- }
- }
- if (windowManager.has(IWindowList.SETTING_WINDOW)) {
- windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
- }
- return result
-}
diff --git a/src/main/apis/app/uploader/index.ts b/src/main/apis/app/uploader/index.ts
index 65f8ec8e..845c8448 100644
--- a/src/main/apis/app/uploader/index.ts
+++ b/src/main/apis/app/uploader/index.ts
@@ -6,7 +6,7 @@ import {
Notification,
WebContents
} from 'electron'
-import fse from 'fs-extra'
+import fs from 'fs-extra'
import util from 'util'
import path from 'path'
import { IPicGo } from 'piclist'
@@ -26,7 +26,7 @@ import {
RENAME_FILE_NAME,
TALKING_DATA_EVENT
} from '#/events/constants'
-import { IWindowList } from '#/types/enum'
+import { ICOREBuildInEvent, IWindowList } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import { CLIPBOARD_IMAGE_FOLDER } from '#/utils/static'
@@ -61,21 +61,22 @@ const handleTalkingData = (webContents: WebContents, options: IAnalyticsData) =>
class Uploader {
private webContents: WebContents | null = null
- // private uploading: boolean = false
+
constructor () {
this.init()
}
init () {
- picgo.on('notification', (message: Electron.NotificationConstructorOptions | undefined) => {
+ picgo.on(ICOREBuildInEvent.NOTIFICATION, (message: Electron.NotificationConstructorOptions | undefined) => {
const notification = new Notification(message)
notification.show()
})
- picgo.on('uploadProgress', (progress: any) => {
+ picgo.on(ICOREBuildInEvent.UPLOAD_PROGRESS, (progress: any) => {
this.webContents?.send('uploadProgress', progress)
})
- picgo.on('beforeTransform', () => {
+
+ picgo.on(ICOREBuildInEvent.BEFORE_TRANSFORM, () => {
if (db.get(configPaths.settings.uploadNotification)) {
const notification = new Notification({
title: T('UPLOAD_PROGRESS'),
@@ -84,6 +85,7 @@ class Uploader {
notification.show()
}
})
+
picgo.helper.beforeUploadPlugins.register('renameFn', {
handle: async (ctx: IPicGo) => {
const rename = db.get(configPaths.settings.rename)
@@ -150,7 +152,7 @@ class Uploader {
return false
} finally {
if (filePath) {
- fse.remove(filePath)
+ fs.remove(filePath)
}
}
}
diff --git a/src/main/apis/app/window/windowList.ts b/src/main/apis/app/window/windowList.ts
index 225d76e1..20a15b86 100644
--- a/src/main/apis/app/window/windowList.ts
+++ b/src/main/apis/app/window/windowList.ts
@@ -12,7 +12,6 @@ import {
import bus from '@core/bus'
import { CREATE_APP_MENU } from '@core/bus/constants'
import db from '@core/datastore'
-import picgo from '@core/picgo'
import { T } from '~/i18n'
@@ -25,16 +24,14 @@ const windowList = new Map()
const handleWindowParams = (windowURL: string) => windowURL
const getDefaultWindowSizes = (): { width: number, height: number } => {
- const mainWindowWidth = picgo.getConfig(configPaths.settings.mainWindowWidth)
- const mainWindowHeight = picgo.getConfig(configPaths.settings.mainWindowHeight)
+ const [mainWindowWidth, mainWindowHeight] = db.get([configPaths.settings.mainWindowWidth, configPaths.settings.mainWindowHeight])
return {
width: mainWindowWidth || 1200,
height: mainWindowHeight || 800
}
}
-const defaultWindowWidth = getDefaultWindowSizes().width
-const defaultWindowHeight = getDefaultWindowSizes().height
+const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes()
const trayWindowOptions = {
height: 350,
diff --git a/src/main/apis/app/window/windowManager.ts b/src/main/apis/app/window/windowManager.ts
index ea652f19..496ee50d 100644
--- a/src/main/apis/app/window/windowManager.ts
+++ b/src/main/apis/app/window/windowManager.ts
@@ -6,6 +6,7 @@ import { IWindowList } from '#/types/enum'
class WindowManager implements IWindowManager {
#windowMap: Map = new Map()
#windowIdMap: Map = new Map()
+
create (name: IWindowList) {
const windowConfig: IWindowListItem = windowList.get(name)!
if (windowConfig.isValid) {
diff --git a/src/main/apis/core/datastore/index.ts b/src/main/apis/core/datastore/index.ts
index 18bb6609..78888dfe 100644
--- a/src/main/apis/core/datastore/index.ts
+++ b/src/main/apis/core/datastore/index.ts
@@ -5,6 +5,8 @@ import { dbPathChecker, dbPathDir, getGalleryDBPath } from '@core/datastore/dbCh
import { T } from '~/i18n'
import { configPaths } from '#/utils/configPaths'
+import { IJSON } from '@picgo/store/dist/types'
+import { IConfig } from 'piclist'
const STORE_PATH = dbPathDir()
@@ -16,6 +18,7 @@ export const DB_PATH: string = getGalleryDBPath().dbPath
class ConfigStore {
#db: JSONStore
+
constructor () {
this.#db = new JSONStore(CONFIG_PATH)
@@ -40,34 +43,54 @@ class ConfigStore {
this.read()
}
- flush () {
- this.#db = new JSONStore(CONFIG_PATH)
+ read (flush?: boolean): IJSON {
+ return this.#db.read(flush)
}
- read () {
- this.#db.read()
- return this.#db
- }
-
- get (key = ''): any {
+ getSingle (key = ''): any {
if (key === '') {
- return this.#db.read()
+ return this.#db.read(true)
}
+ this.read(true)
return this.#db.get(key)
}
+ get (key: string): any
+ get (key: string[]): any[]
+ get (key: string | string[] = ''): any {
+ if (Array.isArray(key)) {
+ return key.map(k => this.getSingle(k))
+ }
+ return this.getSingle(key)
+ }
+
set (key: string, value: any): void {
+ this.read(true)
return this.#db.set(key, value)
}
has (key: string) {
+ this.read(true)
return this.#db.has(key)
}
unset (key: string, value: any): boolean {
+ this.read(true)
return this.#db.unset(key, value)
}
+ saveConfig (config: Partial): void {
+ Object.keys(config).forEach((name: string) => {
+ this.set(name, config[name])
+ })
+ }
+
+ removeConfig (config: IConfig): void {
+ Object.keys(config).forEach((name: string) => {
+ this.unset(name, config[name])
+ })
+ }
+
getConfigPath () {
return CONFIG_PATH
}
diff --git a/src/main/apis/core/picgo/index.ts b/src/main/apis/core/picgo/index.ts
index 8cda033c..92d61f5c 100644
--- a/src/main/apis/core/picgo/index.ts
+++ b/src/main/apis/core/picgo/index.ts
@@ -22,7 +22,7 @@ picgo.GUI_VERSION = global.PICGO_GUI_VERSION
const originPicGoSaveConfig = picgo.saveConfig.bind(picgo)
function flushDB () {
- db.flush()
+ db.read(true)
}
const debounced = debounce(flushDB, 1000)
diff --git a/src/main/apis/gui/index.ts b/src/main/apis/gui/index.ts
index f4a0c55e..4e995f0e 100644
--- a/src/main/apis/gui/index.ts
+++ b/src/main/apis/gui/index.ts
@@ -65,7 +65,7 @@ class GuiApi implements IGuiApi {
await this.showSettingWindow()
this.getWebcontentsByWindowId(this.settingWindowId)?.send(SHOW_INPUT_BOX, options)
return new Promise((resolve) => {
- ipcMain.once(SHOW_INPUT_BOX, (event: Event, value: string) => {
+ ipcMain.once(SHOW_INPUT_BOX, (_: Event, value: string) => {
resolve(value)
})
})
diff --git a/src/main/events/ipcList.ts b/src/main/events/ipcList.ts
deleted file mode 100644
index b7f11293..00000000
--- a/src/main/events/ipcList.ts
+++ /dev/null
@@ -1,388 +0,0 @@
-import {
- app,
- ipcMain,
- shell,
- Notification,
- IpcMainEvent,
- BrowserWindow,
- screen,
- IpcMainInvokeEvent
-} from 'electron'
-import fs from 'fs-extra'
-import path from 'path'
-import { ISftpPlistConfig } from 'piclist'
-
-import bus from '@core/bus'
-import logger from '@core/picgo/logger'
-import db, { GalleryDB } from '@core/datastore'
-
-import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
-import uploader from 'apis/app/uploader'
-import {
- uploadClipboardFiles,
- uploadChoosedFiles
-} from 'apis/app/uploader/apis'
-import windowManager from 'apis/app/window/windowManager'
-
-import { T } from '~/i18n'
-import server from '~/server'
-import picgoCoreIPC from '~/events/picgoCoreIPC'
-import { buildMainPageMenu, buildMiniPageMenu, buildPluginPageMenu, buildPicBedListMenu } from '~/events/remotes/menu'
-import { handleCopyUrl, generateShortUrl, setTrayToolTip } from '~/utils/common'
-import { removeFileFromS3InMain, removeFileFromDogeInMain, removeFileFromHuaweiInMain } from '~/utils/deleteFunc'
-import getPicBeds from '~/utils/getPicBeds'
-import pasteTemplate from '~/utils/pasteTemplate'
-import SSHClient from '~/utils/sshClient'
-import { uploadFile, downloadFile } from '~/utils/syncSettings'
-import webServer from '~/server/webServer'
-
-import {
- TOGGLE_SHORTKEY_MODIFIED_MODE,
- OPEN_DEVTOOLS,
- SHOW_MINI_PAGE_MENU,
- MINIMIZE_WINDOW,
- CLOSE_WINDOW,
- SHOW_MAIN_PAGE_MENU,
- SHOW_UPLOAD_PAGE_MENU,
- OPEN_USER_STORE_FILE,
- OPEN_URL,
- RELOAD_APP,
- SHOW_PLUGIN_PAGE_MENU,
- SET_MINI_WINDOW_POS,
- GET_PICBEDS,
- HIDE_DOCK
-} from '#/events/constants'
-import { configPaths } from '#/utils/configPaths'
-import { ILogType, IPasteStyle, IWindowList } from '#/types/enum'
-
-const STORE_PATH = app.getPath('userData')
-const commonConfigList = ['data.json', 'data.bak.json']
-const manageConfigList = ['manage.json', 'manage.bak.json']
-
-export default {
- listen () {
- picgoCoreIPC.listen()
- // Upload Related IPC
- // from macOS tray
- ipcMain.on('uploadClipboardFiles', async () => {
- const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
- // macOS use builtin clipboard is OK
- const img = await uploader.setWebContents(trayWindow.webContents).uploadWithBuildInClipboard()
- if (img !== false) {
- const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
- handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))))
- const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
- if (isShowResultNotification) {
- const notification = new Notification({
- title: T('UPLOAD_SUCCEED'),
- body: img[0].imgUrl!
- // icon: file[0]
- // icon: img[0].imgUrl
- })
- notification.show()
- }
- await GalleryDB.getInstance().insert(img[0])
- trayWindow.webContents.send('clipboardFiles', [])
- if (windowManager.has(IWindowList.SETTING_WINDOW)) {
- windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
- }
- }
- trayWindow.webContents.send('uploadFiles')
- })
-
- ipcMain.on('uploadClipboardFilesFromUploadPage', () => {
- uploadClipboardFiles()
- })
-
- ipcMain.on('uploadChoosedFiles', async (evt: IpcMainEvent, files: IFileWithPath[]) => {
- return uploadChoosedFiles(evt.sender, files)
- })
-
- ipcMain.on('setTrayToolTip', (_: IpcMainEvent, title: string) => {
- setTrayToolTip(title)
- })
-
- // ShortKey Related IPC
- ipcMain.on('updateShortKey', (evt: IpcMainEvent, item: IShortKeyConfig, oldKey: string, from: string) => {
- const result = shortKeyHandler.updateShortKey(item, oldKey, from)
- evt.sender.send('updateShortKeyResponse', result)
- if (result) {
- const notification = new Notification({
- title: T('OPERATION_SUCCEED'),
- body: T('TIPS_SHORTCUT_MODIFIED_SUCCEED')
- })
- notification.show()
- } else {
- const notification = new Notification({
- title: T('OPERATION_FAILED'),
- body: T('TIPS_SHORTCUT_MODIFIED_CONFLICT')
- })
- notification.show()
- }
- })
-
- ipcMain.on('bindOrUnbindShortKey', (_: IpcMainEvent, item: IShortKeyConfig, from: string) => {
- const result = shortKeyHandler.bindOrUnbindShortKey(item, from)
- if (result) {
- const notification = new Notification({
- title: T('OPERATION_SUCCEED'),
- body: T('TIPS_SHORTCUT_MODIFIED_SUCCEED')
- })
- notification.show()
- } else {
- const notification = new Notification({
- title: T('OPERATION_FAILED'),
- body: T('TIPS_SHORTCUT_MODIFIED_CONFLICT')
- })
- notification.show()
- }
- })
-
- // Gallery image cloud delete IPC
-
- ipcMain.on('logDeleteMsg', async (_: IpcMainEvent, msg: string, logLevel: ILogType) => {
- logger[logLevel](msg)
- })
-
- ipcMain.handle('delete-sftp-file', async (_: IpcMainInvokeEvent, config: ISftpPlistConfig, fileName: string) => {
- try {
- const client = SSHClient.instance
- await client.connect(config)
- const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/')
- const remote = path.join(uploadPath, fileName)
- const deleteResult = await client.deleteFileSFTP(config, remote)
- client.close()
- return deleteResult
- } catch (err: any) {
- logger.error(err)
- return false
- }
- })
-
- ipcMain.handle('delete-aws-s3-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
- const result = await removeFileFromS3InMain(configMap)
- return result
- })
-
- ipcMain.handle('delete-doge-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
- const result = await removeFileFromDogeInMain(configMap)
- return result
- })
-
- ipcMain.handle('delete-huaweicloud-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
- const result = await removeFileFromHuaweiInMain(configMap)
- return result
- })
-
- // migrate from PicGo
-
- ipcMain.handle('migrateFromPicGo', async () => {
- const picGoConfigPath = STORE_PATH.replace('piclist', 'picgo')
- const files = [
- 'data.json',
- 'data.bak.json',
- 'picgo.db',
- 'picgo.bak.db'
- ]
- try {
- await Promise.all(files.map(async file => {
- const sourcePath = path.join(picGoConfigPath, file)
- const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist'))
- await fs.remove(targetPath)
- await fs.copy(sourcePath, targetPath, { overwrite: true })
- }
- ))
- return true
- } catch (err: any) {
- logger.error(err)
- return false
- }
- })
-
- // PicList Setting page IPC
-
- ipcMain.on('autoStart', (_: IpcMainEvent, val: boolean) => {
- app.setLoginItemSettings({
- openAtLogin: val
- })
- })
-
- ipcMain.handle('getShortUrl', async (_: IpcMainInvokeEvent, url: string) => {
- const shortUrl = await generateShortUrl(url)
- return shortUrl
- })
-
- ipcMain.handle('uploadCommonConfig', async () => {
- return await uploadFile(commonConfigList)
- })
-
- ipcMain.handle('downloadCommonConfig', async () => {
- return await downloadFile(commonConfigList)
- })
-
- ipcMain.handle('uploadManageConfig', async () => {
- return await uploadFile(manageConfigList)
- })
-
- ipcMain.handle('downloadManageConfig', async () => {
- return await downloadFile(manageConfigList)
- })
-
- ipcMain.handle('uploadAllConfig', async () => {
- return await uploadFile([...commonConfigList, ...manageConfigList])
- })
-
- ipcMain.handle('downloadAllConfig', async () => {
- return await downloadFile([...commonConfigList, ...manageConfigList])
- })
-
- ipcMain.on('toggleMainWindowAlwaysOnTop', () => {
- const mainWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
- const isAlwaysOnTop = mainWindow.isAlwaysOnTop()
- mainWindow.setAlwaysOnTop(!isAlwaysOnTop)
- })
-
- // Window operation API
-
- ipcMain.on('openSettingWindow', () => {
- windowManager.get(IWindowList.SETTING_WINDOW)!.show()
- const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
- if (autoCloseMiniWindow) {
- if (windowManager.has(IWindowList.MINI_WINDOW)) {
- windowManager.get(IWindowList.MINI_WINDOW)!.hide()
- }
- }
- })
-
- ipcMain.on('openManualWindow', () => {
- windowManager.get(IWindowList.MANUAL_WINDOW)!.show()
- })
-
- ipcMain.on('openMiniWindow', () => {
- const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
- const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
- miniWindow.removeAllListeners()
- if (db.get(configPaths.settings.miniWindowOntop)) {
- miniWindow.setAlwaysOnTop(true)
- }
- const { width, height } = screen.getPrimaryDisplay().workAreaSize
- const lastPosition = db.get(configPaths.settings.miniWindowPosition)
- if (lastPosition) {
- miniWindow.setPosition(lastPosition[0], lastPosition[1])
- } else {
- miniWindow.setPosition(width - 100, height - 100)
- }
- const setPositionFunc = () => {
- const position = miniWindow.getPosition()
- db.set(configPaths.settings.miniWindowPosition, position)
- }
- miniWindow.on('close', setPositionFunc)
- miniWindow.on('move', setPositionFunc)
- miniWindow.show()
- miniWindow.focus()
- settingWindow.hide()
- })
-
- ipcMain.on('updateMiniIcon', (_: IpcMainEvent, iconPath: string) => {
- const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
- miniWindow.webContents.send('updateMiniIcon', iconPath)
- })
-
- ipcMain.on('miniWindowOntop', (_: IpcMainEvent, val: boolean) => {
- const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
- miniWindow.setAlwaysOnTop(val)
- })
-
- ipcMain.on('refreshSettingWindow', () => {
- const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
- settingWindow.webContents.reloadIgnoringCache()
- })
-
- ipcMain.on(GET_PICBEDS, (evt: IpcMainEvent) => {
- const picBeds = getPicBeds()
- evt.sender.send(GET_PICBEDS, picBeds)
- // evt.returnValue = picBeds
- })
-
- ipcMain.on(TOGGLE_SHORTKEY_MODIFIED_MODE, (_: IpcMainEvent, val: boolean) => {
- bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, val)
- })
-
- ipcMain.on('updateServer', () => {
- server.restart()
- })
- ipcMain.on('stopWebServer', () => {
- webServer.stop()
- })
- ipcMain.on('restartWebServer', () => {
- webServer.restart()
- })
- ipcMain.on(OPEN_DEVTOOLS, (event: IpcMainEvent) => {
- event.sender.openDevTools()
- })
- // menu & window methods
- ipcMain.on(SHOW_MINI_PAGE_MENU, () => {
- const window = windowManager.get(IWindowList.MINI_WINDOW)!
- const menu = buildMiniPageMenu()
- menu.popup({
- window
- })
- })
- ipcMain.on(SHOW_MAIN_PAGE_MENU, () => {
- const window = windowManager.get(IWindowList.SETTING_WINDOW)!
- const menu = buildMainPageMenu(window)
- menu.popup({
- window
- })
- })
- ipcMain.on(SHOW_UPLOAD_PAGE_MENU, () => {
- const window = windowManager.get(IWindowList.SETTING_WINDOW)!
- const menu = buildPicBedListMenu()
- menu.popup({
- window
- })
- })
- ipcMain.on(SHOW_PLUGIN_PAGE_MENU, (_: IpcMainEvent, plugin: IPicGoPlugin) => {
- const window = windowManager.get(IWindowList.SETTING_WINDOW)!
- const menu = buildPluginPageMenu(plugin)
- menu.popup({
- window
- })
- })
- ipcMain.on(MINIMIZE_WINDOW, () => {
- const window = BrowserWindow.getFocusedWindow()
- window?.minimize()
- })
- ipcMain.on(CLOSE_WINDOW, () => {
- const window = BrowserWindow.getFocusedWindow()
- if (process.platform === 'linux') {
- window?.hide()
- } else {
- window?.close()
- }
- })
- ipcMain.on(OPEN_USER_STORE_FILE, (_: IpcMainEvent, filePath: string) => {
- const abFilePath = path.join(STORE_PATH, filePath)
- shell.openPath(abFilePath)
- })
- ipcMain.on(OPEN_URL, (_: IpcMainEvent, url: string) => {
- shell.openExternal(url)
- })
- ipcMain.on(RELOAD_APP, () => {
- app.relaunch()
- app.exit(0)
- })
- ipcMain.on(SET_MINI_WINDOW_POS, (_: IpcMainEvent, pos: IMiniWindowPos) => {
- const window = BrowserWindow.getFocusedWindow()
- window?.setBounds(pos)
- })
- ipcMain.on(HIDE_DOCK, (_: IpcMainEvent, val: boolean) => {
- if (val) {
- app.dock.hide()
- } else {
- app.dock.show()
- }
- })
- },
- dispose () {}
-}
diff --git a/src/main/events/picgoCoreIPC.ts b/src/main/events/picgoCoreIPC.ts
deleted file mode 100644
index 9d22abe8..00000000
--- a/src/main/events/picgoCoreIPC.ts
+++ /dev/null
@@ -1,459 +0,0 @@
-import {
- dialog,
- shell,
- IpcMainEvent,
- ipcMain,
- clipboard
-} from 'electron'
-import fs from 'fs-extra'
-import path from 'path'
-import { IGuiMenuItem, PicGo as PicGoCore } from 'piclist'
-import { IObject, IFilter } from '@picgo/store/dist/types'
-
-import picgo from '@core/picgo'
-import { GalleryDB } from '@core/datastore'
-import { dbPathChecker } from '@core/datastore/dbChecker'
-
-import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
-import windowManager from 'apis/app/window/windowManager'
-import GuiApi from 'apis/gui'
-
-import { showNotification } from '~/utils/common'
-import pasteTemplate from '~/utils/pasteTemplate'
-import { i18nManager, T } from '~/i18n'
-import { rpcServer } from '~/events/rpc'
-
-import {
- PICGO_SAVE_CONFIG,
- PICGO_GET_CONFIG,
- PICGO_GET_DB,
- PICGO_INSERT_DB,
- PICGO_INSERT_MANY_DB,
- PICGO_UPDATE_BY_ID_DB,
- PICGO_GET_BY_ID_DB,
- PICGO_REMOVE_BY_ID_DB,
- PICGO_OPEN_FILE,
- PICGO_OPEN_DIRECTORY,
- PASTE_TEXT,
- OPEN_WINDOW,
- GET_LANGUAGE_LIST,
- SET_CURRENT_LANGUAGE,
- GET_CURRENT_LANGUAGE,
- PICGO_GET_CONFIG_SYNC
-} from '#/events/constants'
-import { configPaths } from '#/utils/configPaths'
-import { IPasteStyle, IPicGoHelperType, IWindowList } from '#/types/enum'
-import { handleStreamlinePluginName, simpleClone } from '#/utils/common'
-
-// eslint-disable-next-line
-const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
-// const PluginHandler = requireFunc('picgo/lib/PluginHandler').default
-const STORE_PATH = path.dirname(dbPathChecker())
-// const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
-
-interface GuiMenuItem {
- label: string
- handle: (arg0: PicGoCore, arg1: GuiApi) => Promise
-}
-
-// get uploader or transformer config
-const getConfig = (name: string, type: IPicGoHelperType, ctx: PicGoCore) => {
- let config: any[] = []
- if (name === '') {
- return config
- } else {
- const handler = ctx.helper[type].get(name)
- if (handler) {
- if (handler.config) {
- config = handler.config(ctx)
- }
- }
- return config
- }
-}
-
-const handleConfigWithFunction = (config: any[]) => {
- for (const i in config) {
- if (typeof config[i].default === 'function') {
- config[i].default = config[i].default()
- }
- if (typeof config[i].choices === 'function') {
- config[i].choices = config[i].choices()
- }
- }
- return config
-}
-
-const getPluginList = (): IPicGoPlugin[] => {
- const pluginList = picgo.pluginLoader.getFullList()
- const list = []
- for (const i in pluginList) {
- const plugin = picgo.pluginLoader.getPlugin(pluginList[i])!
- const pluginPath = path.join(STORE_PATH, `/node_modules/${pluginList[i]}`)
- const pluginPKG = requireFunc(path.join(pluginPath, 'package.json'))
- const uploaderName = plugin.uploader || ''
- const transformerName = plugin.transformer || ''
- let menu: Omit[] = []
- if (plugin.guiMenu) {
- menu = plugin.guiMenu(picgo).map(item => ({
- label: item.label
- }))
- }
- let gui = false
- if (pluginPKG.keywords && pluginPKG.keywords.length > 0) {
- if (pluginPKG.keywords.includes('picgo-gui-plugin')) {
- gui = true
- }
- }
- const obj: IPicGoPlugin = {
- name: handleStreamlinePluginName(pluginList[i]),
- fullName: pluginList[i],
- author: pluginPKG.author.name || pluginPKG.author,
- description: pluginPKG.description,
- logo: 'file://' + path.join(pluginPath, 'logo.png').split(path.sep).join('/'),
- version: pluginPKG.version,
- gui,
- config: {
- plugin: {
- fullName: pluginList[i],
- name: handleStreamlinePluginName(pluginList[i]),
- config: plugin.config ? handleConfigWithFunction(plugin.config(picgo)) : []
- },
- uploader: {
- name: uploaderName,
- config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader, picgo))
- },
- transformer: {
- name: transformerName,
- config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer, picgo))
- }
- },
- enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
- homepage: pluginPKG.homepage ? pluginPKG.homepage : '',
- guiMenu: menu,
- ing: false
- }
- list.push(obj)
- }
- return list
-}
-
-const handleGetPluginList = () => {
- ipcMain.on('getPluginList', (event: IpcMainEvent) => {
- try {
- const list = simpleClone(getPluginList())
- // here can just send JS Object not function
- // or will cause [Failed to serialize arguments] error
- event.sender.send('pluginList', list)
- } catch (e: any) {
- event.sender.send('pluginList', [])
- showNotification({
- title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
- body: e.message
- })
- picgo.log.error(e)
- }
- })
-}
-
-const handlePluginInstall = () => {
- ipcMain.on('installPlugin', async (event: IpcMainEvent, fullName: string) => {
- const dispose = handleNPMError()
- const res = await picgo.pluginHandler.install([fullName])
- event.sender.send('installPlugin', {
- success: res.success,
- body: fullName,
- errMsg: res.success ? '' : res.body
- })
- if (res.success) {
- shortKeyHandler.registerPluginShortKey(res.body[0])
- } else {
- showNotification({
- title: T('PLUGIN_INSTALL_FAILED'),
- body: res.body as string
- })
- }
- event.sender.send('hideLoading')
- dispose()
- })
-}
-
-const handlePluginUninstall = async (fullName: string) => {
- const window = windowManager.get(IWindowList.SETTING_WINDOW)!
- const dispose = handleNPMError()
- const res = await picgo.pluginHandler.uninstall([fullName])
- if (res.success) {
- window.webContents.send('uninstallSuccess', res.body[0])
- shortKeyHandler.unregisterPluginShortKey(res.body[0])
- } else {
- showNotification({
- title: T('PLUGIN_UNINSTALL_FAILED'),
- body: res.body as string
- })
- }
- window.webContents.send('hideLoading')
- dispose()
-}
-
-const handlePluginUpdate = async (fullName: string | string[]) => {
- const window = windowManager.get(IWindowList.SETTING_WINDOW)!
- const dispose = handleNPMError()
- const res = await picgo.pluginHandler.update(typeof fullName === 'string' ? [fullName] : fullName)
- if (res.success) {
- window.webContents.send('updateSuccess', res.body[0])
- } else {
- showNotification({
- title: T('PLUGIN_UPDATE_FAILED'),
- body: res.body as string
- })
- }
- window.webContents.send('hideLoading')
- dispose()
-}
-
-const handleUpdateAllPlugin = () => {
- ipcMain.on('updateAllPlugin', async (_: IpcMainEvent, list: string[]) => {
- handlePluginUpdate(list)
- })
-}
-
-const handleNPMError = (): IDispose => {
- const handler = (msg: string) => {
- if (msg === 'NPM is not installed') {
- dialog.showMessageBox({
- title: T('TIPS_ERROR'),
- message: T('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'),
- buttons: ['Yes']
- }).then((res) => {
- if (res.response === 0) {
- shell.openExternal('https://nodejs.org/')
- }
- })
- }
- }
- picgo.once('failed', handler)
- return () => picgo.off('failed', handler)
-}
-
-const handleGetPicBedConfig = () => {
- ipcMain.on('getPicBedConfig', (event: IpcMainEvent, type: string) => {
- const name = picgo.helper.uploader.get(type)?.name || type
- if (picgo.helper.uploader.get(type)?.config) {
- const _config = picgo.helper.uploader.get(type)!.config!(picgo)
- const config = handleConfigWithFunction(_config)
- event.sender.send('getPicBedConfig', config, name)
- } else {
- event.sender.send('getPicBedConfig', [], name)
- }
- })
-}
-
-// TODO: remove it
-const handlePluginActions = () => {
- ipcMain.on('pluginActions', (_: IpcMainEvent, name: string, label: string) => {
- const plugin = picgo.pluginLoader.getPlugin(name)
- if (plugin?.guiMenu?.(picgo)?.length) {
- const menu: GuiMenuItem[] = plugin.guiMenu(picgo)
- menu.forEach(item => {
- if (item.label === label) {
- item.handle(picgo, GuiApi.getInstance())
- }
- })
- }
- })
-}
-
-const handleRemoveFiles = () => {
- ipcMain.on('removeFiles', (_: IpcMainEvent, files: ImgInfo[]) => {
- setTimeout(() => {
- picgo.emit('remove', files, GuiApi.getInstance())
- }, 500)
- })
-}
-
-const handlePicGoSaveConfig = () => {
- ipcMain.on(PICGO_SAVE_CONFIG, (_: IpcMainEvent, data: IObj) => {
- picgo.saveConfig(data)
- })
-}
-
-const handlePicGoGetConfig = () => {
- ipcMain.handle(PICGO_GET_CONFIG, (_, key: string | undefined) => {
- return picgo.getConfig(key)
- })
-}
-
-const handlePicGoGetConfigSync = () => {
- ipcMain.on(PICGO_GET_CONFIG_SYNC, (event: IpcMainEvent, key: string | undefined) => {
- const result = picgo.getConfig(key)
- event.returnValue = result
- })
-}
-
-const handleImportLocalPlugin = () => {
- ipcMain.on('importLocalPlugin', async (event: IpcMainEvent) => {
- const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
- const res = await dialog.showOpenDialog(settingWindow, {
- properties: ['openDirectory']
- })
- const filePaths = res.filePaths
- if (filePaths.length > 0) {
- const res = await picgo.pluginHandler.install(filePaths)
- if (res.success) {
- try {
- const list = simpleClone(getPluginList())
- event.sender.send('pluginList', list)
- } catch (e: any) {
- event.sender.send('pluginList', [])
- showNotification({
- title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
- body: e.message
- })
- }
- showNotification({
- title: T('PLUGIN_IMPORT_SUCCEED'),
- body: ''
- })
- } else {
- showNotification({
- title: T('PLUGIN_IMPORT_FAILED'),
- body: res.body as string
- })
- }
- }
- event.sender.send('hideLoading')
- })
-}
-
-const handlePicGoGalleryDB = () => {
- ipcMain.on(PICGO_GET_DB, async (event: IpcMainEvent, filter: IFilter, callbackId: string) => {
- const dbStore = GalleryDB.getInstance()
- const res = await dbStore.get(filter)
- event.sender.send(PICGO_GET_DB, res, callbackId)
- })
-
- ipcMain.on(PICGO_INSERT_DB, async (event: IpcMainEvent, value: IObject, callbackId: string) => {
- const dbStore = GalleryDB.getInstance()
- const res = await dbStore.insert(value)
- event.sender.send(PICGO_INSERT_DB, res, callbackId)
- })
-
- ipcMain.on(PICGO_INSERT_MANY_DB, async (event: IpcMainEvent, value: IObject[], callbackId: string) => {
- const dbStore = GalleryDB.getInstance()
- const res = await dbStore.insertMany(value)
- event.sender.send(PICGO_INSERT_MANY_DB, res, callbackId)
- })
-
- ipcMain.on(PICGO_UPDATE_BY_ID_DB, async (event: IpcMainEvent, id: string, value: IObject[], callbackId: string) => {
- const dbStore = GalleryDB.getInstance()
- const res = await dbStore.updateById(id, value)
- event.sender.send(PICGO_UPDATE_BY_ID_DB, res, callbackId)
- })
-
- ipcMain.on(PICGO_GET_BY_ID_DB, async (event: IpcMainEvent, id: string, callbackId: string) => {
- const dbStore = GalleryDB.getInstance()
- const res = await dbStore.getById(id)
- event.sender.send(PICGO_GET_BY_ID_DB, res, callbackId)
- })
-
- ipcMain.on(PICGO_REMOVE_BY_ID_DB, async (event: IpcMainEvent, id: string, callbackId: string) => {
- const dbStore = GalleryDB.getInstance()
- const res = await dbStore.removeById(id)
- event.sender.send(PICGO_REMOVE_BY_ID_DB, res, callbackId)
- })
-
- ipcMain.handle(PASTE_TEXT, async (_, item: ImgInfo, copy = true) => {
- const pasteStyle = picgo.getConfig(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
- const customLink = picgo.getConfig(configPaths.settings.customLink)
- const txt = await pasteTemplate(pasteStyle, item, customLink)
- if (copy) {
- clipboard.writeText(txt)
- }
- return txt
- })
-}
-
-const handleOpenFile = () => {
- ipcMain.on(PICGO_OPEN_FILE, (event: IpcMainEvent, fileName: string) => {
- const abFilePath = path.join(STORE_PATH, fileName)
- if (!fs.existsSync(abFilePath)) {
- fs.writeFileSync(abFilePath, '')
- }
- shell.openPath(abFilePath)
- })
-}
-
-const handleOpenDirectory = () => {
- ipcMain.on(PICGO_OPEN_DIRECTORY, (event: IpcMainEvent, dirPath?: string, inStorePath: boolean = true) => {
- if (inStorePath) {
- dirPath = path.join(STORE_PATH, dirPath || '')
- }
- if (!dirPath || !fs.existsSync(dirPath)) {
- return
- }
- shell.openPath(dirPath)
- })
-}
-
-const handleOpenWindow = () => {
- ipcMain.on(OPEN_WINDOW, (event: IpcMainEvent, windowName: IWindowList) => {
- const window = windowManager.get(windowName)
- if (window) {
- window.show()
- }
- })
-}
-
-const handleI18n = () => {
- ipcMain.on(GET_LANGUAGE_LIST, (event: IpcMainEvent) => {
- event.sender.send(GET_LANGUAGE_LIST, i18nManager.languageList)
- })
- ipcMain.on(SET_CURRENT_LANGUAGE, (event: IpcMainEvent, language: string) => {
- i18nManager.setCurrentLanguage(language)
- const { lang, locales } = i18nManager.getCurrentLocales()
- picgo.i18n.setLanguage(lang)
- if (process.platform === 'darwin') {
- const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
- trayWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
- }
- const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
- settingWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
- if (windowManager.has(IWindowList.MINI_WINDOW)) {
- const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)
- miniWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
- }
- // event.sender.send(SET_CURRENT_LANGUAGE, lang, locales)
- })
- ipcMain.on(GET_CURRENT_LANGUAGE, (event: IpcMainEvent) => {
- const { lang, locales } = i18nManager.getCurrentLocales()
- event.sender.send(GET_CURRENT_LANGUAGE, lang, locales)
- })
-}
-
-const handleRPCActions = () => {
- rpcServer.start()
-}
-
-export default {
- listen () {
- handleGetPluginList()
- handlePluginInstall()
- handleGetPicBedConfig()
- handlePluginActions()
- handleRemoveFiles()
- handlePicGoSaveConfig()
- handlePicGoGetConfig()
- handlePicGoGetConfigSync()
- handlePicGoGalleryDB()
- handleImportLocalPlugin()
- handleUpdateAllPlugin()
- handleOpenFile()
- handleOpenDirectory()
- handleOpenWindow()
- handleI18n()
- handleRPCActions()
- },
- // TODO: separate to single file
- handlePluginUninstall,
- handlePluginUpdate
-}
diff --git a/src/main/events/remotes/menu.ts b/src/main/events/remotes/menu.ts
index 17314701..96669a54 100644
--- a/src/main/events/remotes/menu.ts
+++ b/src/main/events/remotes/menu.ts
@@ -3,7 +3,9 @@ import {
dialog,
BrowserWindow,
Menu,
- shell
+ shell,
+ MenuItemConstructorOptions,
+ MenuItem
} from 'electron'
import { PicGo as PicGoCore } from 'piclist'
@@ -16,7 +18,7 @@ import {
import windowManager from 'apis/app/window/windowManager'
import GuiApi from 'apis/gui'
-import picgoCoreIPC from '~/events/picgoCoreIPC'
+import { handlePluginUninstall, handlePluginUpdate } from '~/events/rpc/routes/plugin/utils'
import { T } from '~/i18n'
import clipboardPoll from '~/utils/clipboardPoll'
import { setTrayToolTip } from '~/utils/common'
@@ -34,6 +36,7 @@ import { IWindowList } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import pkg from 'root/package.json'
+import { openMainWindow } from '~/utils/windowHelper'
interface GuiMenuItem {
label: string
@@ -44,18 +47,10 @@ const buildMiniPageMenu = () => {
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const ClipboardWatcher = clipboardPoll
const submenu = buildPicBedListMenu()
- const template = [
+ const template: Array<(MenuItemConstructorOptions) | (MenuItem)> = [
{
label: T('OPEN_MAIN_WINDOW'),
- click () {
- windowManager.get(IWindowList.SETTING_WINDOW)!.show()
- const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
- if (autoCloseMiniWindow) {
- if (windowManager.has(IWindowList.MINI_WINDOW)) {
- windowManager.get(IWindowList.MINI_WINDOW)!.hide()
- }
- }
- }
+ click: openMainWindow
},
{
label: T('CHOOSE_DEFAULT_PICBED'),
@@ -69,7 +64,7 @@ const buildMiniPageMenu = () => {
}
},
{
- label: T('HIDE_WINDOW'),
+ label: T('HIDE_MINI_WINDOW'),
click () {
BrowserWindow.getFocusedWindow()!.hide()
}
@@ -85,7 +80,7 @@ const buildMiniPageMenu = () => {
})
buildMiniPageMenu()
},
- enabled: !isListeningClipboard
+ visible: !isListeningClipboard
},
{
label: T('STOP_WATCH_CLIPBOARD'),
@@ -95,7 +90,7 @@ const buildMiniPageMenu = () => {
ClipboardWatcher.removeAllListeners()
buildMiniPageMenu()
},
- enabled: isListeningClipboard
+ visible: isListeningClipboard
},
{
label: T('RELOAD_APP'),
@@ -109,7 +104,6 @@ const buildMiniPageMenu = () => {
label: T('QUIT')
}
]
- // @ts-ignore
return Menu.buildFromTemplate(template)
}
@@ -269,14 +263,14 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
click () {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
- picgoCoreIPC.handlePluginUninstall(plugin.fullName)
+ handlePluginUninstall(plugin.fullName)
}
}, {
label: T('UPDATE_PLUGIN'),
click () {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
- picgoCoreIPC.handlePluginUpdate(plugin.fullName)
+ handlePluginUpdate(plugin.fullName)
}
}]
for (const i in plugin.config) {
@@ -330,7 +324,6 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
menu.push({
label: i.label,
click () {
- // ipcRenderer.send('pluginActions', plugin.fullName, i.label)
const picgPlugin = picgo.pluginLoader.getPlugin(plugin.fullName)
if (picgPlugin?.guiMenu?.(picgo)?.length) {
const menu: GuiMenuItem[] = picgPlugin.guiMenu(picgo)
diff --git a/src/main/events/rpc/index.ts b/src/main/events/rpc/index.ts
index 9d7bdb20..8b6a8892 100644
--- a/src/main/events/rpc/index.ts
+++ b/src/main/events/rpc/index.ts
@@ -1,45 +1,62 @@
-import { ipcMain, IpcMainEvent } from 'electron'
+import { ipcMain, IpcMainEvent, IpcMainInvokeEvent } from 'electron'
-import { configRouter } from '~/events/rpc/routes/config'
-import { toolboxRouter } from '~/events/rpc/routes/toolbox'
+import logger from '@core/picgo/logger'
+
+import { galleryRouter } from '~/events/rpc/routes/gallery'
+import { picbedRouter } from '~/events/rpc/routes/picbed'
+import { pluginRouter } from '~/events/rpc/routes/plugin'
+import { settingRouter } from '~/events/rpc/routes/setting'
import { systemRouter } from '~/events/rpc/routes/system'
+import { toolboxRouter } from '~/events/rpc/routes/toolbox'
+import { trayRouter } from '~/events/rpc/routes/tray'
+import { uploadRouter } from '~/events/rpc/routes/upload'
-import { IRPCActionType } from '#/types/enum'
-import { RPC_ACTIONS } from '#/events/constants'
+import { IRPCActionType, IRPCType } from '#/types/enum'
+import { RPC_ACTIONS, RPC_ACTIONS_INVOKE } from '#/events/constants'
+
+const isDevelopment = process.env.NODE_ENV !== 'production'
class RPCServer implements IRPCServer {
private routes: IRPCRoutes = new Map()
+ private routesWithResponse: IRPCRoutes = new Map()
- private rpcEventHandler = async (event: IpcMainEvent, action: IRPCActionType, args: any[], callbackId: string) => {
+ private rpcEventHandler = async (event: IpcMainEvent, action: IRPCActionType, args: any[]) => {
try {
- const handler = this.routes.get(action)
- if (!handler) {
- return this.sendBack(event, action, null, callbackId)
+ if (isDevelopment) {
+ console.log(`action: ${action} args: ${JSON.stringify(args)}`)
}
- const res = await handler?.(args, event)
- this.sendBack(event, action, res, callbackId)
- } catch (e) {
- this.sendBack(event, action, null, callbackId)
+ const route = this.routes.get(action)
+ await route?.handler?.(event, args)
+ } catch (e: any) {
+ logger.error(e)
}
}
- /**
- * if sendback data is null, then it means that the action is not supported or error occurs
- * if there is no callbackId, then do not send back
- */
- private sendBack (event: IpcMainEvent, action: IRPCActionType, data: any, callbackId: string) {
- if (callbackId) {
- event.sender.send(RPC_ACTIONS, data, action, callbackId)
+ private rpcEventHandlerWithResponse = async (event: IpcMainInvokeEvent, action: IRPCActionType, args: any[]) => {
+ try {
+ if (isDevelopment) {
+ console.log(`action: ${action} args: ${JSON.stringify(args)}`)
+ }
+ const route = this.routesWithResponse.get(action)
+ return await route?.handler?.(event, args)
+ } catch (e: any) {
+ logger.error(e)
+ return undefined
}
}
start () {
ipcMain.on(RPC_ACTIONS, this.rpcEventHandler)
+ ipcMain.handle(RPC_ACTIONS_INVOKE, this.rpcEventHandlerWithResponse)
}
use (routes: IRPCRoutes) {
- for (const [action, handler] of routes) {
- this.routes.set(action, handler)
+ for (const [action, route] of routes) {
+ if (route.type === IRPCType.SEND) {
+ this.routes.set(action, route)
+ } else {
+ this.routesWithResponse.set(action, route)
+ }
}
}
@@ -50,9 +67,20 @@ class RPCServer implements IRPCServer {
const rpcServer = new RPCServer()
-rpcServer.use(configRouter.routes())
-rpcServer.use(toolboxRouter.routes())
-rpcServer.use(systemRouter.routes())
+const routes = [
+ galleryRouter.routes(),
+ picbedRouter.routes(),
+ pluginRouter.routes(),
+ settingRouter.routes(),
+ systemRouter.routes(),
+ toolboxRouter.routes(),
+ trayRouter.routes(),
+ uploadRouter.routes()
+]
+
+for (const route of routes) {
+ rpcServer.use(route)
+}
export {
rpcServer
diff --git a/src/main/events/rpc/router.ts b/src/main/events/rpc/router.ts
index abda51e5..8117e21b 100644
--- a/src/main/events/rpc/router.ts
+++ b/src/main/events/rpc/router.ts
@@ -1,9 +1,22 @@
-import { IRPCActionType } from '#/types/enum'
+import { IRPCType, IRPCActionType } from '#/types/enum'
+
+interface IBatchAddParams {
+ action: IRPCActionType
+ handler: IRPCHandler
+ type?: IRPCType
+}
export class RPCRouter implements IRPCRouter {
private routeMap: IRPCRoutes = new Map()
- add = (action: IRPCActionType, handler: IRPCHandler) => {
- this.routeMap.set(action, handler)
+ add = (action: IRPCActionType, handler: IRPCHandler, type: IRPCType = IRPCType.SEND): this => {
+ this.routeMap.set(action, { handler, type })
+ return this
+ }
+
+ addBatch = (params: IBatchAddParams[]): this => {
+ for (const { action, handler, type = IRPCType.SEND } of params) {
+ this.routeMap.set(action, { handler, type })
+ }
return this
}
diff --git a/src/main/events/rpc/routes/config.ts b/src/main/events/rpc/routes/config.ts
deleted file mode 100644
index b8b0ee1e..00000000
--- a/src/main/events/rpc/routes/config.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { RPCRouter } from '~/events/rpc/router'
-import {
- deleteUploaderConfig,
- getUploaderConfigList,
- resetUploaderConfig,
- selectUploaderConfig,
- updateUploaderConfig
-} from '~/utils/handleUploaderConfig'
-import { IRPCActionType } from '#/types/enum'
-
-const configRouter = new RPCRouter()
-
-configRouter
- .add(IRPCActionType.GET_PICBED_CONFIG_LIST, async (args) => {
- const [type] = args as IGetUploaderConfigListArgs
- const config = getUploaderConfigList(type)
- return config
- })
- .add(IRPCActionType.DELETE_PICBED_CONFIG, async (args) => {
- const [type, id] = args as IDeleteUploaderConfigArgs
- const config = deleteUploaderConfig(type, id)
- return config
- })
- .add(IRPCActionType.SELECT_UPLOADER, async (args) => {
- const [type, id] = args as ISelectUploaderConfigArgs
- selectUploaderConfig(type, id)
- return true
- })
- .add(IRPCActionType.UPDATE_UPLOADER_CONFIG, async (args) => {
- const [type, id, config] = args as IUpdateUploaderConfigArgs
- updateUploaderConfig(type, id, config)
- return true
- })
- .add(IRPCActionType.RESET_UPLOADER_CONFIG, async (args) => {
- const [type, id] = args as IUpdateUploaderConfigArgs
- resetUploaderConfig(type, id)
- return true
- })
-
-export {
- configRouter
-}
diff --git a/src/main/events/rpc/routes/gallery/index.ts b/src/main/events/rpc/routes/gallery/index.ts
new file mode 100644
index 00000000..5ae1e388
--- /dev/null
+++ b/src/main/events/rpc/routes/gallery/index.ts
@@ -0,0 +1,133 @@
+
+import { clipboard } from 'electron'
+
+import { GalleryDB } from '@core/datastore'
+import picgo from '@core/picgo'
+import logger from '@core/picgo/logger'
+import { IFilter, IObject } from '@picgo/store/dist/types'
+import GuiApi from 'apis/gui'
+
+import { RPCRouter } from '~/events/rpc/router'
+import { removeFileFromDogeInMain, removeFileFromHuaweiInMain, removeFileFromS3InMain, removeFileFromSFTPInMain } from '~/utils/deleteFunc'
+import pasteTemplate from '~/utils/pasteTemplate'
+
+import { ICOREBuildInEvent, IPasteStyle, IRPCActionType, IRPCType } from '#/types/enum'
+import { configPaths } from '#/utils/configPaths'
+
+const galleryRouter = new RPCRouter()
+
+const galleryRoutes = [
+ {
+ action: IRPCActionType.GALLERY_PASTE_TEXT,
+ handler: async (_: IIPCEvent, args: [ item: ImgInfo, copy?: boolean]) => {
+ const [item, copy = true] = args
+ const pasteStyle = picgo.getConfig(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
+ const customLink = picgo.getConfig(configPaths.settings.customLink)
+ const txt = await pasteTemplate(pasteStyle, item, customLink)
+ if (copy) {
+ clipboard.writeText(txt)
+ }
+ return txt
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_REMOVE_FILES,
+ handler: async (_: IIPCEvent, args: [files: ImgInfo[]]) => {
+ setTimeout(() => {
+ picgo.emit(ICOREBuildInEvent.REMOVE, args[0], GuiApi.getInstance())
+ }, 500)
+ }
+ },
+ {
+ action: IRPCActionType.GALLERY_GET_DB,
+ handler: async (_: IIPCEvent, args: [filter: IFilter]) => {
+ const dbStore = GalleryDB.getInstance()
+ return await dbStore.get(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_GET_BY_ID_DB,
+ handler: async (_: IIPCEvent, args: [id: string]) => {
+ const dbStore = GalleryDB.getInstance()
+ return await dbStore.getById(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_UPDATE_BY_ID_DB,
+ handler: async (_: IIPCEvent, args: [id: string, value: IObject]) => {
+ const dbStore = GalleryDB.getInstance()
+ return await dbStore.updateById(args[0], args[1])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_REMOVE_BY_ID_DB,
+ handler: async (_: IIPCEvent, args: [id: string]) => {
+ const dbStore = GalleryDB.getInstance()
+ return await dbStore.removeById(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_INSERT_DB,
+ handler: async (_: IIPCEvent, args: [value: IObject]) => {
+ const dbStore = GalleryDB.getInstance()
+ return await dbStore.insert(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_INSERT_DB_BATCH,
+ handler: async (_: IIPCEvent, args: [value: IObject[]]) => {
+ const dbStore = GalleryDB.getInstance()
+ return await dbStore.insertMany(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_LOG_DELETE_MSG,
+ handler: async (_: IIPCEvent, args: [msg: string, logLevel: ILogType]) => {
+ const [msg, logLevel] = args
+ console.log(msg, logLevel)
+ logger[logLevel](msg)
+ }
+ },
+ {
+ action: IRPCActionType.GALLERY_DELETE_SFTP_FILE,
+ handler: async (_: IIPCEvent, args: [config: ISftpPlistConfig, fileName: string]) => {
+ const [config, fileName] = args
+ return await removeFileFromSFTPInMain(config, fileName)
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_DELETE_AWS_S3_FILE,
+ handler: async (_: IIPCEvent, args: [configMap: IStringKeyMap]) => {
+ return await removeFileFromS3InMain(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_DELETE_DOGE_FILE,
+ handler: async (_: IIPCEvent, args: [configMap: IStringKeyMap]) => {
+ return await removeFileFromDogeInMain(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE,
+ handler: async (_: IIPCEvent, args: [configMap: IStringKeyMap]) => {
+ return await removeFileFromHuaweiInMain(args[0])
+ },
+ type: IRPCType.INVOKE
+ }
+]
+
+galleryRouter.addBatch(galleryRoutes)
+
+export {
+ galleryRouter
+}
diff --git a/src/main/events/rpc/routes/picbed/index.ts b/src/main/events/rpc/routes/picbed/index.ts
new file mode 100644
index 00000000..5936a863
--- /dev/null
+++ b/src/main/events/rpc/routes/picbed/index.ts
@@ -0,0 +1,99 @@
+import picgo from '@core/picgo'
+
+import { RPCRouter } from '~/events/rpc/router'
+import {
+ deleteUploaderConfig,
+ getUploaderConfigList,
+ resetUploaderConfig,
+ selectUploaderConfig,
+ updateUploaderConfig
+} from '~/utils/handleUploaderConfig'
+import { IRPCActionType, IRPCType } from '#/types/enum'
+
+const picbedRouter = new RPCRouter()
+
+const handleConfigWithFunction = (config: any[]) => {
+ for (const i in config) {
+ if (typeof config[i].default === 'function') {
+ config[i].default = config[i].default()
+ }
+ if (typeof config[i].choices === 'function') {
+ config[i].choices = config[i].choices()
+ }
+ }
+ return config
+}
+
+const picbedRoutes = [
+ {
+ action: IRPCActionType.PICBED_GET_CONFIG_LIST,
+ handler: async (_: IIPCEvent, args: [type: string]) => {
+ const config = getUploaderConfigList(args[0])
+ return config
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.PICBED_DELETE_CONFIG,
+ handler: async (_: IIPCEvent, args: [type: string, id: string]) => {
+ const [type, id] = args
+ const config = deleteUploaderConfig(type, id)
+ return config
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.UPLOADER_SELECT,
+ handler: async (_: IIPCEvent, args: [type: string, id: string]) => {
+ const [type, id] = args
+ selectUploaderConfig(type, id)
+ return true
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.UPLOADER_UPDATE_CONFIG,
+ handler: async (_: IIPCEvent, args: [type: string, id: string, config: IStringKeyMap]) => {
+ const [type, id, config] = args
+ updateUploaderConfig(type, id, config)
+ return true
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.UPLOADER_RESET_CONFIG,
+ handler: async (_: IIPCEvent, args: [type: string, id: string]) => {
+ const [type, id] = args
+ resetUploaderConfig(type, id)
+ return true
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.PICBED_GET_PICBED_CONFIG,
+ handler: async (_: IIPCEvent, args: [type: string]) => {
+ const type = args[0]
+ const name = picgo.helper.uploader.get(type)?.name || type
+ if (picgo.helper.uploader.get(type)?.config) {
+ const _config = picgo.helper.uploader.get(type)!.config!(picgo)
+ const config = handleConfigWithFunction(_config)
+ return {
+ config,
+ name
+ }
+ } else {
+ return {
+ config: [],
+ name
+ }
+ }
+ },
+ type: IRPCType.INVOKE
+ }
+]
+
+picbedRouter.addBatch(picbedRoutes)
+
+export {
+ picbedRouter
+}
diff --git a/src/main/events/rpc/routes/plugin/index.ts b/src/main/events/rpc/routes/plugin/index.ts
new file mode 100644
index 00000000..ea91bc78
--- /dev/null
+++ b/src/main/events/rpc/routes/plugin/index.ts
@@ -0,0 +1,37 @@
+
+import { RPCRouter } from '~/events/rpc/router'
+import {
+ pluginImportLocalFunc,
+ pluginInstallFunc,
+ pluginGetListFunc,
+ pluginUpdateAllFunc
+} from '~/events/rpc/routes/plugin/utils'
+
+import { IRPCActionType } from '#/types/enum'
+
+const pluginRouter = new RPCRouter()
+
+const pluginRoutes = [
+ {
+ action: IRPCActionType.PLUGIN_GET_LIST,
+ handler: pluginGetListFunc
+ },
+ {
+ action: IRPCActionType.PLUGIN_INSTALL,
+ handler: pluginInstallFunc
+ },
+ {
+ action: IRPCActionType.PLUGIN_IMPORT_LOCAL,
+ handler: pluginImportLocalFunc
+ },
+ {
+ action: IRPCActionType.PLUGIN_UPDATE_ALL,
+ handler: pluginUpdateAllFunc
+ }
+]
+
+pluginRouter.addBatch(pluginRoutes)
+
+export {
+ pluginRouter
+}
diff --git a/src/main/events/rpc/routes/plugin/utils.ts b/src/main/events/rpc/routes/plugin/utils.ts
new file mode 100644
index 00000000..37711074
--- /dev/null
+++ b/src/main/events/rpc/routes/plugin/utils.ts
@@ -0,0 +1,227 @@
+import { dialog, shell } from 'electron'
+import { IGuiMenuItem, PicGo as PicGoCore } from 'piclist'
+import path from 'path'
+
+import { dbPathDir } from '@core/datastore/dbChecker'
+import picgo from '@core/picgo'
+
+import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
+import windowManager from 'apis/app/window/windowManager'
+
+import { T } from '~/i18n'
+import { showNotification } from '~/utils/common'
+
+import { handleStreamlinePluginName, simpleClone } from '#/utils/common'
+import { ICOREBuildInEvent, IPicGoHelperType, IWindowList } from '#/types/enum'
+
+const STORE_PATH = dbPathDir()
+
+// eslint-disable-next-line
+const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
+
+// get uploader or transformer config
+const getConfig = (name: string, type: IPicGoHelperType, ctx: PicGoCore) => {
+ let config: any[] = []
+ if (name === '') {
+ return config
+ } else {
+ const handler = ctx.helper[type].get(name)
+ if (handler) {
+ if (handler.config) {
+ config = handler.config(ctx)
+ }
+ }
+ return config
+ }
+}
+
+const handleConfigWithFunction = (config: any[]) => {
+ for (const i in config) {
+ if (typeof config[i].default === 'function') {
+ config[i].default = config[i].default()
+ }
+ if (typeof config[i].choices === 'function') {
+ config[i].choices = config[i].choices()
+ }
+ }
+ return config
+}
+
+const getPluginList = (): IPicGoPlugin[] => {
+ const pluginList = picgo.pluginLoader.getFullList()
+ const list = []
+ for (const i in pluginList) {
+ const plugin = picgo.pluginLoader.getPlugin(pluginList[i])!
+ const pluginPath = path.join(STORE_PATH, `/node_modules/${pluginList[i]}`)
+ const pluginPKG = requireFunc(path.join(pluginPath, 'package.json'))
+ const uploaderName = plugin.uploader || ''
+ const transformerName = plugin.transformer || ''
+ let menu: Omit[] = []
+ if (plugin.guiMenu) {
+ menu = plugin.guiMenu(picgo).map(item => ({
+ label: item.label
+ }))
+ }
+ let gui = false
+ if (pluginPKG.keywords && pluginPKG.keywords.length > 0) {
+ if (pluginPKG.keywords.includes('picgo-gui-plugin')) {
+ gui = true
+ }
+ }
+ const obj: IPicGoPlugin = {
+ name: handleStreamlinePluginName(pluginList[i]),
+ fullName: pluginList[i],
+ author: pluginPKG.author.name || pluginPKG.author,
+ description: pluginPKG.description,
+ logo: 'file://' + path.join(pluginPath, 'logo.png').split(path.sep).join('/'),
+ version: pluginPKG.version,
+ gui,
+ config: {
+ plugin: {
+ fullName: pluginList[i],
+ name: handleStreamlinePluginName(pluginList[i]),
+ config: plugin.config ? handleConfigWithFunction(plugin.config(picgo)) : []
+ },
+ uploader: {
+ name: uploaderName,
+ config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader, picgo))
+ },
+ transformer: {
+ name: transformerName,
+ config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer, picgo))
+ }
+ },
+ enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
+ homepage: pluginPKG.homepage ? pluginPKG.homepage : '',
+ guiMenu: menu,
+ ing: false
+ }
+ list.push(obj)
+ }
+ return list
+}
+
+const handleNPMError = (): IDispose => {
+ const handler = (msg: string) => {
+ if (msg === 'NPM is not installed') {
+ dialog.showMessageBox({
+ title: T('TIPS_ERROR'),
+ message: T('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'),
+ buttons: ['Yes']
+ }).then((res) => {
+ if (res.response === 0) {
+ shell.openExternal('https://nodejs.org/')
+ }
+ })
+ }
+ }
+ picgo.once(ICOREBuildInEvent.FAILED, handler)
+ return () => picgo.off(ICOREBuildInEvent.FAILED, handler)
+}
+
+export const handlePluginUpdate = async (fullName: string | string[]) => {
+ const window = windowManager.get(IWindowList.SETTING_WINDOW)!
+ const dispose = handleNPMError()
+ const res = await picgo.pluginHandler.update(typeof fullName === 'string' ? [fullName] : fullName)
+ if (res.success) {
+ window.webContents.send('updateSuccess', res.body[0])
+ } else {
+ showNotification({
+ title: T('PLUGIN_UPDATE_FAILED'),
+ body: res.body as string
+ })
+ }
+ window.webContents.send('hideLoading')
+ dispose()
+}
+
+export const handlePluginUninstall = async (fullName: string) => {
+ const window = windowManager.get(IWindowList.SETTING_WINDOW)!
+ const dispose = handleNPMError()
+ const res = await picgo.pluginHandler.uninstall([fullName])
+ if (res.success) {
+ window.webContents.send('uninstallSuccess', res.body[0])
+ shortKeyHandler.unregisterPluginShortKey(res.body[0])
+ } else {
+ showNotification({
+ title: T('PLUGIN_UNINSTALL_FAILED'),
+ body: res.body as string
+ })
+ }
+ window.webContents.send('hideLoading')
+ dispose()
+}
+
+export const pluginGetListFunc = async (event: IIPCEvent) => {
+ try {
+ const list = simpleClone(getPluginList())
+ // here can just send JS Object not function
+ // or will cause [Failed to serialize arguments] error
+ event.sender.send('pluginList', list)
+ } catch (e: any) {
+ event.sender.send('pluginList', [])
+ showNotification({
+ title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
+ body: e.message
+ })
+ picgo.log.error(e)
+ }
+}
+
+export const pluginInstallFunc = async (event: IIPCEvent, args: [fullName: string]) => {
+ const fullName = args[0]
+ const dispose = handleNPMError()
+ const res = await picgo.pluginHandler.install([fullName])
+ event.sender.send('installPlugin', {
+ success: res.success,
+ body: fullName,
+ errMsg: res.success ? '' : res.body
+ })
+ if (res.success) {
+ shortKeyHandler.registerPluginShortKey(res.body[0])
+ } else {
+ showNotification({
+ title: T('PLUGIN_INSTALL_FAILED'),
+ body: res.body as string
+ })
+ }
+ event.sender.send('hideLoading')
+ dispose()
+}
+
+export const pluginImportLocalFunc = async (event: IIPCEvent) => {
+ const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
+ const res = await dialog.showOpenDialog(settingWindow, {
+ properties: ['openDirectory']
+ })
+ const filePaths = res.filePaths
+ if (filePaths.length > 0) {
+ const res = await picgo.pluginHandler.install(filePaths)
+ if (res.success) {
+ try {
+ const list = simpleClone(getPluginList())
+ event.sender.send('pluginList', list)
+ } catch (e: any) {
+ event.sender.send('pluginList', [])
+ showNotification({
+ title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
+ body: e.message
+ })
+ }
+ showNotification({
+ title: T('PLUGIN_IMPORT_SUCCEED'),
+ body: ''
+ })
+ } else {
+ showNotification({
+ title: T('PLUGIN_IMPORT_FAILED'),
+ body: res.body as string
+ })
+ }
+ }
+ event.sender.send('hideLoading')
+}
+
+export const pluginUpdateAllFunc = async (_: IIPCEvent, args: [list: string[]]) => {
+ handlePluginUpdate(args[0])
+}
diff --git a/src/main/events/rpc/routes/setting/advanced.ts b/src/main/events/rpc/routes/setting/advanced.ts
new file mode 100644
index 00000000..9edef769
--- /dev/null
+++ b/src/main/events/rpc/routes/setting/advanced.ts
@@ -0,0 +1,25 @@
+
+import { IRPCActionType } from '#/types/enum'
+import server from '~/server'
+import webServer from '~/server/webServer'
+
+export default [
+ {
+ action: IRPCActionType.ADVANCED_UPDATE_SERVER,
+ handler: async () => {
+ server.restart()
+ }
+ },
+ {
+ action: IRPCActionType.ADVANCED_STOP_WEB_SERVER,
+ handler: async () => {
+ webServer.stop()
+ }
+ },
+ {
+ action: IRPCActionType.ADVANCED_RESTART_WEB_SERVER,
+ handler: async () => {
+ webServer.restart()
+ }
+ }
+]
diff --git a/src/main/events/rpc/routes/setting/configure.ts b/src/main/events/rpc/routes/setting/configure.ts
new file mode 100644
index 00000000..0987cad6
--- /dev/null
+++ b/src/main/events/rpc/routes/setting/configure.ts
@@ -0,0 +1,82 @@
+import { app } from 'electron'
+import fs from 'fs-extra'
+import path from 'path'
+
+import logger from '@core/picgo/logger'
+import { downloadFile, uploadFile } from '~/utils/syncSettings'
+import { IRPCActionType, IRPCType } from '#/types/enum'
+
+const STORE_PATH = app.getPath('userData')
+
+const commonConfigList = ['data.json', 'data.bak.json']
+const manageConfigList = ['manage.json', 'manage.bak.json']
+
+export default [
+ {
+ action: IRPCActionType.CONFIGURE_MIGRATE_FROM_PICGO,
+ handler: async () => {
+ const picGoConfigPath = STORE_PATH.replace('piclist', 'picgo')
+ const files = [
+ 'data.json',
+ 'data.bak.json',
+ 'picgo.db',
+ 'picgo.bak.db'
+ ]
+ try {
+ await Promise.all(files.map(async file => {
+ const sourcePath = path.join(picGoConfigPath, file)
+ const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist'))
+ await fs.copy(sourcePath, targetPath, { overwrite: true })
+ }
+ ))
+ return true
+ } catch (err: any) {
+ logger.error(err)
+ throw new Error('Migrate failed')
+ }
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.CONFIGURE_UPLOAD_COMMON_CONFIG,
+ handler: async () => {
+ return await uploadFile(commonConfigList)
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.CONFIGURE_UPLOAD_MANAGE_CONFIG,
+ handler: async () => {
+ return await uploadFile(manageConfigList)
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.CONFIGURE_UPLOAD_ALL_CONFIG,
+ handler: async () => {
+ return await uploadFile([...commonConfigList, ...manageConfigList])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.CONFIGURE_DOWNLOAD_COMMON_CONFIG,
+ handler: async () => {
+ return await downloadFile(commonConfigList)
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.CONFIGURE_DOWNLOAD_MANAGE_CONFIG,
+ handler: async () => {
+ return await downloadFile(manageConfigList)
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.CONFIGURE_DOWNLOAD_ALL_CONFIG,
+ handler: async () => {
+ return await downloadFile([...commonConfigList, ...manageConfigList])
+ },
+ type: IRPCType.INVOKE
+ }
+]
diff --git a/src/main/events/rpc/routes/setting/index.ts b/src/main/events/rpc/routes/setting/index.ts
new file mode 100644
index 00000000..20ecdbe9
--- /dev/null
+++ b/src/main/events/rpc/routes/setting/index.ts
@@ -0,0 +1,21 @@
+import { RPCRouter } from '~/events/rpc/router'
+
+import advancedRoutes from '~/events/rpc/routes/setting/advanced'
+import configureRoutes from '~/events/rpc/routes/setting/configure'
+import mainAppRoutes from '~/events/rpc/routes/setting/mainApp'
+import shortKeyRoutes from '~/events/rpc/routes/setting/shortKey'
+
+const settingRouter = new RPCRouter()
+
+const settingRoutes = [
+ ...advancedRoutes,
+ ...configureRoutes,
+ ...mainAppRoutes,
+ ...shortKeyRoutes
+]
+
+settingRouter.addBatch(settingRoutes)
+
+export {
+ settingRouter
+}
diff --git a/src/main/events/rpc/routes/setting/mainApp.ts b/src/main/events/rpc/routes/setting/mainApp.ts
new file mode 100644
index 00000000..4851e9e4
--- /dev/null
+++ b/src/main/events/rpc/routes/setting/mainApp.ts
@@ -0,0 +1,65 @@
+import { app, IpcMainEvent, shell } from 'electron'
+import fs from 'fs-extra'
+import path from 'path'
+
+import picgo from '@core/picgo'
+import { dbPathDir } from '@core/datastore/dbChecker'
+
+import { IRPCActionType, IRPCType } from '#/types/enum'
+
+const STORE_PATH = dbPathDir()
+
+export default [
+ {
+ action: IRPCActionType.PICLIST_GET_CONFIG,
+ handler: async (_: IIPCEvent, args: [key?: string]) => {
+ return picgo.getConfig(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.PICLIST_GET_CONFIG_SYNC,
+ handler: async (event: IIPCEvent, args: [key?: string]) => {
+ const result = picgo.getConfig(args[0])
+ const eventInstance = event as IpcMainEvent
+ eventInstance.returnValue = result
+ }
+ },
+ {
+ action: IRPCActionType.PICLIST_SAVE_CONFIG,
+ handler: async (_: IIPCEvent, args: [data: IObj]) => {
+ picgo.saveConfig(args[0])
+ }
+ },
+ {
+ action: IRPCActionType.PICLIST_OPEN_FILE,
+ handler: async (_: IIPCEvent, args: [fileName: string]) => {
+ const abFilePath = path.join(STORE_PATH, args[0])
+ if (!fs.existsSync(abFilePath)) {
+ fs.writeFileSync(abFilePath, '')
+ }
+ shell.openPath(abFilePath)
+ }
+ },
+ {
+ action: IRPCActionType.PICLIST_OPEN_DIRECTORY,
+ handler: async (_: IIPCEvent, args: [dirPath?: string, inStorePath?: boolean]) => {
+ let [dirPath, inStorePath = true] = args
+ if (inStorePath) {
+ dirPath = path.join(STORE_PATH, dirPath || '')
+ }
+ if (!dirPath || !fs.existsSync(dirPath)) {
+ return
+ }
+ shell.openPath(dirPath)
+ }
+ },
+ {
+ action: IRPCActionType.PICLIST_AUTO_START,
+ handler: async (_: IIPCEvent, args: [val: boolean]) => {
+ app.setLoginItemSettings({
+ openAtLogin: args[0]
+ })
+ }
+ }
+]
diff --git a/src/main/events/rpc/routes/setting/shortKey.ts b/src/main/events/rpc/routes/setting/shortKey.ts
new file mode 100644
index 00000000..9cf4443c
--- /dev/null
+++ b/src/main/events/rpc/routes/setting/shortKey.ts
@@ -0,0 +1,46 @@
+import {
+ Notification
+} from 'electron'
+
+import bus from '@core/bus'
+import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
+import { T } from '~/i18n'
+
+import { IRPCActionType, IRPCType } from '#/types/enum'
+import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
+
+const notificationFunc = (result: boolean) => {
+ const notification = new Notification({
+ title: T(`OPERATION_${result ? 'SUCCEED' : 'FAILED'}`),
+ body: T(`TIPS_SHORTCUT_MODIFIED_${result ? 'SUCCEED' : 'CONFLICT'}`)
+ })
+ notification.show()
+}
+
+export default [
+ {
+ action: IRPCActionType.SHORTKEY_UPDATE,
+ handler: async (_: IIPCEvent, args: [item: IShortKeyConfig, oldKey: string, from: string]) => {
+ const [item, oldKey, from] = args
+ const result = shortKeyHandler.updateShortKey(item, oldKey, from)
+ notificationFunc(result)
+ return result
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.SHORTKEY_BIND_OR_UNBIND,
+ handler: async (_: IIPCEvent, args: [item: IShortKeyConfig, from: string]) => {
+ const [item, from] = args
+ const result = shortKeyHandler.bindOrUnbindShortKey(item, from)
+ notificationFunc(result)
+ }
+ },
+ {
+ action: IRPCActionType.SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE,
+ handler: async (_: IIPCEvent, args: [status: boolean]) => {
+ const [status] = args
+ bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, status)
+ }
+ }
+]
diff --git a/src/main/events/rpc/routes/system.ts b/src/main/events/rpc/routes/system.ts
deleted file mode 100644
index e7180f6d..00000000
--- a/src/main/events/rpc/routes/system.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { app, clipboard, shell } from 'electron'
-
-import { RPCRouter } from '~/events/rpc/router'
-import { IRPCActionType } from '#/types/enum'
-
-const systemRouter = new RPCRouter()
-
-systemRouter
- .add(IRPCActionType.RELOAD_APP, async () => {
- app.relaunch()
- app.exit(0)
- })
- .add(IRPCActionType.OPEN_FILE, async (args) => {
- const [filePath] = args as IOpenFileArgs
- shell.openPath(filePath)
- })
- .add(IRPCActionType.COPY_TEXT, async (args) => {
- const [text] = args as ICopyTextArgs
- return clipboard.writeText(text)
- })
-
-export {
- systemRouter
-}
diff --git a/src/main/events/rpc/routes/system/app.ts b/src/main/events/rpc/routes/system/app.ts
new file mode 100644
index 00000000..6a9b76fd
--- /dev/null
+++ b/src/main/events/rpc/routes/system/app.ts
@@ -0,0 +1,62 @@
+import { app, shell } from 'electron'
+
+import picgo from '@core/picgo'
+
+import windowManager from 'apis/app/window/windowManager'
+import { i18nManager } from '~/i18n'
+
+import { IRPCActionType, IWindowList } from '#/types/enum'
+import { GET_CURRENT_LANGUAGE, GET_LANGUAGE_LIST, SET_CURRENT_LANGUAGE } from '#/events/constants'
+
+export default [
+ {
+ action: IRPCActionType.RELOAD_APP,
+ handler: async () => {
+ app.relaunch()
+ app.exit(0)
+ }
+ },
+ {
+ action: IRPCActionType.OPEN_FILE,
+ handler: async (_: IIPCEvent, args: [filePath: string]) => {
+ shell.openPath(args[0])
+ }
+ },
+ {
+ action: IRPCActionType.OPEN_URL,
+ handler: async (_: IIPCEvent, args: [url: string]) => {
+ shell.openExternal(args[0])
+ }
+ },
+ {
+ action: IRPCActionType.GET_LANGUAGE_LIST,
+ handler: async (event: IIPCEvent) => {
+ event.sender.send(GET_LANGUAGE_LIST, i18nManager.languageList)
+ }
+ },
+ {
+ action: IRPCActionType.GET_CURRENT_LANGUAGE,
+ handler: async (event: IIPCEvent) => {
+ const { lang, locales } = i18nManager.getCurrentLocales()
+ event.sender.send(GET_CURRENT_LANGUAGE, lang, locales)
+ }
+ },
+ {
+ action: IRPCActionType.SET_CURRENT_LANGUAGE,
+ handler: async (_: IIPCEvent, args: [language: string]) => {
+ i18nManager.setCurrentLanguage(args[0])
+ const { lang, locales } = i18nManager.getCurrentLocales()
+ picgo.i18n.setLanguage(lang)
+ if (process.platform === 'darwin') {
+ const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
+ trayWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
+ }
+ const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
+ settingWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
+ if (windowManager.has(IWindowList.MINI_WINDOW)) {
+ const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)
+ miniWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
+ }
+ }
+ }
+]
diff --git a/src/main/events/rpc/routes/system/index.ts b/src/main/events/rpc/routes/system/index.ts
new file mode 100644
index 00000000..9b5a6df4
--- /dev/null
+++ b/src/main/events/rpc/routes/system/index.ts
@@ -0,0 +1,16 @@
+import { RPCRouter } from '~/events/rpc/router'
+import appRoutes from '~/events/rpc/routes/system/app'
+import windowRoutes from '~/events/rpc/routes/system/window'
+
+const systemRouter = new RPCRouter()
+
+const systemRoutes = [
+ ...appRoutes,
+ ...windowRoutes
+]
+
+systemRouter.addBatch(systemRoutes)
+
+export {
+ systemRouter
+}
diff --git a/src/main/events/rpc/routes/system/window.ts b/src/main/events/rpc/routes/system/window.ts
new file mode 100644
index 00000000..e2a70cd1
--- /dev/null
+++ b/src/main/events/rpc/routes/system/window.ts
@@ -0,0 +1,137 @@
+import { app, BrowserWindow } from 'electron'
+
+import windowManager from 'apis/app/window/windowManager'
+
+import {
+ buildMainPageMenu,
+ buildMiniPageMenu,
+ buildPicBedListMenu,
+ buildPluginPageMenu
+} from '~/events/remotes/menu'
+import { openMiniWindow } from '~/utils/windowHelper'
+
+import { IRPCActionType, IWindowList } from '#/types/enum'
+
+export default [
+ {
+ action: IRPCActionType.HIDE_DOCK,
+ handler: async (_: IIPCEvent, args: [value: boolean]) => {
+ args[0] ? app.dock.hide() : app.dock.show()
+ }
+ },
+ {
+ action: IRPCActionType.OPEN_WINDOW,
+ handler: async (_: IIPCEvent, args: [windowName: IWindowList]) => {
+ const window = windowManager.get(args[0])
+ if (window) {
+ window.show()
+ }
+ }
+ },
+ {
+ action: IRPCActionType.OPEN_MANUAL_WINDOW,
+ handler: async () => {
+ windowManager.get(IWindowList.MANUAL_WINDOW)!.show()
+ }
+ },
+ {
+ action: IRPCActionType.OPEN_MINI_WINDOW,
+ handler: async () => {
+ openMiniWindow()
+ }
+ },
+ {
+ action: IRPCActionType.CLOSE_WINDOW,
+ handler: async () => {
+ const window = BrowserWindow.getFocusedWindow()
+ if (process.platform === 'linux') {
+ window?.hide()
+ } else {
+ window?.close()
+ }
+ }
+ },
+ {
+ action: IRPCActionType.MINIMIZE_WINDOW,
+ handler: async () => {
+ const window = BrowserWindow.getFocusedWindow()
+ window?.minimize()
+ }
+ },
+ {
+ action: IRPCActionType.SHOW_MINI_PAGE_MENU,
+ handler: async () => {
+ const window = windowManager.get(IWindowList.MINI_WINDOW)!
+ const menu = buildMiniPageMenu()
+ menu.popup({
+ window
+ })
+ }
+ },
+ {
+ action: IRPCActionType.SHOW_MAIN_PAGE_MENU,
+ handler: async () => {
+ const window = windowManager.get(IWindowList.SETTING_WINDOW)!
+ const menu = buildMainPageMenu(window)
+ menu.popup({
+ window
+ })
+ }
+ },
+ {
+ action: IRPCActionType.SHOW_UPLOAD_PAGE_MENU,
+ handler: async () => {
+ const window = windowManager.get(IWindowList.SETTING_WINDOW)!
+ const menu = buildPicBedListMenu()
+ menu.popup({
+ window
+ })
+ }
+ },
+ {
+ action: IRPCActionType.SHOW_PLUGIN_PAGE_MENU,
+ handler: async (_: IIPCEvent, args: [plugin: IPicGoPlugin]) => {
+ const window = windowManager.get(IWindowList.SETTING_WINDOW)!
+ const menu = buildPluginPageMenu(args[0])
+ menu.popup({
+ window
+ })
+ }
+ },
+ {
+ action: IRPCActionType.SET_MINI_WINDOW_POS,
+ handler: async (_: IIPCEvent, args: [pos: IMiniWindowPos]) => {
+ const window = BrowserWindow.getFocusedWindow()
+ window?.setBounds(args[0])
+ }
+ },
+ {
+ action: IRPCActionType.MINI_WINDOW_ON_TOP,
+ handler: async (_: IIPCEvent, args: [isOnTop: boolean]) => {
+ const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
+ miniWindow.setAlwaysOnTop(args[0])
+ }
+ },
+ {
+ action: IRPCActionType.MAIN_WINDOW_ON_TOP,
+ handler: async () => {
+ const mainWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
+ const isAlwaysOnTop = mainWindow.isAlwaysOnTop()
+ mainWindow.setAlwaysOnTop(!isAlwaysOnTop)
+ }
+ },
+ {
+ action: IRPCActionType.UPDATE_MINI_WINDOW_ICON,
+ handler: async (_: IIPCEvent, args: [iconPath: string]) => {
+ const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
+ miniWindow.webContents.send('updateMiniIcon', args[0])
+ }
+ },
+ {
+ action: IRPCActionType.REFRESH_SETTING_WINDOW,
+ handler: async () => {
+ const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
+ settingWindow.webContents.reloadIgnoringCache()
+ }
+ }
+]
diff --git a/src/main/events/rpc/routes/toolbox/checkProxy.ts b/src/main/events/rpc/routes/toolbox/checkProxy.ts
index b2a0f6b5..5e7b680d 100644
--- a/src/main/events/rpc/routes/toolbox/checkProxy.ts
+++ b/src/main/events/rpc/routes/toolbox/checkProxy.ts
@@ -11,7 +11,7 @@ import { T } from '~/i18n'
import { IToolboxItemCheckStatus, IToolboxItemType } from '#/types/enum'
-const getProxy = (proxyStr: string): AxiosRequestConfig['proxy'] | false => {
+function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null {
if (proxyStr) {
try {
const proxyOptions = new URL(proxyStr)
@@ -20,10 +20,9 @@ const getProxy = (proxyStr: string): AxiosRequestConfig['proxy'] | false => {
port: parseInt(proxyOptions.port || '0', 10),
protocol: proxyOptions.protocol
}
- } catch (e) {
- }
+ } catch (e) {}
}
- return false
+ return null
}
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY)
diff --git a/src/main/events/rpc/routes/toolbox/index.ts b/src/main/events/rpc/routes/toolbox/index.ts
index 934b8155..dfc7db1d 100644
--- a/src/main/events/rpc/routes/toolbox/index.ts
+++ b/src/main/events/rpc/routes/toolbox/index.ts
@@ -3,7 +3,8 @@ import { checkFileMap, fixFileMap } from '~/events/rpc/routes/toolbox/checkFile'
import { checkProxyMap } from '~/events/rpc/routes/toolbox/checkProxy'
import { RPCRouter } from '~/events/rpc/router'
-import { IRPCActionType, IToolboxItemType } from '#/types/enum'
+import { IRPCActionType, IRPCType, IToolboxItemType } from '#/types/enum'
+import { IpcMainEvent } from 'electron'
const toolboxRouter = new RPCRouter()
@@ -19,30 +20,37 @@ const toolboxFixMap: Partial> = {
}
toolboxRouter
- .add(IRPCActionType.TOOLBOX_CHECK, async (args, event) => {
- const [type] = args as IToolboxCheckArgs
- if (type) {
- const handler = toolboxCheckMap[type]
- if (handler) {
- handler(event)
- }
- } else {
- // do check all
- for (const key in toolboxCheckMap) {
- const handler = toolboxCheckMap[key as IToolboxItemType]
+ .add(
+ IRPCActionType.TOOLBOX_CHECK,
+ async (event, args) => {
+ const [type] = args as IToolboxCheckArgs
+ if (type) {
+ const handler = toolboxCheckMap[type]
if (handler) {
- handler(event)
+ handler(event as IpcMainEvent)
+ }
+ } else {
+ // do check all
+ for (const key in toolboxCheckMap) {
+ const handler = toolboxCheckMap[key as IToolboxItemType]
+ if (handler) {
+ handler(event as IpcMainEvent)
+ }
}
}
- }
- })
- .add(IRPCActionType.TOOLBOX_CHECK_FIX, async (args, event) => {
- const [type] = args as IToolboxCheckArgs
- const handler = toolboxFixMap[type]
- if (handler) {
- return await handler(event)
- }
- })
+ },
+ IRPCType.SEND
+ )
+ .add(
+ IRPCActionType.TOOLBOX_CHECK_FIX, async (event, args) => {
+ const [type] = args as IToolboxCheckArgs
+ const handler = toolboxFixMap[type]
+ if (handler) {
+ return await handler(event as IpcMainEvent)
+ }
+ },
+ IRPCType.INVOKE
+ )
export {
toolboxRouter
diff --git a/src/main/events/rpc/routes/toolbox/utils.ts b/src/main/events/rpc/routes/toolbox/utils.ts
index 7b8a18b1..4cb34285 100644
--- a/src/main/events/rpc/routes/toolbox/utils.ts
+++ b/src/main/events/rpc/routes/toolbox/utils.ts
@@ -1,9 +1,11 @@
import { IpcMainEvent } from 'electron'
import { IRPCActionType, IToolboxItemType } from '#/types/enum'
-export const sendToolboxResWithType = (type: IToolboxItemType) => (event: IpcMainEvent, res?: Omit) => {
- return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, {
- ...res,
- type
- })
+export function sendToolboxResWithType (type: IToolboxItemType) {
+ return (event: IpcMainEvent, res?: Omit) => {
+ return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, {
+ ...res,
+ type
+ })
+ }
}
diff --git a/src/main/events/rpc/routes/tray/index.ts b/src/main/events/rpc/routes/tray/index.ts
new file mode 100644
index 00000000..40906dc9
--- /dev/null
+++ b/src/main/events/rpc/routes/tray/index.ts
@@ -0,0 +1,71 @@
+import {
+ Notification
+} from 'electron'
+
+import { RPCRouter } from '~/events/rpc/router'
+import { generateShortUrl, setTrayToolTip, handleCopyUrl } from '~/utils/common'
+
+import { IRPCActionType, IRPCType, IPasteStyle, IWindowList } from '#/types/enum'
+
+import db, { GalleryDB } from '@core/datastore'
+
+import uploader from 'apis/app/uploader'
+import windowManager from 'apis/app/window/windowManager'
+
+import { T } from '~/i18n'
+
+import pasteTemplate from '~/utils/pasteTemplate'
+
+import { configPaths } from '#/utils/configPaths'
+
+const trayRouter = new RPCRouter()
+
+const trayRoutes = [
+ {
+ action: IRPCActionType.TRAY_SET_TOOL_TIP,
+ handler: async (_: IIPCEvent, args: [text: string]) => {
+ setTrayToolTip(args[0])
+ }
+ },
+ {
+ action: IRPCActionType.TRAY_GET_SHORT_URL,
+ handler: async (_: IIPCEvent, args: [url: string]) => {
+ return await generateShortUrl(args[0])
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.TRAY_UPLOAD_CLIPBOARD_FILES,
+ handler: async () => {
+ const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
+ // macOS use builtin clipboard is OK
+ const img = await uploader.setWebContents(trayWindow.webContents).uploadWithBuildInClipboard()
+ if (img !== false) {
+ const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
+ handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))))
+ const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
+ if (isShowResultNotification) {
+ const notification = new Notification({
+ title: T('UPLOAD_SUCCEED'),
+ body: img[0].imgUrl!
+ // icon: file[0]
+ // icon: img[0].imgUrl
+ })
+ notification.show()
+ }
+ await GalleryDB.getInstance().insert(img[0])
+ trayWindow.webContents.send('clipboardFiles', [])
+ if (windowManager.has(IWindowList.SETTING_WINDOW)) {
+ windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
+ }
+ }
+ trayWindow.webContents.send('uploadFiles')
+ }
+ }
+]
+
+trayRouter.addBatch(trayRoutes)
+
+export {
+ trayRouter
+}
diff --git a/src/main/events/rpc/routes/upload/index.ts b/src/main/events/rpc/routes/upload/index.ts
new file mode 100644
index 00000000..740f7cb3
--- /dev/null
+++ b/src/main/events/rpc/routes/upload/index.ts
@@ -0,0 +1,35 @@
+import { RPCRouter } from '~/events/rpc/router'
+import getPicBeds from '~/utils/getPicBeds'
+import { uploadChoosedFiles, uploadClipboardFiles } from '~/apis/app/uploader/apis'
+
+import { IRPCActionType, IRPCType } from '#/types/enum'
+
+const uploadRouter = new RPCRouter()
+
+const uploadRoutes = [
+ {
+ action: IRPCActionType.MAIN_GET_PICBED,
+ handler: async () => {
+ return getPicBeds()
+ },
+ type: IRPCType.INVOKE
+ },
+ {
+ action: IRPCActionType.UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE,
+ handler: async () => {
+ uploadClipboardFiles()
+ }
+ },
+ {
+ action: IRPCActionType.UPLOAD_CHOOSED_FILES,
+ handler: async (evt: IIPCEvent, args: [files: IFileWithPath[]]) => {
+ return uploadChoosedFiles(evt.sender, args[0])
+ }
+ }
+]
+
+uploadRouter.addBatch(uploadRoutes)
+
+export {
+ uploadRouter
+}
diff --git a/src/main/fileServer/index.ts b/src/main/fileServer/index.ts
index b6701986..06ec7ca1 100644
--- a/src/main/fileServer/index.ts
+++ b/src/main/fileServer/index.ts
@@ -10,8 +10,10 @@ fs.ensureDirSync(imgFilePath)
const serverPort = 36699
+let server: http.Server
+
export function startFileServer () {
- const server = http.createServer((req, res) => {
+ server = http.createServer((req, res) => {
const requestPath = req.url?.split('?')[0]
const filePath = path.join(imgFilePath, decodeURIComponent(requestPath as string))
@@ -31,3 +33,9 @@ export function startFileServer () {
logger.error(err)
})
}
+
+export function stopFileServer () {
+ server.close(() => {
+ logger.info('File server is stopped')
+ })
+}
diff --git a/src/main/lifeCycle/index.ts b/src/main/lifeCycle/index.ts
index 169c7bd3..ccba9f7d 100644
--- a/src/main/lifeCycle/index.ts
+++ b/src/main/lifeCycle/index.ts
@@ -32,8 +32,7 @@ import {
import windowManager from 'apis/app/window/windowManager'
import busEventList from '~/events/busEventList'
-import ipcList from '~/events/ipcList'
-import { startFileServer } from '~/fileServer'
+import { startFileServer, stopFileServer } from '~/fileServer'
import { T } from '~/i18n'
import '~/lifeCycle/errorHandler'
import fixPath from '~/lifeCycle/fixPath'
@@ -52,6 +51,7 @@ import updateChecker from '~/utils/updateChecker'
import { II18nLanguage, IRemoteNoticeTriggerHook, ISartMode, IWindowList } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import { CLIPBOARD_IMAGE_FOLDER } from '#/utils/static'
+import { rpcServer } from '~/events/rpc'
const isDevelopment = process.env.NODE_ENV !== 'production'
@@ -146,7 +146,7 @@ class LifeCycle {
fixPath()
beforeOpen()
initI18n()
- ipcList.listen()
+ rpcServer.start()
getManageApi()
UpDownTaskQueue.getInstance()
manageIpcList.listen()
@@ -285,6 +285,8 @@ class LifeCycle {
globalShortcut.unregisterAll()
bus.removeAllListeners()
server.shutdown()
+ webServer.stop()
+ stopFileServer()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
diff --git a/src/main/manage/events/manageCoreIPC.ts b/src/main/manage/events/manageCoreIPC.ts
index 9ed27b09..04b48f56 100644
--- a/src/main/manage/events/manageCoreIPC.ts
+++ b/src/main/manage/events/manageCoreIPC.ts
@@ -1,5 +1,6 @@
import {
IpcMainEvent,
+ IpcMainInvokeEvent,
ipcMain
} from 'electron'
@@ -9,20 +10,19 @@ import { PICLIST_MANAGE_GET_CONFIG, PICLIST_MANAGE_SAVE_CONFIG, PICLIST_MANAGE_R
const manageApi = getManageApi()
const handleManageGetConfig = () => {
- ipcMain.on(PICLIST_MANAGE_GET_CONFIG, (event: IpcMainEvent, key: string | undefined, callbackId: string) => {
- const result = manageApi.getConfig(key)
- event.sender.send(PICLIST_MANAGE_GET_CONFIG, result, callbackId)
+ ipcMain.handle(PICLIST_MANAGE_GET_CONFIG, (_: IpcMainInvokeEvent, key: string | undefined) => {
+ return manageApi.getConfig(key)
})
}
const handleManageSaveConfig = () => {
- ipcMain.on(PICLIST_MANAGE_SAVE_CONFIG, (_event: IpcMainEvent, data: any) => {
+ ipcMain.on(PICLIST_MANAGE_SAVE_CONFIG, (_: IpcMainEvent, data: any) => {
manageApi.saveConfig(data)
})
}
const handleManageRemoveConfig = () => {
- ipcMain.on(PICLIST_MANAGE_REMOVE_CONFIG, (_event: IpcMainEvent, key: string, propName: string) => {
+ ipcMain.on(PICLIST_MANAGE_REMOVE_CONFIG, (_: IpcMainEvent, key: string, propName: string) => {
manageApi.removeConfig(key, propName)
})
}
diff --git a/src/main/server/routerManager.ts b/src/main/server/routerManager.ts
index 0a912273..34b7495f 100644
--- a/src/main/server/routerManager.ts
+++ b/src/main/server/routerManager.ts
@@ -11,12 +11,13 @@ import logger from '@core/picgo/logger'
import { AESHelper } from '~/utils/aesHelper'
import { changeCurrentUploader } from '~/utils/handleUploaderConfig'
-import { uploadChoosedFiles, uploadClipboardFiles, deleteChoosedFiles } from 'apis/app/uploader/apis'
+import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis'
import windowManager from 'apis/app/window/windowManager'
import { markdownContent } from '~/server/apiDoc'
import router from '~/server/router'
import {
+ deleteChoosedFiles,
handleResponse
} from '~/server/utils'
diff --git a/src/main/server/utils.ts b/src/main/server/utils.ts
index ba6c4e7c..b1f6de89 100644
--- a/src/main/server/utils.ts
+++ b/src/main/server/utils.ts
@@ -1,4 +1,20 @@
+import {
+ Notification
+} from 'electron'
+
+import picgo from '@core/picgo'
import logger from '@core/picgo/logger'
+import db, { GalleryDB } from '@core/datastore'
+
+import windowManager from 'apis/app/window/windowManager'
+
+import GuiApi from '~/apis/gui'
+import { T } from '~/i18n/index'
+import { configPaths } from '#/utils/configPaths'
+import { picBedsCanbeDeleted } from '#/utils/static'
+import { ICOREBuildInEvent, IWindowList } from '#/types/enum'
+
+import ALLApi from '@/apis/allApi'
export const handleResponse = ({
response,
@@ -31,3 +47,43 @@ export const ensureHTTPLink = (url: string): string => {
? url
: `http://${url}`
}
+
+export const deleteChoosedFiles = async (list: ImgInfo[]): Promise => {
+ const result = []
+ for (const item of list) {
+ if (item.id) {
+ try {
+ const dbStore = GalleryDB.getInstance()
+ const file = await dbStore.getById(item.id)
+ await dbStore.removeById(item.id)
+ if (await db.get(configPaths.settings.deleteCloudFile)) {
+ if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
+ const noteFunc = (value: boolean) => {
+ const notification = new Notification({
+ title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
+ body: T(value
+ ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED'
+ : 'GALLERY_SYNC_DELETE_NOTICE_FAILED'
+ )
+ })
+ notification.show()
+ }
+ setTimeout(() => {
+ ALLApi.delete(item).then(noteFunc)
+ }, 0)
+ }
+ }
+ setTimeout(() => {
+ picgo.emit(ICOREBuildInEvent.REMOVE, [file], GuiApi.getInstance())
+ }, 500)
+ result.push(true)
+ } catch (e) {
+ result.push(false)
+ }
+ }
+ }
+ if (windowManager.has(IWindowList.SETTING_WINDOW)) {
+ windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
+ }
+ return result
+}
diff --git a/src/main/utils/deleteFunc.ts b/src/main/utils/deleteFunc.ts
index efd3b1be..078abe43 100644
--- a/src/main/utils/deleteFunc.ts
+++ b/src/main/utils/deleteFunc.ts
@@ -2,10 +2,13 @@ import axios from 'axios'
import crypto from 'crypto'
import http, { AgentOptions } from 'http'
import https from 'https'
+import path from 'path'
+import { ISftpPlistConfig } from 'piclist'
import querystring from 'querystring'
import { S3Client, DeleteObjectCommand, S3ClientConfig } from '@aws-sdk/client-s3'
import { NodeHttpHandler } from '@smithy/node-http-handler'
+import SSHClient from '~/utils/sshClient'
import { getAgent } from '~/manage/utils/common'
interface DogecloudTokenFull {
@@ -219,3 +222,18 @@ export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
return false
}
}
+
+export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileName: string) {
+ try {
+ const client = SSHClient.instance
+ await client.connect(config)
+ const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/')
+ const remote = path.join(uploadPath, fileName)
+ const deleteResult = await client.deleteFileSFTP(config, remote)
+ client.close()
+ return deleteResult
+ } catch (err: any) {
+ console.log(err)
+ return false
+ }
+}
diff --git a/src/main/utils/windowHelper.ts b/src/main/utils/windowHelper.ts
new file mode 100644
index 00000000..37175c47
--- /dev/null
+++ b/src/main/utils/windowHelper.ts
@@ -0,0 +1,56 @@
+import { screen } from 'electron'
+
+import db from '@core/datastore'
+
+import windowManager from 'apis/app/window/windowManager'
+
+import { IWindowList } from '#/types/enum'
+import { configPaths } from '#/utils/configPaths'
+
+export function openMiniWindow (hideSettingWindow:boolean = true) {
+ const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
+ miniWindow.removeAllListeners()
+ if (db.get(configPaths.settings.miniWindowOntop)) {
+ miniWindow.setAlwaysOnTop(true)
+ }
+ const { width, height } = screen.getPrimaryDisplay().workAreaSize
+ const lastPosition = db.get(configPaths.settings.miniWindowPosition)
+ if (lastPosition) {
+ miniWindow.setPosition(lastPosition[0], lastPosition[1])
+ } else {
+ miniWindow.setPosition(width - 100, height - 100)
+ }
+ const setPositionFunc = () => {
+ const position = miniWindow.getPosition()
+ db.set(configPaths.settings.miniWindowPosition, position)
+ }
+ miniWindow.on('close', setPositionFunc)
+ miniWindow.on('move', setPositionFunc)
+ miniWindow.show()
+ miniWindow.focus()
+ if (hideSettingWindow) {
+ const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
+ settingWindow.hide()
+ } else {
+ const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
+ if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
+ windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
+ }
+ }
+}
+
+export const openMainWindow = () => {
+ const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
+ const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
+ settingWindow!.show()
+ settingWindow!.focus()
+ if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
+ windowManager.get(IWindowList.MINI_WINDOW)!.hide()
+ }
+}
+
+export const hideMiniWindow = () => {
+ if (windowManager.has(IWindowList.MINI_WINDOW)) {
+ windowManager.get(IWindowList.MINI_WINDOW)!.hide()
+ }
+}
diff --git a/src/renderer/App.vue b/src/renderer/App.vue
index de9c3739..5cb84e4f 100644
--- a/src/renderer/App.vue
+++ b/src/renderer/App.vue
@@ -17,6 +17,7 @@ import { FORCE_UPDATE } from '#/events/constants'
useATagClick()
const store = useStore()
+
onBeforeMount(async () => {
const config = await getConfig()
if (config) {
diff --git a/src/renderer/apis/alist.ts b/src/renderer/apis/alist.ts
index 99426e72..e70be769 100644
--- a/src/renderer/apis/alist.ts
+++ b/src/renderer/apis/alist.ts
@@ -1,7 +1,7 @@
import axios from 'axios'
import path from 'path'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string
diff --git a/src/renderer/apis/aliyun.ts b/src/renderer/apis/aliyun.ts
index 495c6420..c02dcbb5 100644
--- a/src/renderer/apis/aliyun.ts
+++ b/src/renderer/apis/aliyun.ts
@@ -1,6 +1,6 @@
import OSS from 'ali-oss'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string
diff --git a/src/renderer/apis/awss3.ts b/src/renderer/apis/awss3.ts
index aaa4563f..5b4a3a5f 100644
--- a/src/renderer/apis/awss3.ts
+++ b/src/renderer/apis/awss3.ts
@@ -1,15 +1,15 @@
import { ipcRenderer } from 'electron'
-import { deleteFailedLog, getRawData } from '@/utils/common'
+import { getRawData, triggerRPC } from '@/utils/common'
import { removeFileFromS3InMain } from '~/utils/deleteFunc'
+import { deleteFailedLog } from '#/utils/deleteLog'
+import { IRPCActionType } from '#/types/enum'
export default class AwsS3Api {
static async delete (configMap: IStringKeyMap): Promise {
try {
return ipcRenderer
- ? await ipcRenderer.invoke('delete-aws-s3-file',
- getRawData(configMap)
- )
+ ? await triggerRPC(IRPCActionType.GALLERY_DELETE_AWS_S3_FILE, getRawData(configMap)) || false
: await removeFileFromS3InMain(getRawData(configMap))
} catch (error: any) {
deleteFailedLog(configMap.fileName, 'AWS S3', error)
diff --git a/src/renderer/apis/dogecloud.ts b/src/renderer/apis/dogecloud.ts
index 796303c1..2e4796f3 100644
--- a/src/renderer/apis/dogecloud.ts
+++ b/src/renderer/apis/dogecloud.ts
@@ -1,15 +1,16 @@
import { ipcRenderer } from 'electron'
-import { deleteFailedLog, getRawData } from '@/utils/common'
import { removeFileFromDogeInMain } from '~/utils/deleteFunc'
+import { getRawData, triggerRPC } from '@/utils/common'
+import { deleteFailedLog } from '#/utils/deleteLog'
+import { IRPCActionType } from '#/types/enum'
+
export default class AwsS3Api {
static async delete (configMap: IStringKeyMap): Promise {
try {
return ipcRenderer
- ? await ipcRenderer.invoke('delete-doge-file',
- getRawData(configMap)
- )
+ ? await triggerRPC(IRPCActionType.GALLERY_DELETE_DOGE_FILE, getRawData(configMap)) || false
: await removeFileFromDogeInMain(getRawData(configMap))
} catch (error: any) {
deleteFailedLog(configMap.fileName, 'DogeCloud', error)
diff --git a/src/renderer/apis/github.ts b/src/renderer/apis/github.ts
index 6c848110..70091dc4 100644
--- a/src/renderer/apis/github.ts
+++ b/src/renderer/apis/github.ts
@@ -1,6 +1,6 @@
import { Octokit } from '@octokit/rest'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string
diff --git a/src/renderer/apis/huaweiyun.ts b/src/renderer/apis/huaweiyun.ts
index c840c119..5499e7a0 100644
--- a/src/renderer/apis/huaweiyun.ts
+++ b/src/renderer/apis/huaweiyun.ts
@@ -1,15 +1,16 @@
import { ipcRenderer } from 'electron'
-import { deleteFailedLog, getRawData } from '@/utils/common'
import { removeFileFromHuaweiInMain } from '~/utils/deleteFunc'
+import { getRawData, triggerRPC } from '@/utils/common'
+import { deleteFailedLog } from '#/utils/deleteLog'
+import { IRPCActionType } from '#/types/enum'
+
export default class HuaweicloudApi {
static async delete (configMap: IStringKeyMap): Promise {
try {
return ipcRenderer
- ? await ipcRenderer.invoke('delete-huaweicloud-file',
- getRawData(configMap)
- )
+ ? await triggerRPC(IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE, getRawData(configMap)) || false
: await removeFileFromHuaweiInMain(getRawData(configMap))
} catch (error: any) {
deleteFailedLog(configMap.fileName, 'HuaweiCloud', error)
diff --git a/src/renderer/apis/imgur.ts b/src/renderer/apis/imgur.ts
index 1167e246..4c980775 100644
--- a/src/renderer/apis/imgur.ts
+++ b/src/renderer/apis/imgur.ts
@@ -1,6 +1,6 @@
import axios, { AxiosResponse } from 'axios'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
config?: Partial
diff --git a/src/renderer/apis/local.ts b/src/renderer/apis/local.ts
index 6951044a..1f08a5c3 100644
--- a/src/renderer/apis/local.ts
+++ b/src/renderer/apis/local.ts
@@ -1,6 +1,6 @@
import fs from 'fs-extra'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
hash: string
diff --git a/src/renderer/apis/lskyplist.ts b/src/renderer/apis/lskyplist.ts
index a2e65432..e0404e33 100644
--- a/src/renderer/apis/lskyplist.ts
+++ b/src/renderer/apis/lskyplist.ts
@@ -1,7 +1,7 @@
import axios, { AxiosResponse } from 'axios'
import https from 'https'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
export default class LskyplistApi {
static async delete (configMap: IStringKeyMap): Promise {
diff --git a/src/renderer/apis/piclist.ts b/src/renderer/apis/piclist.ts
index eb9e93db..26a5607c 100644
--- a/src/renderer/apis/piclist.ts
+++ b/src/renderer/apis/piclist.ts
@@ -1,6 +1,6 @@
import axios, { AxiosResponse } from 'axios'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
export default class PiclistApi {
static async delete (configMap: IStringKeyMap): Promise {
diff --git a/src/renderer/apis/qiniu.ts b/src/renderer/apis/qiniu.ts
index 4e619da3..12fa90e1 100644
--- a/src/renderer/apis/qiniu.ts
+++ b/src/renderer/apis/qiniu.ts
@@ -1,6 +1,6 @@
import Qiniu from 'qiniu'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string
diff --git a/src/renderer/apis/sftpplist.ts b/src/renderer/apis/sftpplist.ts
index 381a4b99..60a17d66 100644
--- a/src/renderer/apis/sftpplist.ts
+++ b/src/renderer/apis/sftpplist.ts
@@ -1,16 +1,19 @@
import { ipcRenderer } from 'electron'
-import { deleteFailedLog, getRawData } from '@/utils/common'
+import { removeFileFromSFTPInMain } from '~/utils/deleteFunc'
+
+import { getRawData, triggerRPC } from '@/utils/common'
+import { deleteFailedLog } from '#/utils/deleteLog'
+import { IRPCActionType } from '#/types/enum'
export default class SftpPlistApi {
static async delete (configMap: IStringKeyMap): Promise {
const { fileName, config } = configMap
try {
- const deleteResult = await ipcRenderer.invoke('delete-sftp-file',
- getRawData(config),
- fileName
- )
- return deleteResult
+ return ipcRenderer
+ ? await triggerRPC(IRPCActionType.GALLERY_DELETE_SFTP_FILE, getRawData(config),
+ fileName) || false
+ : await removeFileFromSFTPInMain(getRawData(config), fileName)
} catch (error: any) {
deleteFailedLog(fileName, 'SFTP', error)
return false
diff --git a/src/renderer/apis/smms.ts b/src/renderer/apis/smms.ts
index b99a578a..bd21fb4a 100644
--- a/src/renderer/apis/smms.ts
+++ b/src/renderer/apis/smms.ts
@@ -1,6 +1,6 @@
import axios, { AxiosResponse } from 'axios'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
hash?: string
diff --git a/src/renderer/apis/tcyun.ts b/src/renderer/apis/tcyun.ts
index bb348618..1026e20e 100644
--- a/src/renderer/apis/tcyun.ts
+++ b/src/renderer/apis/tcyun.ts
@@ -1,6 +1,6 @@
import COS from 'cos-nodejs-sdk-v5'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string
diff --git a/src/renderer/apis/upyun.ts b/src/renderer/apis/upyun.ts
index 9858aabe..a2283bfc 100644
--- a/src/renderer/apis/upyun.ts
+++ b/src/renderer/apis/upyun.ts
@@ -1,6 +1,6 @@
import Upyun from 'upyun'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string
diff --git a/src/renderer/apis/webdav.ts b/src/renderer/apis/webdav.ts
index 1afbd4e1..c7ef4803 100644
--- a/src/renderer/apis/webdav.ts
+++ b/src/renderer/apis/webdav.ts
@@ -1,7 +1,6 @@
import { AuthType, WebDAVClientOptions, createClient } from 'webdav'
-import { deleteFailedLog, deleteLog } from '@/utils/common'
-
+import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
import { formatEndpoint } from '#/utils/common'
interface IConfigMap {
diff --git a/src/renderer/hooks/useATagClick.ts b/src/renderer/hooks/useATagClick.ts
index b5d195dc..8b6f42b7 100644
--- a/src/renderer/hooks/useATagClick.ts
+++ b/src/renderer/hooks/useATagClick.ts
@@ -1,13 +1,14 @@
import { onMounted, onUnmounted } from 'vue'
-import { openURL } from '@/utils/common'
+import { sendRPC } from '@/utils/common'
+import { IRPCActionType } from 'root/src/universal/types/enum'
export function useATagClick () {
const handleATagClick = (e: MouseEvent) => {
if (e.target instanceof HTMLAnchorElement) {
if (e.target.href) {
e.preventDefault()
- openURL(e.target.href)
+ sendRPC(IRPCActionType.OPEN_URL, e.target.href)
}
}
}
diff --git a/src/renderer/i18n/index.ts b/src/renderer/i18n/index.ts
index 6c6338b1..1cc80e7b 100644
--- a/src/renderer/i18n/index.ts
+++ b/src/renderer/i18n/index.ts
@@ -2,23 +2,34 @@ import { ipcRenderer } from 'electron'
import { ObjectAdapter, I18n } from '@picgo/i18n'
import bus from '@/utils/bus'
+import { sendRPC } from '@/utils/common'
import { GET_CURRENT_LANGUAGE, SET_CURRENT_LANGUAGE, FORCE_UPDATE, GET_LANGUAGE_LIST } from '#/events/constants'
import { builtinI18nList } from '#/i18n'
+import { IRPCActionType } from '#/types/enum'
export class I18nManager {
#i18n: I18n | null = null
#i18nFileList: II18nItem[] = builtinI18nList
+ constructor () {
+ this.#getCurrentLanguage()
+ this.#getLanguageList()
+ ipcRenderer.on(SET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
+ this.#setLocales(lang, locales)
+ bus.emit(FORCE_UPDATE)
+ })
+ }
+
#getLanguageList () {
- ipcRenderer.send(GET_LANGUAGE_LIST)
+ sendRPC(IRPCActionType.GET_LANGUAGE_LIST)
ipcRenderer.once(GET_LANGUAGE_LIST, (_, list: II18nItem[]) => {
this.#i18nFileList = list
})
}
#getCurrentLanguage () {
- ipcRenderer.send(GET_CURRENT_LANGUAGE)
+ sendRPC(IRPCActionType.GET_CURRENT_LANGUAGE)
ipcRenderer.once(GET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
this.#setLocales(lang, locales)
bus.emit(FORCE_UPDATE)
@@ -35,21 +46,12 @@ export class I18nManager {
})
}
- constructor () {
- this.#getCurrentLanguage()
- this.#getLanguageList()
- ipcRenderer.on(SET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
- this.#setLocales(lang, locales)
- bus.emit(FORCE_UPDATE)
- })
- }
-
T (key: ILocalesKey, args: IStringKeyMap = {}): string {
return this.#i18n?.translate(key, args) || key
}
setCurrentLanguage (lang: string) {
- ipcRenderer.send(SET_CURRENT_LANGUAGE, lang)
+ sendRPC(IRPCActionType.SET_CURRENT_LANGUAGE, lang)
}
get languageList () {
diff --git a/src/renderer/layouts/Main.vue b/src/renderer/layouts/Main.vue
index 857f5b45..ba72bf86 100644
--- a/src/renderer/layouts/Main.vue
+++ b/src/renderer/layouts/Main.vue
@@ -7,7 +7,7 @@
PicList - {{ version }}
@@ -101,7 +100,7 @@
{{ $T('PICBEDS_SETTINGS') }}
= ref([])
const qrcodeVisible = ref(false)
const picBedConfigString = ref('')
const choosedPicBedForQRCode: Ref = ref([])
@@ -277,10 +271,7 @@ const isShowprogress = ref(false)
const progress = ref(0)
onBeforeMount(() => {
- os.value = process.platform
- sendToMain(GET_PICBEDS)
- ipcRenderer.on(GET_PICBEDS, getPicBeds)
- handleGetPicPeds()
+ updatePicBedGlobal()
ipcRenderer.on(SHOW_MAIN_PAGE_QRCODE, () => {
qrcodeVisible.value = true
})
@@ -300,17 +291,13 @@ watch(() => choosedPicBedForQRCode, (val) => {
}
}, { deep: true })
-const handleGetPicPeds = () => {
- sendToMain(GET_PICBEDS)
-}
-
const handleSelect = async (index: string) => {
defaultActive.value = index
if (index === routerConfig.DocumentPage) {
const manualPageOpenSetting = await getConfig(configPaths.settings.manualPageOpen)
const lang = await getConfig(configPaths.settings.language) || II18nLanguage.ZH_CN
- const openManual = () => ipcRenderer.send('openManualWindow')
- const openExternal = () => openURL(lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html')
+ const openManual = () => sendRPC(IRPCActionType.OPEN_MANUAL_WINDOW)
+ const openExternal = () => sendRPC(IRPCActionType.OPEN_URL, lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html')
if (!manualPageOpenSetting) {
ElMessageBox.confirm($T('MANUAL_PAGE_OPEN_TIP'), $T('MANUAL_PAGE_OPEN_TIP_TITLE'), {
@@ -347,19 +334,19 @@ const handleSelect = async (index: string) => {
}
function minimizeWindow () {
- sendToMain(MINIMIZE_WINDOW)
+ sendRPC(IRPCActionType.MINIMIZE_WINDOW)
}
function closeWindow () {
- sendToMain(CLOSE_WINDOW)
+ sendRPC(IRPCActionType.CLOSE_WINDOW)
}
function openMenu () {
- sendToMain(SHOW_MAIN_PAGE_MENU)
+ sendRPC(IRPCActionType.SHOW_MAIN_PAGE_MENU)
}
function openMiniWindow () {
- sendToMain('openMiniWindow')
+ sendRPC(IRPCActionType.OPEN_MINI_WINDOW)
}
function handleCopyPicBedConfig () {
@@ -367,13 +354,9 @@ function handleCopyPicBedConfig () {
$message.success($T('COPY_PICBED_CONFIG_SUCCEED'))
}
-function getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
- picBed.value = picBeds
-}
-
function setAlwaysOnTop () {
isAlwaysOnTop.value = !isAlwaysOnTop.value
- sendToMain('toggleMainWindowAlwaysOnTop', isAlwaysOnTop.value)
+ sendRPC(IRPCActionType.MAIN_WINDOW_ON_TOP)
}
onBeforeRouteUpdate(async (to) => {
@@ -385,7 +368,6 @@ onBeforeRouteUpdate(async (to) => {
})
onBeforeUnmount(() => {
- ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
ipcRenderer.removeAllListeners(SHOW_MAIN_PAGE_QRCODE)
ipcRenderer.removeAllListeners('updateProgress')
})
diff --git a/src/renderer/manage/pages/logIn.vue b/src/renderer/manage/pages/LogInPage.vue
similarity index 100%
rename from src/renderer/manage/pages/logIn.vue
rename to src/renderer/manage/pages/LogInPage.vue
diff --git a/src/renderer/manage/utils/dataSender.ts b/src/renderer/manage/utils/dataSender.ts
index 3cfce67a..2434fdb9 100644
--- a/src/renderer/manage/utils/dataSender.ts
+++ b/src/renderer/manage/utils/dataSender.ts
@@ -1,34 +1,16 @@
-import { ipcRenderer, IpcRendererEvent } from 'electron'
-import { v4 as uuid } from 'uuid'
+import { ipcRenderer } from 'electron'
import { getRawData } from '@/utils/common'
import { PICLIST_MANAGE_GET_CONFIG, PICLIST_MANAGE_SAVE_CONFIG, PICLIST_MANAGE_REMOVE_CONFIG } from '~/manage/events/constants'
-export function getConfig (key?: string): Promise {
- return new Promise((resolve) => {
- const callbackId = uuid()
- const callback = (_: IpcRendererEvent, config: T | undefined, returnCallbackId: string) => {
- if (returnCallbackId === callbackId) {
- resolve(config)
- ipcRenderer.removeListener(PICLIST_MANAGE_GET_CONFIG, callback)
- }
- }
- ipcRenderer.on(PICLIST_MANAGE_GET_CONFIG, callback)
- ipcRenderer.send(PICLIST_MANAGE_GET_CONFIG, key, callbackId)
- })
+export function saveConfig (config: IObj | string, value?: any) {
+ const configObj = typeof config === 'string' ? { [config]: value } : getRawData(config)
+ ipcRenderer.send(PICLIST_MANAGE_SAVE_CONFIG, configObj)
}
-export function saveConfig (_config: IObj | string, value?: any) {
- let config
- if (typeof _config === 'string') {
- config = {
- [_config]: value
- }
- } else {
- config = getRawData(_config)
- }
- ipcRenderer.send(PICLIST_MANAGE_SAVE_CONFIG, config)
+export async function getConfig (key?: string): Promise {
+ return await ipcRenderer.invoke(PICLIST_MANAGE_GET_CONFIG, key)
}
export function removeConfig (key: string, propName: string) {
diff --git a/src/renderer/pages/Gallery.vue b/src/renderer/pages/Gallery.vue
index 26a379ab..a3a510b2 100644
--- a/src/renderer/pages/Gallery.vue
+++ b/src/renderer/pages/Gallery.vue
@@ -68,7 +68,7 @@
teleported
>
import {
ipcRenderer,
- clipboard,
- IpcRendererEvent
+ clipboard
} from 'electron'
import { CheckboxValueType, ElMessageBox, ElNotification, ElMessage } from 'element-plus'
import { InfoFilled, Close, CaretBottom, Document, Edit, Delete, CaretTop, Sort, Refresh } from '@element-plus/icons-vue'
@@ -475,14 +474,14 @@ import type { IResult } from '@picgo/store/dist/types'
import ALLApi from '@/apis/allApi'
import { T as $T } from '@/i18n/index'
import { customRenameFormatTable, customStrMatch, customStrReplace } from '@/manage/utils/common'
-import { sendToMain } from '@/utils/common'
+import { sendRPC, triggerRPC } from '@/utils/common'
import { getConfig, saveConfig } from '@/utils/dataSender'
import $$db from '@/utils/db'
+import { picBedGlobal } from '@/utils/global'
-import { PASTE_TEXT, GET_PICBEDS } from '#/events/constants'
import { configPaths } from '#/utils/configPaths'
import { picBedsCanbeDeleted } from '#/utils/static'
-import { IPasteStyle } from '#/types/enum'
+import { IPasteStyle, IRPCActionType } from '#/types/enum'
const images = ref([])
const dialogVisible = ref(false)
@@ -529,7 +528,6 @@ const mathcedCount = computed(() => {
return matchedFiles.length
})
const dateRange = ref('')
-const picBed = ref([])
onBeforeRouteUpdate((to, from) => {
if (from.name === 'gallery') {
clearChoosedList()
@@ -551,8 +549,6 @@ onBeforeMount(async () => {
updateGallery()
})
})
- sendToMain(GET_PICBEDS)
- ipcRenderer.on(GET_PICBEDS, getPicBeds)
updateGallery()
document.addEventListener('keydown', handleDetectShiftKey)
@@ -588,10 +584,6 @@ function formatFileName (name: string) {
return path.basename(name)
}
-function getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
- picBed.value = picBeds
-}
-
function getGallery (): IGalleryItem[] {
if (searchText.value || choosedPicBed.value.length > 0 || searchTextURL.value || dateRange.value) {
return images.value
@@ -636,7 +628,7 @@ function getGallery (): IGalleryItem[] {
}
async function updateGallery () {
- images.value = (await $$db.get({ orderBy: 'desc' })).data
+ images.value = (await $$db.get({ orderBy: 'desc' }))!.data
}
watch(() => filterList, () => {
@@ -659,7 +651,7 @@ function handleChooseImage (val: CheckboxValueType, index: number) {
}
function refreshPage () {
- ipcRenderer.send('refreshSettingWindow')
+ sendRPC(IRPCActionType.REFRESH_SETTING_WINDOW)
}
function clearChoosedList () {
@@ -694,7 +686,7 @@ function handleClose () {
async function copy (item: ImgInfo) {
item.config = JSON.parse(JSON.stringify(item.config) || '{}')
- const copyLink = await ipcRenderer.invoke(PASTE_TEXT, item)
+ const copyLink = await triggerRPC(IRPCActionType.GALLERY_PASTE_TEXT, item)
const obj = {
title: $T('COPY_LINK_SUCCEED'),
body: copyLink
@@ -733,7 +725,7 @@ function remove (item: ImgInfo) {
}
}
await $$db.removeById(item.id!)
- sendToMain('removeFiles', [file])
+ sendRPC(IRPCActionType.GALLERY_REMOVE_FILES, [file])
const obj = {
title: $T('OPERATION_SUCCEED'),
body: ''
@@ -858,7 +850,7 @@ function multiRemove () {
title: $T('OPERATION_SUCCEED'),
body: ''
}
- sendToMain('removeFiles', files)
+ sendRPC(IRPCActionType.GALLERY_REMOVE_FILES, files)
const myNotification = new Notification(obj.title, obj)
myNotification.onclick = () => {
return true
@@ -880,8 +872,8 @@ async function multiCopy () {
if (choosedList[key]) {
const item = await $$db.getById(key)
if (item) {
- const txt = await ipcRenderer.invoke(PASTE_TEXT, item)
- copyString.push(txt)
+ const txt = await triggerRPC(IRPCActionType.GALLERY_PASTE_TEXT, item)
+ copyString.push(txt!)
choosedList[key] = false
}
}
@@ -1026,7 +1018,6 @@ function handleBatchRename () {
onBeforeUnmount(() => {
ipcRenderer.removeAllListeners('updateGallery')
- ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
})
onActivated(async () => {
diff --git a/src/renderer/pages/MiniPage.vue b/src/renderer/pages/MiniPage.vue
index 1d89d5fb..e4d23956 100644
--- a/src/renderer/pages/MiniPage.vue
+++ b/src/renderer/pages/MiniPage.vue
@@ -4,7 +4,7 @@
>
())!
- if (config !== undefined) {
+ const config = await getConfig
()
+ if (config) {
if (config.settings?.isCustomMiniIcon && config.settings?.customMiniIcon) {
logoPath.value = 'data:image/jpg;base64,' + await invokeToMain('convertPathToBase64', config.settings.customMiniIcon)
}
@@ -67,7 +67,6 @@ async function initLogoPath () {
}
onBeforeMount(async () => {
- os.value = process.platform
await initLogoPath()
ipcRenderer.on('uploadProgress', (_: IpcRendererEvent, _progress: number) => {
if (_progress !== -1) {
@@ -110,7 +109,7 @@ function onDrop (e: DragEvent) {
} else if (items[0].type === 'text/plain') {
const str = e.dataTransfer!.getData(items[0].type)
if (isUrl(str)) {
- sendToMain('uploadChoosedFiles', [{ path: str }])
+ sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [{ path: str }])
} else {
$message.error($T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
}
@@ -124,7 +123,7 @@ function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer)
const urlString = dataTransfer.getData(items[1].type)
const urlMatch = urlString.match(/ {
diff --git a/src/renderer/pages/PicGoSetting.vue b/src/renderer/pages/PicGoSetting.vue
index f8aed3ff..2661ccea 100644
--- a/src/renderer/pages/PicGoSetting.vue
+++ b/src/renderer/pages/PicGoSetting.vue
@@ -74,13 +74,13 @@
:value="'quiet'"
/>
@@ -563,11 +563,11 @@
:label="$T('CHOOSE_SHOWED_PICBED')"
>
@@ -745,7 +745,7 @@
{{ $T('SETTINGS_TIPS_PLACEHOLDER_EXTNAME') }}
@@ -781,7 +781,6 @@
>
import { compare } from 'compare-versions'
-import { ipcRenderer } from 'electron'
import { ElForm, ElMessage as $message, ElMessage, ElMessageBox, FormRules } from 'element-plus'
import { Reading, Close, Edit, InfoFilled } from '@element-plus/icons-vue'
import { IConfig } from 'piclist'
-import { computed, onBeforeMount, onBeforeUnmount, reactive, ref, toRaw, watch } from 'vue'
+import { computed, onBeforeMount, reactive, ref, toRaw, watch } from 'vue'
import { useRouter } from 'vue-router'
import ImageProcessSetting from '@/components/ImageProcessSetting.vue'
import { i18nManager, T as $T } from '@/i18n/index'
import { buildInRenameFormatTable } from '@/manage/utils/common'
import { SHORTKEY_PAGE } from '@/router/config'
-import { getConfig, saveConfig, sendRPC } from '@/utils/dataSender'
+import { getConfig, saveConfig } from '@/utils/dataSender'
+import { osGlobal, picBedGlobal, updatePicBedGlobal } from '@/utils/global'
-import { PICGO_OPEN_FILE, PICGO_OPEN_DIRECTORY, OPEN_URL, GET_PICBEDS, HIDE_DOCK } from '#/events/constants'
import { II18nLanguage, IRPCActionType, ISartMode } from '#/types/enum'
import { enforceNumber } from '#/utils/common'
import { configPaths, ISartModeValues } from '#/utils/configPaths'
import { getLatestVersion } from '#/utils/getLatestVersion'
import pkg from 'root/package.json'
-import { invokeToMain, sendToMain } from '@/utils/common'
+import { invokeToMain, sendRPC, triggerRPC } from '@/utils/common'
const $router = useRouter()
const activeName = ref<'system' | 'syncAndConfigure' | 'upload' | 'advanced' | 'upadte'>('system')
@@ -1435,7 +1432,12 @@ const manualPageOpenList = [{
value: 'browser'
}]
-const picBed = ref([])
+const showPicBedList = computed(() => picBedGlobal.value.map(item => {
+ if (item.visible) {
+ return item.name
+ }
+ return null
+}).filter(item => item) as string[])
const $customLink = ref | null>(null)
@@ -1447,9 +1449,8 @@ const customLinkRule = (_: any, value: string, callback: (arg0?: Error) => void)
}
}
-const formOfSetting = ref({
+const formOfSetting = ref({
showUpdateTip: true,
- showPicBedList: [],
autoStart: false,
rename: false,
autoRename: false,
@@ -1483,29 +1484,33 @@ const formOfSetting = ref({
webServerHost: '0.0.0.0',
webServerPort: 37777,
webServerPath: '',
- customLink: '',
registry: '',
proxy: '',
mainWindowWidth: 1200,
mainWindowHeight: 800
})
+
const proxy = ref('')
const formKeys = Object.keys(formOfSetting.value)
const autoWatchKeys = ['showUpdateTip', 'autoImport', 'autoImportPicBed', 'useBuiltinClipboard', 'isAutoListenClipboard', 'deleteCloudFile', 'deleteLocalFile', 'rename', 'autoRename', 'enableWebServer', 'webServerHost', 'webServerPath', 'serverKey', 'uploadNotification', 'uploadResultNotification', 'autoCloseMainWindow', 'autoCloseMiniWindow', 'isCustomMiniIcon', 'c1nToken', 'yourlsDomain', 'yourlsSignature', 'cfWorkerHost', 'registry', 'proxy', 'autoCopy', 'encodeOutputURL', 'useShortUrl']
-autoWatchKeys.forEach(key => {
- watch(() => formOfSetting.value[key], (value) => {
- saveConfig({
- [`settings.${key}`]: value
+const addWatch = () => {
+ autoWatchKeys.forEach(key => {
+ watch(() => formOfSetting.value[key as keyof ISettingForm], value => {
+ saveConfig({
+ [`settings.${key}`]: value
+ })
})
})
-})
+}
-watch(proxy, (value) => {
- saveConfig({
- 'picBed.proxy': value
+const addProxyWatch = () => {
+ watch(proxy, (value) => {
+ saveConfig({
+ 'picBed.proxy': value
+ })
})
-})
+}
const valueToOptionItem = (value: any, list: { label: string, value: any }[]) => {
return list.find(item => item.value === value) || list[0]
@@ -1530,6 +1535,10 @@ const imageProcessDialogVisible = ref(false)
const rawPicGoSize = ref(false)
+const customLink = reactive({
+ value: ''
+})
+
const rules = reactive({
value: [
{ validator: customLinkRule, trigger: 'blur' }
@@ -1592,7 +1601,6 @@ function confirmSyncSetting () {
const version = pkg.version
const latestVersion = ref('')
-const os = ref('')
const needUpdate = computed(() => {
if (latestVersion.value) {
@@ -1602,9 +1610,6 @@ const needUpdate = computed(() => {
})
onBeforeMount(() => {
- os.value = process.platform
- sendToMain(GET_PICBEDS)
- ipcRenderer.on(GET_PICBEDS, getPicBeds)
initData()
})
@@ -1613,7 +1618,7 @@ async function initData () {
const settings = config.settings || {}
const picBed = config.picBed
formKeys.forEach(key => {
- formOfSetting.value[key] = settings[key] ?? formOfSetting.value[key]
+ (formOfSetting.value as any)[key as keyof ISettingForm] = settings[key] ?? formOfSetting.value[key as keyof ISettingForm]
})
formOfSetting.value.logLevel = initArray(settings.logLevel || [], ['all'])
formOfSetting.value.autoImportPicBed = initArray(settings.autoImportPicBed || [], [])
@@ -1621,6 +1626,7 @@ async function initData () {
currentStartMode.value = valueToOptionItem(settings.startMode || ISartMode.QUIET, startModeList)
currentManualPageOpen.value = valueToOptionItem(settings.manualPageOpen || 'window', manualPageOpenList)
currentShortUrlServer.value = valueToOptionItem(settings.shortUrlServer || 'c1n', shortUrlServerList)
+ customLink.value = settings.customLink || ''
proxy.value = picBed.proxy || ''
server.value = settings.server || {
port: 36677,
@@ -1648,6 +1654,8 @@ async function initData () {
interval: 60
}
formOfSetting.value.logFileSizeLimit = enforceNumber(settings.logFileSizeLimit) || 10
+ addProxyWatch()
+ addWatch()
}
function initArray (arrayT: string | string[], defaultValue: string[]) {
@@ -1661,18 +1669,8 @@ function initArray (arrayT: string | string[], defaultValue: string[]) {
return arrayT
}
-function getPicBeds (_: Event, picBeds: IPicBedType[]) {
- picBed.value = picBeds
- formOfSetting.value.showPicBedList = picBed.value.map(item => {
- if (item.visible) {
- return item.name
- }
- return null
- }).filter(item => item) as string[]
-}
-
function openFile (file: string) {
- sendToMain(PICGO_OPEN_FILE, file)
+ sendRPC(IRPCActionType.PICLIST_OPEN_FILE, file)
}
function handleManualPageOpenChange (val: string) {
@@ -1682,7 +1680,7 @@ function handleManualPageOpenChange (val: string) {
}
function openDirectory (directory?: string, inStorePath = true) {
- sendToMain(PICGO_OPEN_DIRECTORY, directory, inStorePath)
+ sendRPC(IRPCActionType.PICLIST_OPEN_DIRECTORY, directory, inStorePath)
}
function openLogSetting () {
@@ -1691,13 +1689,13 @@ function openLogSetting () {
async function cancelCustomLink () {
customLinkVisible.value = false
- formOfSetting.value.customLink = await getConfig(configPaths.settings.customLink) || ''
+ customLink.value = await getConfig(configPaths.settings.customLink) || ''
}
function confirmCustomLink () {
$customLink.value?.validate((valid: boolean) => {
if (valid) {
- saveConfig(configPaths.settings.customLink, formOfSetting.value.customLink)
+ saveConfig(configPaths.settings.customLink, customLink.value)
customLinkVisible.value = false
}
})
@@ -1721,17 +1719,21 @@ function handleSaveAdvancedRename () {
}
function handleMigrateFromPicGo () {
- ElMessageBox.confirm($T('SETTINGS_MIGRATE_FROM_PICGO_CONTENT'), $T('SETTINGS_MIGRATE_FROM_PICGO_TITLE'), {
- confirmButtonText: $T('CONFIRM'),
- cancelButtonText: $T('CANCEL'),
- type: 'warning',
- center: true
- }).then(() => {
- ipcRenderer.invoke('migrateFromPicGo').then(() => {
- ElMessage.success($T('SETTINGS_MIGRATE_FROM_PICGO_SUCCESS'))
- }).catch(() => {
- ElMessage.error($T('SETTINGS_MIGRATE_FROM_PICGO_FAILED'))
- })
+ ElMessageBox.confirm(
+ $T('SETTINGS_MIGRATE_FROM_PICGO_CONTENT'),
+ $T('SETTINGS_MIGRATE_FROM_PICGO_TITLE'), {
+ confirmButtonText: $T('CONFIRM'),
+ cancelButtonText: $T('CANCEL'),
+ type: 'warning',
+ center: true
+ }).then(() => {
+ triggerRPC(IRPCActionType.CONFIGURE_MIGRATE_FROM_PICGO)
+ .then(() => {
+ ElMessage.success($T('SETTINGS_MIGRATE_FROM_PICGO_SUCCESS'))
+ })
+ .catch(() => {
+ ElMessage.error($T('SETTINGS_MIGRATE_FROM_PICGO_FAILED'))
+ })
}).catch(() => {
return false
})
@@ -1744,11 +1746,11 @@ function handleHideDockChange (val: ICheckBoxValueType) {
return
}
saveConfig(configPaths.settings.isHideDock, val)
- sendToMain(HIDE_DOCK, val)
+ sendRPC(IRPCActionType.HIDE_DOCK, val)
}
function handleShowPicBedListChange (val: ICheckBoxValueType[]) {
- const list = picBed.value.map(item => {
+ const list = picBedGlobal.value.map(item => {
if (!val.includes(item.name)) {
item.visible = false
} else {
@@ -1759,12 +1761,12 @@ function handleShowPicBedListChange (val: ICheckBoxValueType[]) {
saveConfig({
[configPaths.picBed.list]: list
})
- sendToMain(GET_PICBEDS)
+ updatePicBedGlobal()
}
function handleAutoStartChange (val: ICheckBoxValueType) {
saveConfig(configPaths.settings.autoStart, val)
- sendToMain('autoStart', val)
+ sendRPC(IRPCActionType.PICLIST_AUTO_START, val)
}
function compareVersion2Update (current: string, latest: string): boolean {
@@ -1793,9 +1795,9 @@ function handleWebServerPortChange (val?: number, _?: number) {
function confirmWebServerSetting () {
if (formOfSetting.value.enableWebServer) {
- sendToMain('restartWebServer')
+ sendRPC(IRPCActionType.ADVANCED_RESTART_WEB_SERVER)
} else {
- sendToMain('stopWebServer')
+ sendRPC(IRPCActionType.ADVANCED_STOP_WEB_SERVER)
}
}
@@ -1822,7 +1824,7 @@ async function confirmWindowSize () {
function handleMiniWindowOntop (val: ICheckBoxValueType) {
saveConfig(configPaths.settings.miniWindowOntop, val)
- ipcRenderer.send('miniWindowOntop', val)
+ sendRPC(IRPCActionType.MINI_WINDOW_ON_TOP, val)
}
async function handleMiniIconPath (_: Event) {
@@ -1830,7 +1832,7 @@ async function handleMiniIconPath (_: Event) {
if (result && result[0]) {
formOfSetting.value.customMiniIcon = result[0]
saveConfig(configPaths.settings.customMiniIcon, formOfSetting.value.customMiniIcon)
- ipcRenderer.send('updateMiniIcon', formOfSetting.value.customMiniIcon)
+ sendRPC(IRPCActionType.UPDATE_MINI_WINDOW_ICON, formOfSetting.value.customMiniIcon)
}
}
@@ -1879,40 +1881,40 @@ function syncMessage (failed: number, taskType: 'UPLOAD' | 'DOWNLOAD') {
const syncTaskList = [
{
- task: 'uploadCommonConfig',
+ task: IRPCActionType.CONFIGURE_UPLOAD_COMMON_CONFIG,
label: $T('SETTINGS_SYNC_COMMON_CONFIG'),
number: 2
},
{
- task: 'uploadManageConfig',
+ task: IRPCActionType.CONFIGURE_UPLOAD_MANAGE_CONFIG,
label: $T('SETTINGS_SYNC_MANAGE_CONFIG'),
number: 2
},
{
- task: 'uploadAllConfig',
+ task: IRPCActionType.CONFIGURE_UPLOAD_ALL_CONFIG,
label: $T('SETTINGS_SYNC_UPLOAD_ALL'),
number: 4
},
{
- task: 'downloadCommonConfig',
+ task: IRPCActionType.CONFIGURE_DOWNLOAD_COMMON_CONFIG,
label: $T('SETTINGS_SYNC_COMMON_CONFIG'),
number: 2
},
{
- task: 'downloadManageConfig',
+ task: IRPCActionType.CONFIGURE_DOWNLOAD_MANAGE_CONFIG,
label: $T('SETTINGS_SYNC_MANAGE_CONFIG'),
number: 2
},
{
- task: 'downloadAllConfig',
+ task: IRPCActionType.CONFIGURE_DOWNLOAD_ALL_CONFIG,
label: $T('SETTINGS_SYNC_DOWNLOAD_ALL'),
number: 4
}
]
-async function syncTaskFn (task: string, number: number) {
- const failed = number - await invokeToMain(task)
- syncMessage(failed, task.includes('upload') ? 'UPLOAD' : 'DOWNLOAD')
+async function syncTaskFn (task: IRPCActionType, number: number) {
+ const failed = number - (await triggerRPC(task) || 0)
+ syncMessage(failed, task.includes('UPLOAD') ? 'UPLOAD' : 'DOWNLOAD')
}
function confirmServerSetting () {
@@ -1921,7 +1923,7 @@ function confirmServerSetting () {
[configPaths.settings.server]: server.value
})
serverVisible.value = false
- sendToMain('updateServer')
+ sendRPC(IRPCActionType.ADVANCED_UPDATE_SERVER)
}
async function cancelServerSetting () {
@@ -1959,7 +1961,7 @@ function handleLanguageChange (val: string) {
saveConfig({
[configPaths.settings.language]: val
})
- sendToMain(GET_PICBEDS)
+ updatePicBedGlobal()
}
function handleStartModeChange (val: ISartModeValues) {
@@ -1981,7 +1983,7 @@ async function goConfigPage () {
const url = lang === II18nLanguage.ZH_CN
? 'https://piclist.cn/configure.html'
: 'https://piclist.cn/en/configure.html'
- sendToMain(OPEN_URL, url)
+ sendRPC(IRPCActionType.OPEN_URL, url)
}
function goShortCutPage () {
@@ -1990,10 +1992,6 @@ function goShortCutPage () {
})
}
-onBeforeUnmount(() => {
- ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
-})
-
+
+