From f11a4264d0542767dcf7de4c157121aafb6d1abc Mon Sep 17 00:00:00 2001 From: Kuingsmile <96409857+Kuingsmile@users.noreply.github.com> Date: Fri, 15 Aug 2025 13:29:09 +0800 Subject: [PATCH] :art: Style(custom): lint code --- electron.vite.config.js | 113 +- eslint.config.js | 2 + package.json | 15 +- scripts/check-dep.js | 4 +- scripts/config.js | 132 +- scripts/gen-sha256.js | 10 +- scripts/link.js | 52 +- scripts/notarize.cjs | 2 +- src/main/apis/app/remoteNotice/index.ts | 16 +- src/main/apis/app/shortKey/shortKeyHandler.ts | 28 +- src/main/apis/app/shortKey/shortKeyService.ts | 8 +- src/main/apis/app/system/index.ts | 32 +- src/main/apis/app/uploader/apis.ts | 472 +- src/main/apis/app/uploader/index.ts | 16 +- src/main/apis/app/window/windowList.ts | 554 +- src/main/apis/app/window/windowManager.ts | 10 +- src/main/apis/core/bus/index.ts | 62 +- src/main/apis/core/datastore/dbChecker.ts | 8 +- src/main/apis/core/datastore/index.ts | 28 +- src/main/apis/core/picgo/index.ts | 2 +- src/main/apis/delete/alist.ts | 2 +- src/main/apis/delete/alistplist.ts | 2 +- src/main/apis/delete/aliyun.ts | 4 +- src/main/apis/delete/allApi.ts | 2 +- src/main/apis/delete/awss3.ts | 2 +- src/main/apis/delete/dogecloud.ts | 2 +- src/main/apis/delete/github.ts | 6 +- src/main/apis/delete/huaweiyun.ts | 2 +- src/main/apis/delete/imgur.ts | 2 +- src/main/apis/delete/local.ts | 2 +- src/main/apis/delete/lskyplist.ts | 2 +- src/main/apis/delete/piclist.ts | 2 +- src/main/apis/delete/qiniu.ts | 2 +- src/main/apis/delete/sftpplist.ts | 2 +- src/main/apis/delete/smms.ts | 2 +- src/main/apis/delete/tcyun.ts | 4 +- src/main/apis/delete/upyun.ts | 2 +- src/main/apis/delete/webdav.ts | 2 +- src/main/apis/gui/index.ts | 39 +- src/main/events/busEventList.ts | 12 +- src/main/events/constant.ts | 30 +- src/main/events/remotes/menu.ts | 58 +- src/main/events/rpc/index.ts | 6 +- src/main/events/rpc/router.ts | 2 +- src/main/events/rpc/routes/picbed/delete.ts | 30 +- src/main/events/rpc/routes/plugin/utils.ts | 8 +- .../events/rpc/routes/toolbox/checkFile.ts | 8 +- .../events/rpc/routes/toolbox/checkProxy.ts | 178 +- src/main/events/rpc/routes/toolbox/utils.ts | 2 +- src/main/fileServer/index.ts | 4 +- src/main/i18n/index.ts | 16 +- src/main/index.ts | 6 +- src/main/lifeCycle/errorHandler.ts | 8 +- src/main/lifeCycle/fixPath.ts | 2 +- src/main/lifeCycle/index.ts | 714 +- src/main/manage/apis/aliyun.ts | 38 +- src/main/manage/apis/github.ts | 26 +- src/main/manage/apis/imgur.ts | 14 +- src/main/manage/apis/local.ts | 26 +- src/main/manage/apis/qiniu.ts | 38 +- src/main/manage/apis/s3plist.ts | 100 +- src/main/manage/apis/sftp.ts | 24 +- src/main/manage/apis/smms.ts | 14 +- src/main/manage/apis/tcyun.ts | 36 +- src/main/manage/apis/upyun.ts | 30 +- src/main/manage/apis/webdavplist.ts | 24 +- src/main/manage/datastore/db.ts | 16 +- src/main/manage/datastore/dbChecker.ts | 6 +- src/main/manage/datastore/upDownTaskQueue.ts | 44 +- src/main/manage/manageApi.ts | 64 +- src/main/manage/utils/common.ts | 10 +- src/main/manage/utils/dogeAPI.ts | 4 +- src/main/manage/utils/logger.ts | 24 +- src/main/server/index.ts | 12 +- src/main/server/router.ts | 10 +- src/main/server/routerManager.ts | 468 +- src/main/server/webServer/index.ts | 18 +- src/main/utils/aesHelper.ts | 135 +- src/main/utils/beforeOpen.ts | 21 +- src/main/utils/clipboardPoll.ts | 8 +- src/main/utils/common.ts | 646 +- src/main/utils/configPaths.ts | 394 +- src/main/utils/deleteFunc.ts | 518 +- src/main/utils/deleteLog.ts | 16 +- src/main/utils/digestAuth.ts | 6 +- src/main/utils/enum.ts | 484 +- src/main/utils/getMacOSVersion.ts | 12 +- src/main/utils/handleUploaderConfig.ts | 8 +- src/main/utils/notification.ts | 6 +- src/main/utils/performanceOptimizer.ts | 64 +- src/main/utils/sshClient.ts | 388 +- src/main/utils/static.ts | 50 +- src/main/utils/syncSettings.ts | 26 +- src/main/utils/windowHelper.ts | 138 +- src/preload/index.ts | 202 +- src/renderer/App.vue | 116 +- src/renderer/apis/allApi.ts | 2 +- src/renderer/components/ImageLocal.vue | 222 +- src/renderer/components/ImagePreSign.vue | 246 +- .../components/ImageProcessSetting.vue | 2441 +++---- src/renderer/components/ImageWebdav.vue | 304 +- src/renderer/components/InputBoxDialog.vue | 42 +- src/renderer/components/NavigationPage.vue | 1667 +++-- src/renderer/components/ToolboxHandler.vue | 118 +- src/renderer/components/ToolboxStatusIcon.vue | 6 +- src/renderer/components/UnifiedConfigForm.vue | 1501 ++-- src/renderer/components/VirtualScroller.vue | 139 +- .../components/ui/ConfirmMessageBox.vue | 647 +- src/renderer/components/ui/MessageToast.vue | 527 +- src/renderer/components/ui/ThemeSwitcher.vue | 223 +- src/renderer/components/ui/TitleBar.vue | 458 +- .../components/ui/UIServiceProvider.vue | 202 +- src/renderer/hooks/useATagClick.ts | 48 +- src/renderer/hooks/useAppStore.ts | 165 +- src/renderer/hooks/useConfirm.ts | 76 +- src/renderer/hooks/useMessage.ts | 120 +- src/renderer/hooks/useVirtualGrid.ts | 20 +- src/renderer/i18n/index.ts | 2 +- src/renderer/layouts/Main.vue | 15 +- src/renderer/main.ts | 110 +- .../manage/components/CustomSwitch.vue | 38 +- src/renderer/manage/pages/BucketPage.vue | 6274 ++++++++--------- src/renderer/manage/pages/LogInPage.vue | 2039 +++--- src/renderer/manage/pages/ManageMain.vue | 1228 ++-- src/renderer/manage/pages/ManageSetting.vue | 84 +- src/renderer/manage/store/bucketFileDb.ts | 2 +- src/renderer/manage/store/manageStore.ts | 22 +- src/renderer/manage/utils/bucketConfigCons.ts | 144 +- src/renderer/manage/utils/common.ts | 30 +- src/renderer/manage/utils/dataSender.ts | 6 +- src/renderer/manage/utils/digestAuth.ts | 6 +- src/renderer/pages/Gallery.vue | 3065 ++++---- src/renderer/pages/MiniPage.vue | 480 +- src/renderer/pages/PicGoSetting.vue | 941 +-- src/renderer/pages/Plugin.vue | 1244 ++-- src/renderer/pages/RenamePage.vue | 725 +- src/renderer/pages/ShortKey.vue | 68 +- src/renderer/pages/Toolbox.vue | 537 +- src/renderer/pages/TrayPage.vue | 1022 ++- src/renderer/pages/Upload.vue | 859 ++- src/renderer/pages/UploaderConfigPage.vue | 399 +- src/renderer/pages/picbeds/index.vue | 1442 ++-- src/renderer/store/index.ts | 2 +- src/renderer/utils/common.ts | 4 +- src/renderer/utils/configPaths.ts | 398 +- src/renderer/utils/constant.ts | 28 +- src/renderer/utils/dataSender.ts | 4 +- src/renderer/utils/db.ts | 14 +- src/renderer/utils/drag.ts | 6 +- src/renderer/utils/enum.ts | 326 +- src/renderer/utils/global.ts | 38 +- src/renderer/utils/static.ts | 142 +- src/universal/types/globals.d.ts | 16 +- src/universal/types/i18n.d.ts | 16 +- src/universal/types/rpc.ts | 6 +- src/universal/types/shims-module.d.ts | 16 +- src/universal/types/shims-tsx.d.ts | 146 +- src/universal/types/types.ts | 26 +- tests/aeshelper.test.ts | 193 +- yarn.lock | 268 +- 160 files changed, 18208 insertions(+), 20414 deletions(-) diff --git a/electron.vite.config.js b/electron.vite.config.js index 8c354874..f1a2fbf9 100644 --- a/electron.vite.config.js +++ b/electron.vite.config.js @@ -1,57 +1,56 @@ -/// -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' - -import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' -import vue from '@vitejs/plugin-vue' -import { defineConfig, externalizeDepsPlugin } from 'electron-vite' -export default defineConfig({ - main: { - plugins: [ - externalizeDepsPlugin() - ], - resolve: { - alias: { - '@': resolve('src/renderer'), - '~': resolve('src/main'), - root: resolve('./'), - '#': resolve('src/universal'), - apis: resolve('src/main/apis'), - '@core': resolve('src/main/apis/core') - } - } - }, - preload: { - plugins: [externalizeDepsPlugin(), - VueI18nPlugin({ - /* options */ - // locale messages resource pre-compile option - include: resolve(dirname(fileURLToPath(import.meta.url)), './src/renderer/i18n/locales/**') - }) - ], - resolve: { - alias: { - '@': resolve('src/renderer'), - '~': resolve('src/main'), - root: resolve('./'), - '#': resolve('src/universal') - } - } - }, - renderer: { - root: resolve('src/renderer'), - base: './', - resolve: { - alias: { - '@': resolve('src/renderer'), - '~': resolve('src/main'), - root: resolve('./'), - '#': resolve('src/universal') - } - }, - plugins: [vue()], - server: { - port: 3000 - } - } -}) +/// +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' +import vue from '@vitejs/plugin-vue' +import { defineConfig, externalizeDepsPlugin } from 'electron-vite' +export default defineConfig({ + main: { + plugins: [externalizeDepsPlugin()], + resolve: { + alias: { + '@': resolve('src/renderer'), + '~': resolve('src/main'), + root: resolve('./'), + '#': resolve('src/universal'), + apis: resolve('src/main/apis'), + '@core': resolve('src/main/apis/core') + } + } + }, + preload: { + plugins: [ + externalizeDepsPlugin(), + VueI18nPlugin({ + /* options */ + // locale messages resource pre-compile option + include: resolve(dirname(fileURLToPath(import.meta.url)), './src/renderer/i18n/locales/**') + }) + ], + resolve: { + alias: { + '@': resolve('src/renderer'), + '~': resolve('src/main'), + root: resolve('./'), + '#': resolve('src/universal') + } + } + }, + renderer: { + root: resolve('src/renderer'), + base: './', + resolve: { + alias: { + '@': resolve('src/renderer'), + '~': resolve('src/main'), + root: resolve('./'), + '#': resolve('src/universal') + } + }, + plugins: [vue()], + server: { + port: 3000 + } + } +}) diff --git a/eslint.config.js b/eslint.config.js index b81d7fc4..c70ed8d4 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,5 +1,6 @@ import eslint from '@eslint/js' import standard from '@vue/eslint-config-standard' +import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' import simpleImportSort from 'eslint-plugin-simple-import-sort' import eslintPluginUnicorn from 'eslint-plugin-unicorn' import pluginVue from 'eslint-plugin-vue' @@ -18,6 +19,7 @@ export default tseslint.config( ...tseslint.configs.stylistic, ...pluginVue.configs['flat/recommended'], ...standard, + eslintPluginPrettierRecommended, { plugins: { 'simple-import-sort': simpleImportSort, diff --git a/package.json b/package.json index 04ae865f..2f1a4eba 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,10 @@ "dev": "electron-vite dev --watch", "i18n": "node ./scripts/gen-i18n-types.js", "link": "node ./scripts/link.js", - "lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src/", + "lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src/ scripts/ .", "lint:dpdm": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/main/index.ts", "lint:dpdm:renderer": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/renderer/main.ts", - "lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/", + "lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/ scripts/ .", "ncu": "node ./scripts/check-dep.js", "postinstall": "electron-builder install-app-deps", "postuninstall": "electron-builder install-app-deps", @@ -44,7 +44,6 @@ "@aws-sdk/client-s3": "^3.864.0", "@aws-sdk/lib-storage": "^3.864.0", "@aws-sdk/s3-request-presigner": "^3.864.0", - "@electron-toolkit/preload": "^3.0.2", "@headlessui/vue": "^1.7.23", "@highlightjs/vue-plugin": "^2.1.2", "@nodelib/fs.walk": "^3.0.1", @@ -53,11 +52,12 @@ "@piclist/store": "^3.0.0", "@smithy/node-http-handler": "^4.1.1", "@videojs-player/vue": "^1.0.0", - "@vueuse/core": "^13.6.0", "ali-oss": "^6.23.0", "axios": "^1.11.0", + "chalk": "^5.5.0", "compare-versions": "^6.1.1", "cos-nodejs-sdk-v5": "^2.15.4", + "dayjs": "^1.11.13", "dexie": "^3.2.4", "electron-updater": "^6.6.2", "fast-xml-parser": "^5.2.5", @@ -78,13 +78,12 @@ "piclist": "^2.0.0", "pinia": "^3.0.3", "pinia-plugin-persistedstate": "^4.5.0", - "proxy-agent": "^6.5.0", "qiniu": "7.14.0", "qrcode.vue": "^3.6.0", - "querystring": "^0.2.1", "semver": "^7.7.2", "shell-path": "3.0.0", "ssh2-no-cpu-features": "^2.0.0", + "tunnel": "^0.0.6", "upyun": "^3.4.6", "uuid": "^11.1.0", "video.js": "^8.23.4", @@ -112,9 +111,7 @@ "@types/video.js": "^7.3.58", "@types/write-file-atomic": "^4.0.3", "@vitejs/plugin-vue": "^6.0.1", - "@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-standard": "^9.0.1", - "@vue/eslint-config-typescript": "^14.6.0", "dotenv": "^16.3.1", "dpdm": "^3.14.0", "electron": "^36.7.4", @@ -122,10 +119,12 @@ "electron-devtools-installer": "^4.0.0", "electron-vite": "^4.0.0", "eslint": "^9.33.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unicorn": "^60.0.0", "eslint-plugin-vue": "^10.4.0", + "globals": "^16.3.0", "husky": "^9.1.7", "node-bump-version": "^2.0.0", "npm-check-updates": "^18.0.2", diff --git a/scripts/check-dep.js b/scripts/check-dep.js index 574d8bb4..ab2f1788 100644 --- a/scripts/check-dep.js +++ b/scripts/check-dep.js @@ -1,7 +1,7 @@ import axios from 'axios' import { run } from 'npm-check-updates' -async function getRepositoryInfo (packageName) { +async function getRepositoryInfo(packageName) { try { const { data } = await axios.get(`https://registry.npmjs.org/${packageName}`) const repository = data.repository @@ -17,7 +17,7 @@ async function getRepositoryInfo (packageName) { return null } -async function checkUpdates () { +async function checkUpdates() { const updated = await run({ packageFile: './package.json', upgrade: false diff --git a/scripts/config.js b/scripts/config.js index 2e8c81aa..282c7755 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -1,66 +1,66 @@ -// different platform has different format - -// macos -const darwin = [ - { - appNameWithPrefix: 'PicList-', - ext: '.dmg', - arch: '-arm64', - 'version-file': 'latest-mac.yml' - }, - { - appNameWithPrefix: 'PicList-', - ext: '.dmg', - arch: '-x64', - 'version-file': 'latest-mac.yml' - } -] - -const linux = [ - { - appNameWithPrefix: 'PicList-', - ext: '.AppImage', - arch: '', - 'version-file': 'latest-linux.yml' - }, - { - appNameWithPrefix: 'piclist_', - ext: '.snap', - arch: '_amd64', - 'version-file': 'latest-linux.yml' - } -] - -// windows -const win32 = [ - { - appNameWithPrefix: 'PicList-Setup-', - ext: '.exe', - arch: '-ia32', - 'version-file': 'latest.yml' - }, - { - appNameWithPrefix: 'PicList-Setup-', - ext: '.exe', - arch: '-x64', - 'version-file': 'latest.yml' - }, - { - appNameWithPrefix: 'PicList-Setup-', - ext: '.exe', - arch: '', // 32 & 64 - 'version-file': 'latest.yml' - }, - { - appNameWithPrefix: 'PicList-Setup-', - ext: '.exe', - arch: '-arm64', - 'version-file': 'latest.yml' - } -] - -export default { - darwin, - linux, - win32 -} +// different platform has different format + +// macos +const darwin = [ + { + appNameWithPrefix: 'PicList-', + ext: '.dmg', + arch: '-arm64', + 'version-file': 'latest-mac.yml' + }, + { + appNameWithPrefix: 'PicList-', + ext: '.dmg', + arch: '-x64', + 'version-file': 'latest-mac.yml' + } +] + +const linux = [ + { + appNameWithPrefix: 'PicList-', + ext: '.AppImage', + arch: '', + 'version-file': 'latest-linux.yml' + }, + { + appNameWithPrefix: 'piclist_', + ext: '.snap', + arch: '_amd64', + 'version-file': 'latest-linux.yml' + } +] + +// windows +const win32 = [ + { + appNameWithPrefix: 'PicList-Setup-', + ext: '.exe', + arch: '-ia32', + 'version-file': 'latest.yml' + }, + { + appNameWithPrefix: 'PicList-Setup-', + ext: '.exe', + arch: '-x64', + 'version-file': 'latest.yml' + }, + { + appNameWithPrefix: 'PicList-Setup-', + ext: '.exe', + arch: '', // 32 & 64 + 'version-file': 'latest.yml' + }, + { + appNameWithPrefix: 'PicList-Setup-', + ext: '.exe', + arch: '-arm64', + 'version-file': 'latest.yml' + } +] + +export default { + darwin, + linux, + win32 +} diff --git a/scripts/gen-sha256.js b/scripts/gen-sha256.js index 38ee5ccf..35478a93 100644 --- a/scripts/gen-sha256.js +++ b/scripts/gen-sha256.js @@ -5,7 +5,7 @@ import path from 'node:path' import axios from 'axios' import fs from 'fs-extra' -import pkg from '../package.json' with { type: 'json'} +import pkg from '../package.json' with { type: 'json' } const version = process.argv[2] || pkg.version // Configuration @@ -26,7 +26,7 @@ const files = [ /** * Create progress bar string */ -function getProgressBar (current, total, length = 20) { +function getProgressBar(current, total, length = 20) { const progress = Math.round((current / total) * length) const percentage = Math.round((current / total) * 100) const bar = '█'.repeat(progress) + '░'.repeat(length - progress) @@ -36,7 +36,7 @@ function getProgressBar (current, total, length = 20) { /** * Format bytes to human-readable format */ -function formatBytes (bytes, decimals = 2) { +function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes' const k = 1024 const sizes = ['Bytes', 'KB', 'MB', 'GB'] @@ -47,7 +47,7 @@ function formatBytes (bytes, decimals = 2) { /** * Download file and calculate SHA256 hash */ -async function downloadAndHash (fileInfo) { +async function downloadAndHash(fileInfo) { const { url, name } = fileInfo const filePath = path.join(DOWNLOAD_DIR, name) @@ -103,7 +103,7 @@ async function downloadAndHash (fileInfo) { /** * Main function */ -async function main () { +async function main() { console.log(`Generating SHA256 hashes for PicList v${version}`) console.log(`Download directory: ${DOWNLOAD_DIR}`) diff --git a/scripts/link.js b/scripts/link.js index 63ca1f9a..fb315cf6 100644 --- a/scripts/link.js +++ b/scripts/link.js @@ -1,26 +1,26 @@ -import pkg from '../package.json' with { type: 'json' } -const version = pkg.version -// TODO: use the same name format -const generateURL = (platform, ext, prefix = 'PicList-') => { - return `https://release.piclist.cn/latest/${prefix}${version}${platform}${ext}` -} - -const template = ` -### 加速下载地址 - -#### MacOS -[PicList-${version}-arm64.dmg](${generateURL('-arm64', '.dmg', 'PicList-')}) -[PicList-${version}-x64.dmg](${generateURL('-x64', '.dmg', 'PicList-')}) -[PicList-${version}-universal.dmg](${generateURL('-universal', '.dmg', 'PicList-')}) - -#### Windows -[PicList-Setup-${version}-ia32.exe](${generateURL('-ia32', '.exe', 'PicList-Setup-')}) -[PicList-Setup-${version}-x64.exe](${generateURL('-x64', '.exe', 'PicList-Setup-')}) -[PicList-Setup-${version}-arm64.exe](${generateURL('-arm64', '.exe', 'PicList-Setup-')}) -[PicList-Setup-${version}.exe](${generateURL('', '.exe', 'PicList-Setup-')}) - -#### Linux -[PicList-${version}.AppImage](${generateURL('', '.AppImage', 'PicList-')}) -[piclist_${version}_amd64.snap](${generateURL('_amd64', '.snap', 'piclist_')})` - -console.log(template) +import pkg from '../package.json' with { type: 'json' } +const version = pkg.version +// TODO: use the same name format +const generateURL = (platform, ext, prefix = 'PicList-') => { + return `https://release.piclist.cn/latest/${prefix}${version}${platform}${ext}` +} + +const template = ` +### 加速下载地址 + +#### MacOS +[PicList-${version}-arm64.dmg](${generateURL('-arm64', '.dmg', 'PicList-')}) +[PicList-${version}-x64.dmg](${generateURL('-x64', '.dmg', 'PicList-')}) +[PicList-${version}-universal.dmg](${generateURL('-universal', '.dmg', 'PicList-')}) + +#### Windows +[PicList-Setup-${version}-ia32.exe](${generateURL('-ia32', '.exe', 'PicList-Setup-')}) +[PicList-Setup-${version}-x64.exe](${generateURL('-x64', '.exe', 'PicList-Setup-')}) +[PicList-Setup-${version}-arm64.exe](${generateURL('-arm64', '.exe', 'PicList-Setup-')}) +[PicList-Setup-${version}.exe](${generateURL('', '.exe', 'PicList-Setup-')}) + +#### Linux +[PicList-${version}.AppImage](${generateURL('', '.AppImage', 'PicList-')}) +[piclist_${version}_amd64.snap](${generateURL('_amd64', '.snap', 'piclist_')})` + +console.log(template) diff --git a/scripts/notarize.cjs b/scripts/notarize.cjs index 53c8ff37..3435af2a 100644 --- a/scripts/notarize.cjs +++ b/scripts/notarize.cjs @@ -5,7 +5,7 @@ require('dotenv').config() const { notarize } = require('@electron/notarize') const { ELECTRON_SKIP_NOTARIZATION, XCODE_APP_LOADER_EMAIL, XCODE_APP_LOADER_PASSWORD, XCODE_TEAM_ID } = process.env -async function main (context) { +async function main(context) { const { electronPlatformName, appOutDir } = context if ( diff --git a/src/main/apis/app/remoteNotice/index.ts b/src/main/apis/app/remoteNotice/index.ts index 62587142..9ef9840d 100644 --- a/src/main/apis/app/remoteNotice/index.ts +++ b/src/main/apis/app/remoteNotice/index.ts @@ -23,12 +23,12 @@ class RemoteNoticeHandler { private remoteNotice: IRemoteNotice | null = null private remoteNoticeLocalCountStorage: IRemoteNoticeLocalCountStorage | null = null - async init () { + async init() { this.remoteNotice = await this.getRemoteNoticeInfo() this.initLocalCountStorage() } - private initLocalCountStorage () { + private initLocalCountStorage() { const localCountStorage = {} if (!fs.existsSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH)) { fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify({})) @@ -44,14 +44,14 @@ class RemoteNoticeHandler { } } - private saveLocalCountStorage (newData?: IRemoteNoticeLocalCountStorage) { + private saveLocalCountStorage(newData?: IRemoteNoticeLocalCountStorage) { if (newData) { this.remoteNoticeLocalCountStorage = newData } fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify(this.remoteNoticeLocalCountStorage)) } - private async getRemoteNoticeInfo (): Promise { + private async getRemoteNoticeInfo(): Promise { try { const noticeInfo = (await axios({ method: 'get', @@ -68,7 +68,7 @@ class RemoteNoticeHandler { * if the notice is not shown or is always shown, then show the notice * @param action */ - private checkActionCount (action: IRemoteNoticeAction) { + private checkActionCount(action: IRemoteNoticeAction) { try { if (!this.remoteNoticeLocalCountStorage) { return true @@ -102,7 +102,7 @@ class RemoteNoticeHandler { } } - private async doActions (actions: IRemoteNoticeAction[]) { + private async doActions(actions: IRemoteNoticeAction[]) { for (const action of actions) { if (this.checkActionCount(action)) { switch (action.type) { @@ -117,7 +117,7 @@ class RemoteNoticeHandler { body: action.data?.content || '', clickToCopy: !!action.data?.copyToClipboard, copyContent: action.data?.copyToClipboard || '', - clickFn () { + clickFn() { if (action.data?.url) { shell.openExternal(action.data.url) } @@ -163,7 +163,7 @@ class RemoteNoticeHandler { } } - triggerHook (hook: string) { + triggerHook(hook: string) { if (!this.remoteNotice || !this.remoteNotice.list) { return } diff --git a/src/main/apis/app/shortKey/shortKeyHandler.ts b/src/main/apis/app/shortKey/shortKeyHandler.ts index 53df405f..e559dc9b 100644 --- a/src/main/apis/app/shortKey/shortKeyHandler.ts +++ b/src/main/apis/app/shortKey/shortKeyHandler.ts @@ -6,24 +6,30 @@ import shortKeyService from 'apis/app/shortKey/shortKeyService' import GuiApi from 'apis/gui' import { globalShortcut } from 'electron' -import type { IKeyCommandType, IPluginShortKeyConfig, IShortKeyConfig, IShortKeyConfigs, IShortKeyHandler } from '#/types/types' +import type { + IKeyCommandType, + IPluginShortKeyConfig, + IShortKeyConfig, + IShortKeyConfigs, + IShortKeyHandler +} from '#/types/types' import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant' import { configPaths } from '~/utils/configPaths' class ShortKeyHandler { private isInModifiedMode: boolean = false - constructor () { + constructor() { bus.on(TOGGLE_SHORTKEY_MODIFIED_MODE, flag => { this.isInModifiedMode = flag }) } - async init () { + async init() { this.initBuiltInShortKey() await this.initPluginsShortKey() } - private initBuiltInShortKey () { + private initBuiltInShortKey() { const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs Object.keys(commands) .filter(item => item.includes('picgo:')) @@ -38,7 +44,7 @@ class ShortKeyHandler { }) } - private async initPluginsShortKey () { + private async initPluginsShortKey() { // get enabled plugin const pluginList = picgo.pluginLoader.getList() for (const item of pluginList) { @@ -68,7 +74,7 @@ class ShortKeyHandler { } } - private registerShortKey ( + private registerShortKey( config: IShortKeyConfig | IPluginShortKeyConfig, command: string, handler: IShortKeyHandler, @@ -97,7 +103,7 @@ class ShortKeyHandler { } // enable or disable shortKey - bindOrUnbindShortKey (item: IShortKeyConfig, from: string): boolean { + bindOrUnbindShortKey(item: IShortKeyConfig, from: string): boolean { const command = `${from}:${item.name}` if (item.enable === false) { globalShortcut.unregister(item.key) @@ -121,7 +127,7 @@ class ShortKeyHandler { } // update shortKey bindings - updateShortKey (item: IShortKeyConfig, oldKey: string, from: string): boolean { + updateShortKey(item: IShortKeyConfig, oldKey: string, from: string): boolean { const command = `${from}:${item.name}` if (globalShortcut.isRegistered(item.key)) return false globalShortcut.unregister(oldKey) @@ -134,7 +140,7 @@ class ShortKeyHandler { return true } - private async handler (command: string) { + private async handler(command: string) { if (this.isInModifiedMode) { return } @@ -150,7 +156,7 @@ class ShortKeyHandler { } } - async registerPluginShortKey (pluginName: string) { + async registerPluginShortKey(pluginName: string) { const plugin = await picgo.pluginLoader.getPlugin(pluginName) if (plugin && plugin.commands) { if (typeof plugin.commands !== 'function') { @@ -170,7 +176,7 @@ class ShortKeyHandler { } } - unregisterPluginShortKey (pluginName: string) { + unregisterPluginShortKey(pluginName: string) { const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs const keyList = Object.keys(commands) .filter(command => command.includes(pluginName)) diff --git a/src/main/apis/app/shortKey/shortKeyService.ts b/src/main/apis/app/shortKey/shortKeyService.ts index 3811e032..8ac97329 100644 --- a/src/main/apis/app/shortKey/shortKeyService.ts +++ b/src/main/apis/app/shortKey/shortKeyService.ts @@ -4,22 +4,22 @@ import type { IShortKeyHandler } from '#/types/types' class ShortKeyService { private commandList: Map = new Map() - registerCommand (command: string, handler: IShortKeyHandler) { + registerCommand(command: string, handler: IShortKeyHandler) { this.commandList.set(command, handler) } - unregisterCommand (command: string) { + unregisterCommand(command: string) { this.commandList.delete(command) } - getShortKeyHandler (command: string): IShortKeyHandler | null { + getShortKeyHandler(command: string): IShortKeyHandler | null { const handler = this.commandList.get(command) if (handler) return handler logger.warn(`cannot find command: ${command}`) return null } - getCommandList () { + getCommandList() { return [...this.commandList.keys()] } } diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts index cd3efbaa..19390018 100644 --- a/src/main/apis/app/system/index.ts +++ b/src/main/apis/app/system/index.ts @@ -36,7 +36,7 @@ import uploadPng from '../../../../../resources/upload.png?asset&asarUnpack' import uploadDarkPng from '../../../../../resources/upload-dark.png?asset&asarUnpack' let contextMenu: Menu | null -export function setDockMenu () { +export function setDockMenu() { const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false const dockMenu = Menu.buildFromTemplate([ { @@ -45,7 +45,7 @@ export function setDockMenu () { }, { label: $t('START_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, true) clipboardPoll.startListening() clipboardPoll.on('change', () => { @@ -58,7 +58,7 @@ export function setDockMenu () { }, { label: $t('STOP_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, false) clipboardPoll.stopListening() clipboardPoll.removeAllListeners() @@ -70,7 +70,7 @@ export function setDockMenu () { app.dock?.setMenu(dockMenu) } -export function createMenu () { +export function createMenu() { const submenu = buildPicBedListMenu() const appMenu = Menu.buildFromTemplate([ { @@ -79,7 +79,7 @@ export function createMenu () { { label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow }, { label: $t('RELOAD_APP'), - click () { + click() { app.relaunch() app.exit(0) } @@ -107,7 +107,7 @@ export function createMenu () { Menu.setApplicationMenu(appMenu) } -export function createContextMenu () { +export function createContextMenu() { const ClipboardWatcher = clipboardPoll const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false const isMiniWindowVisible = @@ -147,7 +147,7 @@ export function createContextMenu () { }, { label: $t('RELOAD_APP'), - click () { + click() { app.relaunch() app.exit(0) } @@ -160,7 +160,7 @@ export function createContextMenu () { 0, { label: $t('OPEN_MINI_WINDOW'), - click () { + click() { openMiniWindow(false) }, visible: !isMiniWindowVisible @@ -185,7 +185,7 @@ export function createContextMenu () { { label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow }, { label: $t('OPEN_MINI_WINDOW'), - click () { + click() { openMiniWindow(false) }, visible: !isMiniWindowVisible @@ -207,7 +207,7 @@ export function createContextMenu () { }, { label: $t('ABOUT'), - click () { + click() { dialog.showMessageBox({ title: 'PicList', message: 'PicList', @@ -230,7 +230,7 @@ const getTrayIcon = () => { } } -export function createTray (tooltip: string) { +export function createTray(tooltip: string) { const menubarPic = getTrayIcon() setTray(new Tray(menubarPic)) tray.setToolTip(tooltip) @@ -309,7 +309,7 @@ export function createTray (tooltip: string) { // drop-files only be supported in macOS // so the tray window must be available if (process.platform === 'darwin') { - (tray as any).on('drop-files', async (_: Event, files: string[]) => { + ;(tray as any).on('drop-files', async (_: Event, files: string[]) => { const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN const rawInput = cloneDeep(files) const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)! @@ -338,14 +338,14 @@ export function createTray (tooltip: string) { imgs[i].shortUrl = shortUrl pasteText.push(pasteTextItem) const isShowResultNotification = - db.get(configPaths.settings.uploadResultNotification) === undefined - ? true - : !!db.get(configPaths.settings.uploadResultNotification) + db.get(configPaths.settings.uploadResultNotification) === undefined + ? true + : !!db.get(configPaths.settings.uploadResultNotification) if (isShowResultNotification) { const notification = new Notification({ title: $t('UPLOAD_SUCCEED'), body: shortUrl || imgs[i].imgUrl! - // icon: files[i] + // icon: files[i] }) setTimeout(() => { notification.show() diff --git a/src/main/apis/app/uploader/apis.ts b/src/main/apis/app/uploader/apis.ts index fbf21a4b..72f36ff9 100644 --- a/src/main/apis/app/uploader/apis.ts +++ b/src/main/apis/app/uploader/apis.ts @@ -1,236 +1,236 @@ -import db, { GalleryDB } from '@core/datastore' -import picgo from '@core/picgo' -import uploader from 'apis/app/uploader' -import windowManager from 'apis/app/window/windowManager' -import { Notification, WebContents } from 'electron' -import fs from 'fs-extra' -import { cloneDeep } from 'lodash-es' -import type { IPicGo } from 'piclist' - -import type { IFileWithPath, ImgInfo, IStringKeyMap, IUploadOption } from '#/types/types' -import { T as $t } from '~/i18n/index' -import { handleCopyUrl, handleUrlEncodeWithSetting } from '~/utils/common' -import { configPaths } from '~/utils/configPaths' -import { IPasteStyle, IWindowList } from '~/utils/enum' -import { changeCurrentUploader } from '~/utils/handleUploaderConfig' -import pasteTemplate from '~/utils/pasteTemplate' - -const handleClipboardUploading = async (): Promise => { - const useBuiltinClipboard = - db.get(configPaths.settings.useBuiltinClipboard) === undefined - ? true - : !!db.get(configPaths.settings.useBuiltinClipboard) - const win = windowManager.getAvailableWindow() - if (useBuiltinClipboard) { - return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard() - } - return await uploader.setWebContents(win!.webContents).upload() -} - -const handleClipboardUploadingReturnCtx = async (img?: IUploadOption, skipProcess = false): Promise => { - const useBuiltinClipboard = - db.get(configPaths.settings.useBuiltinClipboard) === undefined - ? true - : !!db.get(configPaths.settings.useBuiltinClipboard) - const win = windowManager.getAvailableWindow() - if (useBuiltinClipboard) { - return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboardReturnCtx(img, skipProcess) - } - return await uploader.setWebContents(win!.webContents).uploadReturnCtx(img, skipProcess) -} - -export const uploadClipboardFiles = async (): Promise => { - const { needRestore, ctx } = await handleSecondaryUpload(undefined, undefined, 'clipboard') - let img: ImgInfo[] | false = false - if (needRestore) { - const res = await handleClipboardUploadingReturnCtx(ctx ? ctx.processedInput : undefined, true) - img = res ? res.output : false - } else { - img = await handleClipboardUploading() - } - if (img !== false) { - if (img.length > 0) { - const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW) - const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN - const [pastedText, shortUrl] = await pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink)) - img[0].shortUrl = shortUrl - handleCopyUrl(pastedText) - 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: shortUrl || img[0].imgUrl! - // icon: img[0].imgUrl - }) - setTimeout(() => { - notification.show() - }, 100) - } - const inserted = await GalleryDB.getInstance().insert(img[0]) - // trayWindow just be created in mac/windows, not in linux - trayWindow?.webContents?.send('clipboardFiles', []) - trayWindow?.webContents?.send('uploadFiles', img) - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery') - } - return { - url: handleUrlEncodeWithSetting(inserted.imgUrl as string), - fullResult: inserted - } - } else { - const notification = new Notification({ - title: $t('UPLOAD_FAILED'), - body: $t('TIPS_UPLOAD_NOT_PICTURES') - }) - notification.show() - return { - url: '', - fullResult: {} - } - } - } else { - return { - url: '', - fullResult: {} - } - } -} - -export const uploadChoosedFiles = async ( - webContents: WebContents, - files: IFileWithPath[] -): Promise => { - const input = files.map(item => item.path) - const rawInput = cloneDeep(input) - const { needRestore, ctx } = await handleSecondaryUpload(webContents, input) - let imgs: ImgInfo[] | false = false - if (needRestore) { - const res = await uploader.setWebContents(webContents).uploadReturnCtx(ctx ? ctx.processedInput : input, true) - imgs = res ? res.output : false - } else { - imgs = await uploader.setWebContents(webContents).upload(input) - } - const result = [] - if (imgs !== false) { - const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN - const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false - const pasteText: string[] = [] - for (let i = 0; i < imgs.length; i++) { - if (deleteLocalFile) { - fs.remove(rawInput[i]) - .then(() => { - picgo.log.info(`delete local file: ${rawInput[i]}`) - }) - .catch((err: Error) => { - picgo.log.error(err) - }) - } - const [pasteTextItem, shortUrl] = await pasteTemplate( - pasteStyle, - imgs[i], - db.get(configPaths.settings.customLink) - ) - imgs[i].shortUrl = shortUrl - pasteText.push(pasteTextItem) - 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: shortUrl || imgs[i].imgUrl! - // icon: files[i].path - }) - setTimeout(() => { - notification.show() - }, i * 100) - } - const inserted = await GalleryDB.getInstance().insert(imgs[i]) - result.push({ - url: handleUrlEncodeWithSetting(inserted.imgUrl!), - fullResult: inserted - }) - } - handleCopyUrl(pasteText.join('\n')) - // trayWindow just be created in mac/windows, not in linux - windowManager.get(IWindowList.TRAY_WINDOW)?.webContents?.send('uploadFiles', imgs) - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery') - } - return result - } else { - return [] - } -} - -export const handleSecondaryUpload = async ( - webContents?: WebContents, - input?: string[], - uploadType: 'clipboard' | 'file' | 'tray' = 'file' -): Promise<{ needRestore: boolean; ctx: IPicGo | false }> => { - const enableSecondUploader = db.get(configPaths.settings.enableSecondUploader) || false - let currentPicBedType = '' - let currentPicBedConfig = {} as IStringKeyMap - let currentPicBedConfigId = '' - let needRestore = false - let ctx: IPicGo | false = false - if (enableSecondUploader) { - const secondUploader = db.get(configPaths.picBed.secondUploader) - const secondUploaderConfig = db.get(configPaths.picBed.secondUploaderConfig) - const secondUploaderId = db.get(configPaths.picBed.secondUploaderId) - const currentPicBed = db.get('picBed') || ({} as IStringKeyMap) - currentPicBedType = currentPicBed.uploader || currentPicBed.current || 'smms' - currentPicBedConfig = currentPicBed[currentPicBedType] || ({} as IStringKeyMap) - currentPicBedConfigId = currentPicBedConfig._id - if ( - secondUploader === currentPicBedType && - secondUploaderConfig._configName === currentPicBedConfig._configName && - secondUploaderId === currentPicBedConfigId - ) { - picgo.log.info('second uploader is the same as current uploader') - } else { - needRestore = true - let secondImgs: ImgInfo[] | false = false - changeCurrentUploader(secondUploader, secondUploaderConfig, secondUploaderId) - if (uploadType === 'clipboard') { - ctx = await handleClipboardUploadingReturnCtx(undefined) - } else { - ctx = await uploader.setWebContents(webContents!).uploadReturnCtx(input) - } - secondImgs = ctx ? ctx.output : false - if (secondImgs !== false) { - const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW) - if (uploadType === 'clipboard') { - if (secondImgs.length > 0) { - await GalleryDB.getInstance().insert(secondImgs[0]) - trayWindow?.webContents?.send('clipboardFiles', []) - trayWindow?.webContents?.send('uploadFiles', secondImgs) - } - } else { - for (const secondImgsItem of secondImgs) { - await GalleryDB.getInstance().insert(secondImgsItem) - } - if (uploadType === 'tray') { - trayWindow?.webContents?.send('dragFiles', secondImgs) - } else { - trayWindow?.webContents?.send('uploadFiles', secondImgs) - } - } - if (windowManager.has(IWindowList.SETTING_WINDOW) && uploadType !== 'tray') { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery') - } - } - } - } - if (needRestore) { - changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId) - } - return { - needRestore, - ctx - } -} +import db, { GalleryDB } from '@core/datastore' +import picgo from '@core/picgo' +import uploader from 'apis/app/uploader' +import windowManager from 'apis/app/window/windowManager' +import { Notification, WebContents } from 'electron' +import fs from 'fs-extra' +import { cloneDeep } from 'lodash-es' +import type { IPicGo } from 'piclist' + +import type { IFileWithPath, ImgInfo, IStringKeyMap, IUploadOption } from '#/types/types' +import { T as $t } from '~/i18n/index' +import { handleCopyUrl, handleUrlEncodeWithSetting } from '~/utils/common' +import { configPaths } from '~/utils/configPaths' +import { IPasteStyle, IWindowList } from '~/utils/enum' +import { changeCurrentUploader } from '~/utils/handleUploaderConfig' +import pasteTemplate from '~/utils/pasteTemplate' + +const handleClipboardUploading = async (): Promise => { + const useBuiltinClipboard = + db.get(configPaths.settings.useBuiltinClipboard) === undefined + ? true + : !!db.get(configPaths.settings.useBuiltinClipboard) + const win = windowManager.getAvailableWindow() + if (useBuiltinClipboard) { + return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard() + } + return await uploader.setWebContents(win!.webContents).upload() +} + +const handleClipboardUploadingReturnCtx = async (img?: IUploadOption, skipProcess = false): Promise => { + const useBuiltinClipboard = + db.get(configPaths.settings.useBuiltinClipboard) === undefined + ? true + : !!db.get(configPaths.settings.useBuiltinClipboard) + const win = windowManager.getAvailableWindow() + if (useBuiltinClipboard) { + return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboardReturnCtx(img, skipProcess) + } + return await uploader.setWebContents(win!.webContents).uploadReturnCtx(img, skipProcess) +} + +export const uploadClipboardFiles = async (): Promise => { + const { needRestore, ctx } = await handleSecondaryUpload(undefined, undefined, 'clipboard') + let img: ImgInfo[] | false = false + if (needRestore) { + const res = await handleClipboardUploadingReturnCtx(ctx ? ctx.processedInput : undefined, true) + img = res ? res.output : false + } else { + img = await handleClipboardUploading() + } + if (img !== false) { + if (img.length > 0) { + const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW) + const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN + const [pastedText, shortUrl] = await pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink)) + img[0].shortUrl = shortUrl + handleCopyUrl(pastedText) + 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: shortUrl || img[0].imgUrl! + // icon: img[0].imgUrl + }) + setTimeout(() => { + notification.show() + }, 100) + } + const inserted = await GalleryDB.getInstance().insert(img[0]) + // trayWindow just be created in mac/windows, not in linux + trayWindow?.webContents?.send('clipboardFiles', []) + trayWindow?.webContents?.send('uploadFiles', img) + if (windowManager.has(IWindowList.SETTING_WINDOW)) { + windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery') + } + return { + url: handleUrlEncodeWithSetting(inserted.imgUrl as string), + fullResult: inserted + } + } else { + const notification = new Notification({ + title: $t('UPLOAD_FAILED'), + body: $t('TIPS_UPLOAD_NOT_PICTURES') + }) + notification.show() + return { + url: '', + fullResult: {} + } + } + } else { + return { + url: '', + fullResult: {} + } + } +} + +export const uploadChoosedFiles = async ( + webContents: WebContents, + files: IFileWithPath[] +): Promise => { + const input = files.map(item => item.path) + const rawInput = cloneDeep(input) + const { needRestore, ctx } = await handleSecondaryUpload(webContents, input) + let imgs: ImgInfo[] | false = false + if (needRestore) { + const res = await uploader.setWebContents(webContents).uploadReturnCtx(ctx ? ctx.processedInput : input, true) + imgs = res ? res.output : false + } else { + imgs = await uploader.setWebContents(webContents).upload(input) + } + const result = [] + if (imgs !== false) { + const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN + const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false + const pasteText: string[] = [] + for (let i = 0; i < imgs.length; i++) { + if (deleteLocalFile) { + fs.remove(rawInput[i]) + .then(() => { + picgo.log.info(`delete local file: ${rawInput[i]}`) + }) + .catch((err: Error) => { + picgo.log.error(err) + }) + } + const [pasteTextItem, shortUrl] = await pasteTemplate( + pasteStyle, + imgs[i], + db.get(configPaths.settings.customLink) + ) + imgs[i].shortUrl = shortUrl + pasteText.push(pasteTextItem) + 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: shortUrl || imgs[i].imgUrl! + // icon: files[i].path + }) + setTimeout(() => { + notification.show() + }, i * 100) + } + const inserted = await GalleryDB.getInstance().insert(imgs[i]) + result.push({ + url: handleUrlEncodeWithSetting(inserted.imgUrl!), + fullResult: inserted + }) + } + handleCopyUrl(pasteText.join('\n')) + // trayWindow just be created in mac/windows, not in linux + windowManager.get(IWindowList.TRAY_WINDOW)?.webContents?.send('uploadFiles', imgs) + if (windowManager.has(IWindowList.SETTING_WINDOW)) { + windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery') + } + return result + } else { + return [] + } +} + +export const handleSecondaryUpload = async ( + webContents?: WebContents, + input?: string[], + uploadType: 'clipboard' | 'file' | 'tray' = 'file' +): Promise<{ needRestore: boolean; ctx: IPicGo | false }> => { + const enableSecondUploader = db.get(configPaths.settings.enableSecondUploader) || false + let currentPicBedType = '' + let currentPicBedConfig = {} as IStringKeyMap + let currentPicBedConfigId = '' + let needRestore = false + let ctx: IPicGo | false = false + if (enableSecondUploader) { + const secondUploader = db.get(configPaths.picBed.secondUploader) + const secondUploaderConfig = db.get(configPaths.picBed.secondUploaderConfig) + const secondUploaderId = db.get(configPaths.picBed.secondUploaderId) + const currentPicBed = db.get('picBed') || ({} as IStringKeyMap) + currentPicBedType = currentPicBed.uploader || currentPicBed.current || 'smms' + currentPicBedConfig = currentPicBed[currentPicBedType] || ({} as IStringKeyMap) + currentPicBedConfigId = currentPicBedConfig._id + if ( + secondUploader === currentPicBedType && + secondUploaderConfig._configName === currentPicBedConfig._configName && + secondUploaderId === currentPicBedConfigId + ) { + picgo.log.info('second uploader is the same as current uploader') + } else { + needRestore = true + let secondImgs: ImgInfo[] | false = false + changeCurrentUploader(secondUploader, secondUploaderConfig, secondUploaderId) + if (uploadType === 'clipboard') { + ctx = await handleClipboardUploadingReturnCtx(undefined) + } else { + ctx = await uploader.setWebContents(webContents!).uploadReturnCtx(input) + } + secondImgs = ctx ? ctx.output : false + if (secondImgs !== false) { + const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW) + if (uploadType === 'clipboard') { + if (secondImgs.length > 0) { + await GalleryDB.getInstance().insert(secondImgs[0]) + trayWindow?.webContents?.send('clipboardFiles', []) + trayWindow?.webContents?.send('uploadFiles', secondImgs) + } + } else { + for (const secondImgsItem of secondImgs) { + await GalleryDB.getInstance().insert(secondImgsItem) + } + if (uploadType === 'tray') { + trayWindow?.webContents?.send('dragFiles', secondImgs) + } else { + trayWindow?.webContents?.send('uploadFiles', secondImgs) + } + } + if (windowManager.has(IWindowList.SETTING_WINDOW) && uploadType !== 'tray') { + windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery') + } + } + } + } + if (needRestore) { + changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId) + } + return { + needRestore, + ctx + } +} diff --git a/src/main/apis/app/uploader/index.ts b/src/main/apis/app/uploader/index.ts index d80f5f17..d75d147a 100644 --- a/src/main/apis/app/uploader/index.ts +++ b/src/main/apis/app/uploader/index.ts @@ -36,11 +36,11 @@ const waitForRename = (window: BrowserWindow, id: number): Promise { new Notification(message).show() }) @@ -92,12 +92,12 @@ class Uploader { }) } - setWebContents (webContents: WebContents) { + setWebContents(webContents: WebContents) { this.webContents = webContents return this } - private async getClipboardImagePath (): Promise { + private async getClipboardImagePath(): Promise { const imgPath = getClipboardFilePath() if (imgPath) return imgPath @@ -115,7 +115,7 @@ class Uploader { /** * use electron's clipboard image to upload */ - async uploadWithBuildInClipboard (): Promise { + async uploadWithBuildInClipboard(): Promise { let imgPath: string | false = false try { imgPath = await this.getClipboardImagePath() @@ -131,7 +131,7 @@ class Uploader { } } - async uploadWithBuildInClipboardReturnCtx (img?: IUploadOption, skipProcess = false): Promise { + async uploadWithBuildInClipboardReturnCtx(img?: IUploadOption, skipProcess = false): Promise { let imgPath: string | false = false try { imgPath = await this.getClipboardImagePath() @@ -147,7 +147,7 @@ class Uploader { } } - async uploadReturnCtx (img?: IUploadOption, skipProcess = false): Promise { + async uploadReturnCtx(img?: IUploadOption, skipProcess = false): Promise { try { const ctx = await picgo.uploadReturnCtx(img, skipProcess) if (!Array.isArray(ctx.output) || !ctx.output.some((item: ImgInfo) => item.imgUrl)) return false @@ -172,7 +172,7 @@ class Uploader { } } - async upload (img?: IUploadOption): Promise { + async upload(img?: IUploadOption): Promise { try { const output = await picgo.upload(img) if (!Array.isArray(output) || !output.some((item: ImgInfo) => item.imgUrl)) return false diff --git a/src/main/apis/app/window/windowList.ts b/src/main/apis/app/window/windowList.ts index 76a64e94..487de241 100644 --- a/src/main/apis/app/window/windowList.ts +++ b/src/main/apis/app/window/windowList.ts @@ -1,277 +1,277 @@ -import path from 'node:path' -import { fileURLToPath } from 'node:url' - -import bus from '@core/bus' -import { CREATE_APP_MENU } from '@core/bus/constants' -import db from '@core/datastore' -import { app, BrowserWindow, Rectangle } from 'electron' - -import type { IWindowListItem } from '#/types/electron' -import type { IBrowserWindowOptions } from '#/types/types' -import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant' -import { T as $t } from '~/i18n' -import { configPaths } from '~/utils/configPaths' -import { IWindowList } from '~/utils/enum' - -import logo from '../../../../../resources/logo.png?asset&asarUnpack' - -const windowList = new Map() - -const getDefaultWindowSizes = (): { width: number; height: number } => { - const [mainWindowWidth, mainWindowHeight] = db.get([ - configPaths.settings.mainWindowWidth, - configPaths.settings.mainWindowHeight - ]) - return { - width: mainWindowWidth || 1200, - height: mainWindowHeight || 800 - } -} - -function setMiniWindowShape (win: BrowserWindow) { - const radius = 32 - const shape: Rectangle[] = [] - - for (let y = -radius; y <= radius; y++) { - for (let x = -radius; x <= radius; x++) { - if (x * x + y * y <= radius * radius) { - shape.push({ x: radius + x, y: radius + y, width: 1, height: 1 }) - } - } - } - - win.setShape(shape) -} - -const __dirname = path.dirname(fileURLToPath(import.meta.url)) -const preloadPath = fileURLToPath(new URL('../preload/index.mjs', import.meta.url)) - -const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes() - -const trayWindowOptions = { - height: 350, - width: 196, - show: false, - frame: false, - fullscreenable: false, - resizable: false, - transparent: true, - vibrancy: 'ultra-dark', - webPreferences: { - sandbox: false, - preload: preloadPath, - nodeIntegration: false, - contextIsolation: true, - nodeIntegrationInWorker: false, - backgroundThrottling: true, - webSecurity: false - } -} - -const settingWindowOptions = { - height: defaultWindowHeight, - width: defaultWindowWidth, - show: false, - frame: true, - center: true, - fullscreenable: true, - resizable: true, - title: 'PicList', - transparent: false, - backgroundColor: '#ebeef5', - titleBarStyle: 'hidden', - webPreferences: { - sandbox: false, - webviewTag: true, - backgroundThrottling: true, - preload: preloadPath, - nodeIntegration: false, - contextIsolation: true, - nodeIntegrationInWorker: false, - webSecurity: false - } -} as IBrowserWindowOptions - -if (process.platform !== 'darwin') { - settingWindowOptions.frame = false - settingWindowOptions.icon = logo -} - -const miniWindowOptions = { - height: 64, - width: 64, - show: process.platform === 'linux', - frame: false, - fullscreenable: false, - skipTaskbar: true, - resizable: false, - transparent: process.platform !== 'linux', - icon: logo, - webPreferences: { - sandbox: false, - preload: preloadPath, - nodeIntegration: false, - contextIsolation: true, - backgroundThrottling: true, - nodeIntegrationInWorker: false - } -} as IBrowserWindowOptions - -if (db.get(configPaths.settings.miniWindowOntop)) { - miniWindowOptions.alwaysOnTop = true -} - -const renameWindowOptions = { - height: 270, - width: 350, - show: true, - fullscreenable: false, - icon: logo, - resizable: true, - webPreferences: { - sandbox: false, - preload: preloadPath, - nodeIntegration: false, - contextIsolation: true, - nodeIntegrationInWorker: false, - backgroundThrottling: false - } -} as IBrowserWindowOptions - -if (process.platform !== 'darwin') { - renameWindowOptions.show = true - renameWindowOptions.backgroundColor = '#3f3c37' - renameWindowOptions.autoHideMenuBar = true - renameWindowOptions.transparent = false -} - -const toolboxWindowOptions = { - height: 450, - width: 800, - show: false, - frame: true, - center: true, - fullscreenable: false, - resizable: false, - title: `PicList ${$t('TOOLBOX')}`, - backgroundColor: '#ebeef5', - icon: logo, - webPreferences: { - sandbox: false, - backgroundThrottling: true, - preload: preloadPath, - nodeIntegration: false, - contextIsolation: true, - nodeIntegrationInWorker: false, - webSecurity: false - } -} as IBrowserWindowOptions - -if (process.platform !== 'darwin') { - toolboxWindowOptions.backgroundColor = '#3f3c37' - toolboxWindowOptions.autoHideMenuBar = true - toolboxWindowOptions.transparent = false -} - -windowList.set(IWindowList.TRAY_WINDOW, { - isValid: process.platform !== 'linux', - multiple: false, - options: () => trayWindowOptions, - callback (window) { - if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { - window.loadURL(process.env.ELECTRON_RENDERER_URL) - } else { - window.loadFile(path.join(__dirname, '../renderer/index.html')) - } - window.on('blur', () => { - window.hide() - }) - } -}) - -windowList.set(IWindowList.SETTING_WINDOW, { - isValid: true, - multiple: false, - options: () => settingWindowOptions, - callback (window, windowManager) { - if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { - window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`) - } else { - window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'main-page/upload' - }) - } - window.on('closed', () => { - bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false) - if (process.platform === 'linux') { - process.nextTick(() => { - app.quit() - }) - } - }) - bus.emit(CREATE_APP_MENU) - windowManager.create(IWindowList.MINI_WINDOW) - } -}) - -windowList.set(IWindowList.MINI_WINDOW, { - isValid: process.platform !== 'darwin', - multiple: false, - options: () => miniWindowOptions, - callback (window) { - if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { - window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`) - } else { - window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'mini-page' - }) - } - setMiniWindowShape(window) - } -}) - -windowList.set(IWindowList.RENAME_WINDOW, { - isValid: true, - multiple: true, - options: () => renameWindowOptions, - async callback (window, windowManager) { - if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { - window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`) - } else { - window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'rename-page' - }) - } - const currentWindow = windowManager.getAvailableWindow(true) - if (currentWindow && currentWindow.isVisible()) { - const { x, y, width, height } = currentWindow.getBounds() - const positionX = Math.floor(x + width / 2 - 150) - const positionY = Math.floor(y + height / 2 - (height > 400 ? 88 : 0)) - window.setPosition(positionX, positionY, false) - } - } -}) - -windowList.set(IWindowList.TOOLBOX_WINDOW, { - isValid: true, - multiple: false, - options: () => toolboxWindowOptions, - async callback (window, windowManager) { - if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { - window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`) - } else { - window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'toolbox-page' - }) - } - const currentWindow = windowManager.getAvailableWindow(true) - if (currentWindow && currentWindow.isVisible()) { - const { x, y, width, height } = currentWindow.getBounds() - const positionX = Math.floor(x + width / 2 - 400) - const positionY = Math.floor(y + height / 2 - (height > 400 ? 225 : 0)) - window.setPosition(positionX, positionY, false) - } - } -}) - -export default windowList +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +import bus from '@core/bus' +import { CREATE_APP_MENU } from '@core/bus/constants' +import db from '@core/datastore' +import { app, BrowserWindow, Rectangle } from 'electron' + +import type { IWindowListItem } from '#/types/electron' +import type { IBrowserWindowOptions } from '#/types/types' +import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant' +import { T as $t } from '~/i18n' +import { configPaths } from '~/utils/configPaths' +import { IWindowList } from '~/utils/enum' + +import logo from '../../../../../resources/logo.png?asset&asarUnpack' + +const windowList = new Map() + +const getDefaultWindowSizes = (): { width: number; height: number } => { + const [mainWindowWidth, mainWindowHeight] = db.get([ + configPaths.settings.mainWindowWidth, + configPaths.settings.mainWindowHeight + ]) + return { + width: mainWindowWidth || 1200, + height: mainWindowHeight || 800 + } +} + +function setMiniWindowShape(win: BrowserWindow) { + const radius = 32 + const shape: Rectangle[] = [] + + for (let y = -radius; y <= radius; y++) { + for (let x = -radius; x <= radius; x++) { + if (x * x + y * y <= radius * radius) { + shape.push({ x: radius + x, y: radius + y, width: 1, height: 1 }) + } + } + } + + win.setShape(shape) +} + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const preloadPath = fileURLToPath(new URL('../preload/index.mjs', import.meta.url)) + +const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes() + +const trayWindowOptions = { + height: 350, + width: 196, + show: false, + frame: false, + fullscreenable: false, + resizable: false, + transparent: true, + vibrancy: 'ultra-dark', + webPreferences: { + sandbox: false, + preload: preloadPath, + nodeIntegration: false, + contextIsolation: true, + nodeIntegrationInWorker: false, + backgroundThrottling: true, + webSecurity: false + } +} + +const settingWindowOptions = { + height: defaultWindowHeight, + width: defaultWindowWidth, + show: false, + frame: true, + center: true, + fullscreenable: true, + resizable: true, + title: 'PicList', + transparent: false, + backgroundColor: '#ebeef5', + titleBarStyle: 'hidden', + webPreferences: { + sandbox: false, + webviewTag: true, + backgroundThrottling: true, + preload: preloadPath, + nodeIntegration: false, + contextIsolation: true, + nodeIntegrationInWorker: false, + webSecurity: false + } +} as IBrowserWindowOptions + +if (process.platform !== 'darwin') { + settingWindowOptions.frame = false + settingWindowOptions.icon = logo +} + +const miniWindowOptions = { + height: 64, + width: 64, + show: process.platform === 'linux', + frame: false, + fullscreenable: false, + skipTaskbar: true, + resizable: false, + transparent: process.platform !== 'linux', + icon: logo, + webPreferences: { + sandbox: false, + preload: preloadPath, + nodeIntegration: false, + contextIsolation: true, + backgroundThrottling: true, + nodeIntegrationInWorker: false + } +} as IBrowserWindowOptions + +if (db.get(configPaths.settings.miniWindowOntop)) { + miniWindowOptions.alwaysOnTop = true +} + +const renameWindowOptions = { + height: 270, + width: 350, + show: true, + fullscreenable: false, + icon: logo, + resizable: true, + webPreferences: { + sandbox: false, + preload: preloadPath, + nodeIntegration: false, + contextIsolation: true, + nodeIntegrationInWorker: false, + backgroundThrottling: false + } +} as IBrowserWindowOptions + +if (process.platform !== 'darwin') { + renameWindowOptions.show = true + renameWindowOptions.backgroundColor = '#3f3c37' + renameWindowOptions.autoHideMenuBar = true + renameWindowOptions.transparent = false +} + +const toolboxWindowOptions = { + height: 450, + width: 800, + show: false, + frame: true, + center: true, + fullscreenable: false, + resizable: false, + title: `PicList ${$t('TOOLBOX')}`, + backgroundColor: '#ebeef5', + icon: logo, + webPreferences: { + sandbox: false, + backgroundThrottling: true, + preload: preloadPath, + nodeIntegration: false, + contextIsolation: true, + nodeIntegrationInWorker: false, + webSecurity: false + } +} as IBrowserWindowOptions + +if (process.platform !== 'darwin') { + toolboxWindowOptions.backgroundColor = '#3f3c37' + toolboxWindowOptions.autoHideMenuBar = true + toolboxWindowOptions.transparent = false +} + +windowList.set(IWindowList.TRAY_WINDOW, { + isValid: process.platform !== 'linux', + multiple: false, + options: () => trayWindowOptions, + callback(window) { + if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { + window.loadURL(process.env.ELECTRON_RENDERER_URL) + } else { + window.loadFile(path.join(__dirname, '../renderer/index.html')) + } + window.on('blur', () => { + window.hide() + }) + } +}) + +windowList.set(IWindowList.SETTING_WINDOW, { + isValid: true, + multiple: false, + options: () => settingWindowOptions, + callback(window, windowManager) { + if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { + window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`) + } else { + window.loadFile(path.join(__dirname, '../renderer/index.html'), { + hash: 'main-page/upload' + }) + } + window.on('closed', () => { + bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false) + if (process.platform === 'linux') { + process.nextTick(() => { + app.quit() + }) + } + }) + bus.emit(CREATE_APP_MENU) + windowManager.create(IWindowList.MINI_WINDOW) + } +}) + +windowList.set(IWindowList.MINI_WINDOW, { + isValid: process.platform !== 'darwin', + multiple: false, + options: () => miniWindowOptions, + callback(window) { + if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { + window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`) + } else { + window.loadFile(path.join(__dirname, '../renderer/index.html'), { + hash: 'mini-page' + }) + } + setMiniWindowShape(window) + } +}) + +windowList.set(IWindowList.RENAME_WINDOW, { + isValid: true, + multiple: true, + options: () => renameWindowOptions, + async callback(window, windowManager) { + if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { + window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`) + } else { + window.loadFile(path.join(__dirname, '../renderer/index.html'), { + hash: 'rename-page' + }) + } + const currentWindow = windowManager.getAvailableWindow(true) + if (currentWindow && currentWindow.isVisible()) { + const { x, y, width, height } = currentWindow.getBounds() + const positionX = Math.floor(x + width / 2 - 150) + const positionY = Math.floor(y + height / 2 - (height > 400 ? 88 : 0)) + window.setPosition(positionX, positionY, false) + } + } +}) + +windowList.set(IWindowList.TOOLBOX_WINDOW, { + isValid: true, + multiple: false, + options: () => toolboxWindowOptions, + async callback(window, windowManager) { + if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) { + window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`) + } else { + window.loadFile(path.join(__dirname, '../renderer/index.html'), { + hash: 'toolbox-page' + }) + } + const currentWindow = windowManager.getAvailableWindow(true) + if (currentWindow && currentWindow.isVisible()) { + const { x, y, width, height } = currentWindow.getBounds() + const positionX = Math.floor(x + width / 2 - 400) + const positionY = Math.floor(y + height / 2 - (height > 400 ? 225 : 0)) + window.setPosition(positionX, positionY, false) + } + } +}) + +export default windowList diff --git a/src/main/apis/app/window/windowManager.ts b/src/main/apis/app/window/windowManager.ts index fb185890..b43d9331 100644 --- a/src/main/apis/app/window/windowManager.ts +++ b/src/main/apis/app/window/windowManager.ts @@ -5,10 +5,10 @@ import type { IWindowListItem, IWindowManager } from '#/types/electron' import { IWindowList } from '~/utils/enum' class WindowManager implements IWindowManager { - #windowMap: Map< string, BrowserWindow> = new Map() + #windowMap: Map = new Map() #windowIdMap: Map = new Map() - create (name: string) { + create(name: string) { const windowConfig: IWindowListItem = windowList.get(name)! if (!windowConfig.isValid) return null @@ -30,14 +30,14 @@ class WindowManager implements IWindowManager { return window } - get (name: string) { + get(name: string) { if (this.has(name)) { return this.#windowMap.get(name)! } return this.create(name) } - has (name: string) { + has(name: string) { return this.#windowMap.has(name) } @@ -49,7 +49,7 @@ class WindowManager implements IWindowManager { } } - getAvailableWindow (isSkipMiniWindow = false) { + getAvailableWindow(isSkipMiniWindow = false) { const miniWindow = this.#windowMap.get(IWindowList.MINI_WINDOW) if (miniWindow && miniWindow.isVisible() && !isSkipMiniWindow) { return miniWindow diff --git a/src/main/apis/core/bus/index.ts b/src/main/apis/core/bus/index.ts index 60995993..155e230d 100644 --- a/src/main/apis/core/bus/index.ts +++ b/src/main/apis/core/bus/index.ts @@ -1,31 +1,31 @@ -import { EventEmitter } from 'node:events' - -class OptimizedBus extends EventEmitter { - constructor () { - super() - this.setMaxListeners(50) - } - - once (event: string | symbol, listener: (...args: any[]) => void): this { - const wrappedListener = (...args: any[]) => { - try { - listener(...args) - } finally { - this.removeListener(event, wrappedListener) - } - } - return super.once(event, wrappedListener) - } - - cleanupListeners () { - const events = this.eventNames() - events.forEach(event => { - const listenerCount = this.listenerCount(event) - console.log(` listener count (${listenerCount}) for event: ${String(event)}`) - }) - } -} - -const bus = new OptimizedBus() - -export default bus +import { EventEmitter } from 'node:events' + +class OptimizedBus extends EventEmitter { + constructor() { + super() + this.setMaxListeners(50) + } + + once(event: string | symbol, listener: (...args: any[]) => void): this { + const wrappedListener = (...args: any[]) => { + try { + listener(...args) + } finally { + this.removeListener(event, wrappedListener) + } + } + return super.once(event, wrappedListener) + } + + cleanupListeners() { + const events = this.eventNames() + events.forEach(event => { + const listenerCount = this.listenerCount(event) + console.log(` listener count (${listenerCount}) for event: ${String(event)}`) + }) + } +} + +const bus = new OptimizedBus() + +export default bus diff --git a/src/main/apis/core/datastore/dbChecker.ts b/src/main/apis/core/datastore/dbChecker.ts index 948e017b..8e60a850 100644 --- a/src/main/apis/core/datastore/dbChecker.ts +++ b/src/main/apis/core/datastore/dbChecker.ts @@ -23,7 +23,7 @@ const errorMsg = { brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP') } -function dbChecker () { +function dbChecker() { if (process.type !== 'renderer') { // db save bak try { @@ -80,7 +80,7 @@ function dbChecker () { /** * Get config path */ -function dbPathChecker (): string { +function dbPathChecker(): string { if (_configFilePath) { return _configFilePath } @@ -120,11 +120,11 @@ function dbPathChecker (): string { } } -function dbPathDir () { +function dbPathDir() { return path.dirname(dbPathChecker()) } -function getGalleryDBPath (): { +function getGalleryDBPath(): { dbPath: string dbBackupPath: string } { diff --git a/src/main/apis/core/datastore/index.ts b/src/main/apis/core/datastore/index.ts index d0b53dca..283a7635 100644 --- a/src/main/apis/core/datastore/index.ts +++ b/src/main/apis/core/datastore/index.ts @@ -19,7 +19,7 @@ export const DB_PATH: string = getGalleryDBPath().dbPath class ConfigStore { #db: JSONStore - constructor () { + constructor() { this.#db = new JSONStore(CONFIG_PATH) if (!this.#db.has('picBed')) { @@ -43,11 +43,11 @@ class ConfigStore { this.read() } - read (flush?: boolean): IJSON { + read(flush?: boolean): IJSON { return this.#db.read(flush) } - getSingle (key = ''): any { + getSingle(key = ''): any { if (key === '') { return this.#db.read(true) } @@ -55,43 +55,43 @@ class ConfigStore { return this.#db.get(key) } - get (key: string): any - get (key: string[]): any[] - get (key: string | string[] = ''): any { + 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 { + set(key: string, value: any): void { this.read(true) return this.#db.set(key, value) } - has (key: string) { + has(key: string) { this.read(true) return this.#db.has(key) } - unset (key: string, value: any): boolean { + unset(key: string, value: any): boolean { this.read(true) return this.#db.unset(key, value) } - saveConfig (config: Partial): void { + saveConfig(config: Partial): void { Object.keys(config).forEach((name: string) => { this.set(name, config[name]) }) } - removeConfig (config: IConfig): void { + removeConfig(config: IConfig): void { Object.keys(config).forEach((name: string) => { this.unset(name, config[name]) }) } - getConfigPath () { + getConfigPath() { return CONFIG_PATH } } @@ -103,11 +103,11 @@ export default db // v2.3.0 add gallery db class GalleryDB { static #instance: DBStore - private constructor () { + private constructor() { console.log('init gallery db') } - static getInstance (): DBStore { + static getInstance(): DBStore { if (!GalleryDB.#instance) { GalleryDB.#instance = new DBStore(DB_PATH, 'gallery') } diff --git a/src/main/apis/core/picgo/index.ts b/src/main/apis/core/picgo/index.ts index b0a66278..0e0e0e52 100644 --- a/src/main/apis/core/picgo/index.ts +++ b/src/main/apis/core/picgo/index.ts @@ -21,7 +21,7 @@ picgo.GUI_VERSION = pkg.version const originPicGoSaveConfig = picgo.saveConfig.bind(picgo) -function flushDB () { +function flushDB() { db.read(true) } diff --git a/src/main/apis/delete/alist.ts b/src/main/apis/delete/alist.ts index 6caa8bda..55d638fb 100644 --- a/src/main/apis/delete/alist.ts +++ b/src/main/apis/delete/alist.ts @@ -15,7 +15,7 @@ interface IConfigMap { } export default class AlistApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config } = configMap try { const { version, url, uploadPath, token } = config diff --git a/src/main/apis/delete/alistplist.ts b/src/main/apis/delete/alistplist.ts index e9a66cd2..63c8b1f1 100644 --- a/src/main/apis/delete/alistplist.ts +++ b/src/main/apis/delete/alistplist.ts @@ -26,7 +26,7 @@ const getAListToken = async (url: string, username: string, password: string) => } export default class AListplistApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config } = configMap try { const { url, username, password, uploadPath } = config diff --git a/src/main/apis/delete/aliyun.ts b/src/main/apis/delete/aliyun.ts index cc53223c..c5ee6468 100644 --- a/src/main/apis/delete/aliyun.ts +++ b/src/main/apis/delete/aliyun.ts @@ -9,11 +9,11 @@ interface IConfigMap { } export default class AliyunApi { - static #getKey (fileName: string, path?: string): string { + static #getKey(fileName: string, path?: string): string { return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${fileName}` : fileName } - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config } = configMap try { const client = new OSS({ ...config, region: config.area }) diff --git a/src/main/apis/delete/allApi.ts b/src/main/apis/delete/allApi.ts index 225bb257..238c72f6 100644 --- a/src/main/apis/delete/allApi.ts +++ b/src/main/apis/delete/allApi.ts @@ -39,7 +39,7 @@ const apiMap: IStringKeyMap = { } export default class ALLApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const api = apiMap[configMap.type] return api ? await api.delete(configMap) : false } diff --git a/src/main/apis/delete/awss3.ts b/src/main/apis/delete/awss3.ts index d6b40bbb..c4bc0f58 100644 --- a/src/main/apis/delete/awss3.ts +++ b/src/main/apis/delete/awss3.ts @@ -4,7 +4,7 @@ import { removeFileFromS3InMain } from '~/utils/deleteFunc' import { deleteFailedLog } from '~/utils/deleteLog' export default class AwsS3Api { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { try { return await removeFileFromS3InMain(getRawData(configMap)) } catch (error: any) { diff --git a/src/main/apis/delete/dogecloud.ts b/src/main/apis/delete/dogecloud.ts index 6b6032aa..0f7de270 100644 --- a/src/main/apis/delete/dogecloud.ts +++ b/src/main/apis/delete/dogecloud.ts @@ -4,7 +4,7 @@ import { removeFileFromDogeInMain } from '~/utils/deleteFunc' import { deleteFailedLog } from '~/utils/deleteLog' export default class AwsS3Api { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { try { return await removeFileFromDogeInMain(getRawData(configMap)) } catch (error: any) { diff --git a/src/main/apis/delete/github.ts b/src/main/apis/delete/github.ts index 341b6a73..79357f0f 100644 --- a/src/main/apis/delete/github.ts +++ b/src/main/apis/delete/github.ts @@ -10,18 +10,18 @@ interface IConfigMap { } export default class GithubApi { - static #createOctokit (token: string) { + static #createOctokit(token: string) { return new Octokit({ auth: token }) } - static #createKey (path: string | undefined, fileName: string): string { + static #createKey(path: string | undefined, fileName: string): string { const formatedFileName = fileName.replace(/%2F/g, '/') return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${formatedFileName}` : formatedFileName } - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, hash, diff --git a/src/main/apis/delete/huaweiyun.ts b/src/main/apis/delete/huaweiyun.ts index 3bd8ef33..91128a3b 100644 --- a/src/main/apis/delete/huaweiyun.ts +++ b/src/main/apis/delete/huaweiyun.ts @@ -4,7 +4,7 @@ import { removeFileFromHuaweiInMain } from '~/utils/deleteFunc' import { deleteFailedLog } from '~/utils/deleteLog' export default class HuaweicloudApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { try { return await removeFileFromHuaweiInMain(getRawData(configMap)) } catch (error: any) { diff --git a/src/main/apis/delete/imgur.ts b/src/main/apis/delete/imgur.ts index 06d0d8cf..1d1d572f 100644 --- a/src/main/apis/delete/imgur.ts +++ b/src/main/apis/delete/imgur.ts @@ -11,7 +11,7 @@ interface IConfigMap { export default class ImgurApi { static #baseUrl = 'https://api.imgur.com/3' - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { config: { clientId = '', username = '', accessToken = '' } = {}, hash = '' } = configMap let Authorization: string, apiUrl: string diff --git a/src/main/apis/delete/local.ts b/src/main/apis/delete/local.ts index 793a1e55..b85b2101 100644 --- a/src/main/apis/delete/local.ts +++ b/src/main/apis/delete/local.ts @@ -7,7 +7,7 @@ interface IConfigMap { } export default class LocalApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { hash } = configMap if (!hash) { deleteLog(hash, 'Local', false, 'Local.delete: invalid params') diff --git a/src/main/apis/delete/lskyplist.ts b/src/main/apis/delete/lskyplist.ts index dfb073b3..51740edd 100644 --- a/src/main/apis/delete/lskyplist.ts +++ b/src/main/apis/delete/lskyplist.ts @@ -6,7 +6,7 @@ import type { IStringKeyMap } from '#/types/types' import { deleteFailedLog, deleteLog } from '~/utils/deleteLog' export default class LskyplistApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const { hash, config } = configMap if (!hash || !config || !config.token) { deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid params') diff --git a/src/main/apis/delete/piclist.ts b/src/main/apis/delete/piclist.ts index 4fd98f66..a6ae31a9 100644 --- a/src/main/apis/delete/piclist.ts +++ b/src/main/apis/delete/piclist.ts @@ -4,7 +4,7 @@ import type { IStringKeyMap } from '#/types/types' import { deleteFailedLog, deleteLog } from '~/utils/deleteLog' export default class PiclistApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const { config, fullResult } = configMap const { host, port } = config if (!fullResult) return true diff --git a/src/main/apis/delete/qiniu.ts b/src/main/apis/delete/qiniu.ts index 412a43e6..e35c56ff 100644 --- a/src/main/apis/delete/qiniu.ts +++ b/src/main/apis/delete/qiniu.ts @@ -8,7 +8,7 @@ interface IConfigMap { } export default class QiniuApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config: { accessKey, secretKey, bucket, path } diff --git a/src/main/apis/delete/sftpplist.ts b/src/main/apis/delete/sftpplist.ts index 888dd9f3..909f47de 100644 --- a/src/main/apis/delete/sftpplist.ts +++ b/src/main/apis/delete/sftpplist.ts @@ -4,7 +4,7 @@ import { removeFileFromSFTPInMain } from '~/utils/deleteFunc' import { deleteFailedLog } from '~/utils/deleteLog' export default class SftpPlistApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { const { fileName, config } = configMap try { return await removeFileFromSFTPInMain(getRawData(config), fileName) diff --git a/src/main/apis/delete/smms.ts b/src/main/apis/delete/smms.ts index 20431534..b96f65bd 100644 --- a/src/main/apis/delete/smms.ts +++ b/src/main/apis/delete/smms.ts @@ -11,7 +11,7 @@ interface IConfigMap { export default class SmmsApi { static readonly #baseUrl = 'https://smms.app/api/v2' - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { hash, config } = configMap if (!hash || !config || !config.token) { deleteLog(hash, 'Smms', false, 'SmmsApi.delete: invalid params') diff --git a/src/main/apis/delete/tcyun.ts b/src/main/apis/delete/tcyun.ts index b8f898d2..81e1b7b3 100644 --- a/src/main/apis/delete/tcyun.ts +++ b/src/main/apis/delete/tcyun.ts @@ -7,14 +7,14 @@ interface IConfigMap { config: PartialKeys } export default class TcyunApi { - static #createCOS (SecretId: string, SecretKey: string): COS { + static #createCOS(SecretId: string, SecretKey: string): COS { return new COS({ SecretId, SecretKey }) } - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config: { secretId, secretKey, bucket, area, path } diff --git a/src/main/apis/delete/upyun.ts b/src/main/apis/delete/upyun.ts index 26f0cbab..71de37f2 100644 --- a/src/main/apis/delete/upyun.ts +++ b/src/main/apis/delete/upyun.ts @@ -9,7 +9,7 @@ interface IConfigMap { } export default class UpyunApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config: { bucket, operator, password, path } diff --git a/src/main/apis/delete/webdav.ts b/src/main/apis/delete/webdav.ts index fc1c3361..fcb7fbb6 100644 --- a/src/main/apis/delete/webdav.ts +++ b/src/main/apis/delete/webdav.ts @@ -10,7 +10,7 @@ interface IConfigMap { } export default class WebdavApi { - static async delete (configMap: IConfigMap): Promise { + static async delete(configMap: IConfigMap): Promise { const { fileName, config: { host, username, password, path, sslEnabled, authType } diff --git a/src/main/apis/gui/index.ts b/src/main/apis/gui/index.ts index fb020fc3..340605e0 100644 --- a/src/main/apis/gui/index.ts +++ b/src/main/apis/gui/index.ts @@ -8,7 +8,16 @@ import { BrowserWindow, dialog, ipcMain, IpcMainEvent, MessageBoxOptions, Notifi import fs from 'fs-extra' import { cloneDeep } from 'lodash-es' -import type { IGuiApi, ImgInfo, IShowFileExplorerOption, IShowInputBoxOption, IShowMessageBoxOption, IShowMessageBoxResult, IShowNotificationOption, IUploadOption } from '#/types/types' +import type { + IGuiApi, + ImgInfo, + IShowFileExplorerOption, + IShowInputBoxOption, + IShowMessageBoxOption, + IShowMessageBoxResult, + IShowNotificationOption, + IUploadOption +} from '#/types/types' import { SHOW_INPUT_BOX } from '~/events/constant' import { T as $t } from '~/i18n' import { handleCopyUrl } from '~/utils/common' @@ -21,18 +30,18 @@ class GuiApi implements IGuiApi { private static instance: GuiApi private windowId: number = -1 private settingWindowId: number = -1 - private constructor () { + private constructor() { console.log('init guiapi') } - static getInstance (): GuiApi { + static getInstance(): GuiApi { if (!GuiApi.instance) { GuiApi.instance = new GuiApi() } return GuiApi.instance } - private async showSettingWindow () { + private async showSettingWindow() { this.settingWindowId = await getSettingWindowId() const settingWindow = BrowserWindow.fromId(this.settingWindowId) if (settingWindow?.isVisible()) { @@ -46,11 +55,11 @@ class GuiApi implements IGuiApi { }) } - private getWebcontentsByWindowId (id: number) { + private getWebcontentsByWindowId(id: number) { return BrowserWindow.fromId(id)?.webContents } - async showInputBox ( + async showInputBox( options: IShowInputBoxOption = { title: '', placeholder: '' @@ -65,13 +74,13 @@ class GuiApi implements IGuiApi { }) } - async showFileExplorer (options: IShowFileExplorerOption = {}) { + async showFileExplorer(options: IShowFileExplorerOption = {}) { this.windowId = await getWindowId() const res = await dialog.showOpenDialog(BrowserWindow.fromId(this.windowId)!, options) return res.filePaths || [] } - async upload (input: IUploadOption) { + async upload(input: IUploadOption) { this.windowId = await getWindowId() const webContents = this.getWebcontentsByWindowId(this.windowId) const rawInput = cloneDeep(input) @@ -122,7 +131,7 @@ class GuiApi implements IGuiApi { return [] } - showNotification ( + showNotification( options: IShowNotificationOption = { title: '', body: '' @@ -135,7 +144,7 @@ class GuiApi implements IGuiApi { notification.show() } - showMessageBox ( + showMessageBox( options: IShowMessageBoxOption = { title: '', message: '', @@ -159,7 +168,7 @@ class GuiApi implements IGuiApi { /** * get picgo config/data path */ - async getConfigPath () { + async getConfigPath() { const currentConfigPath = dbPathChecker() const galleryDBPath = getGalleryDBPath().dbPath return { @@ -169,12 +178,12 @@ class GuiApi implements IGuiApi { } } - get galleryDB (): DBStore { + get galleryDB(): DBStore { return new Proxy(GalleryDB.getInstance(), { - get (target, prop: keyof DBStore) { + get(target, prop: keyof DBStore) { if (prop === 'overwrite') { return new Proxy(GalleryDB.getInstance().overwrite, { - apply (target, ctx, args) { + apply(target, ctx, args) { return new Promise(resolve => { const guiApi = GuiApi.getInstance() guiApi @@ -197,7 +206,7 @@ class GuiApi implements IGuiApi { } if (prop === 'removeById') { return new Proxy(GalleryDB.getInstance().removeById, { - apply (target, ctx, args) { + apply(target, ctx, args) { return new Promise(resolve => { const guiApi = GuiApi.getInstance() guiApi diff --git a/src/main/events/busEventList.ts b/src/main/events/busEventList.ts index 2f7d658d..da0136b6 100644 --- a/src/main/events/busEventList.ts +++ b/src/main/events/busEventList.ts @@ -17,7 +17,7 @@ import windowManager from 'apis/app/window/windowManager' import type { IFileWithPath } from '#/types/types' import { IWindowList } from '~/utils/enum' -function initEventCenter () { +function initEventCenter() { const eventList: any = { 'picgo:upload': uploadClipboardFiles, [UPLOAD_WITH_CLIPBOARD_FILES]: busCallUploadClipboardFiles, @@ -31,31 +31,31 @@ function initEventCenter () { } } -async function busCallUploadClipboardFiles () { +async function busCallUploadClipboardFiles() { const result = await uploadClipboardFiles() const imgUrl = result.url bus.emit(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, imgUrl) } -async function busCallUploadFiles (pathList: IFileWithPath[]) { +async function busCallUploadFiles(pathList: IFileWithPath[]) { const win = windowManager.getAvailableWindow() const result = await uploadChoosedFiles(win.webContents, pathList) const urls = result.map((item: any) => item.url) bus.emit(UPLOAD_WITH_FILES_RESPONSE, urls) } -function busCallGetWindowId () { +function busCallGetWindowId() { const win = windowManager.getAvailableWindow() bus.emit(GET_WINDOW_ID_REPONSE, win.id) } -function busCallGetSettingWindowId () { +function busCallGetSettingWindowId() { const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! bus.emit(GET_SETTING_WINDOW_ID_RESPONSE, settingWindow.id) } export default { - listen () { + listen() { initEventCenter() } } diff --git a/src/main/events/constant.ts b/src/main/events/constant.ts index f58ba94f..463be6db 100644 --- a/src/main/events/constant.ts +++ b/src/main/events/constant.ts @@ -1,15 +1,15 @@ -export const SHOW_INPUT_BOX = 'SHOW_INPUT_BOX' -export const SHOW_INPUT_BOX_RESPONSE = 'SHOW_INPUT_BOX_RESPONSE' -export const TOGGLE_SHORTKEY_MODIFIED_MODE = 'TOGGLE_SHORTKEY_MODIFIED_MODE' -// picgo plugin -export const PICGO_CONFIG_PLUGIN = 'PICGO_CONFIG_PLUGIN' -export const PICGO_HANDLE_PLUGIN_ING = 'PICGO_HANDLE_PLUGIN_ING' -export const PICGO_HANDLE_PLUGIN_DONE = 'PICGO_HANDLE_PLUGIN_DONE' -export const PICGO_TOGGLE_PLUGIN = 'PICGO_TOGGLE_PLUGIN' -// picgo uploader -export const RENAME_FILE_NAME = 'RENAME_FILE_NAME' -export const GET_RENAME_FILE_NAME = 'GET_RENAME_FILE_NAME' -export const SHOW_MAIN_PAGE_QRCODE = 'SHOW_MAIN_PAGE_QRCODE' -// rpc -export const RPC_ACTIONS = 'RPC_ACTIONS' -export const RPC_ACTIONS_INVOKE = 'RPC_ACTIONS_INVOKE' +export const SHOW_INPUT_BOX = 'SHOW_INPUT_BOX' +export const SHOW_INPUT_BOX_RESPONSE = 'SHOW_INPUT_BOX_RESPONSE' +export const TOGGLE_SHORTKEY_MODIFIED_MODE = 'TOGGLE_SHORTKEY_MODIFIED_MODE' +// picgo plugin +export const PICGO_CONFIG_PLUGIN = 'PICGO_CONFIG_PLUGIN' +export const PICGO_HANDLE_PLUGIN_ING = 'PICGO_HANDLE_PLUGIN_ING' +export const PICGO_HANDLE_PLUGIN_DONE = 'PICGO_HANDLE_PLUGIN_DONE' +export const PICGO_TOGGLE_PLUGIN = 'PICGO_TOGGLE_PLUGIN' +// picgo uploader +export const RENAME_FILE_NAME = 'RENAME_FILE_NAME' +export const GET_RENAME_FILE_NAME = 'GET_RENAME_FILE_NAME' +export const SHOW_MAIN_PAGE_QRCODE = 'SHOW_MAIN_PAGE_QRCODE' +// rpc +export const RPC_ACTIONS = 'RPC_ACTIONS' +export const RPC_ACTIONS_INVOKE = 'RPC_ACTIONS_INVOKE' diff --git a/src/main/events/remotes/menu.ts b/src/main/events/remotes/menu.ts index cc44b7e6..1e7a83e4 100644 --- a/src/main/events/remotes/menu.ts +++ b/src/main/events/remotes/menu.ts @@ -46,19 +46,19 @@ const buildMiniPageMenu = () => { }, { label: $t('UPLOAD_BY_CLIPBOARD'), - click () { + click() { uploadClipboardFiles() } }, { label: $t('HIDE_MINI_WINDOW'), - click () { + click() { BrowserWindow.getFocusedWindow()!.hide() } }, { label: $t('START_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, true) ClipboardWatcher.startListening() ClipboardWatcher.on('change', () => { @@ -71,7 +71,7 @@ const buildMiniPageMenu = () => { }, { label: $t('STOP_WATCH_CLIPBOARD'), - click () { + click() { db.set(configPaths.settings.isListeningClipboard, false) ClipboardWatcher.stopListening() ClipboardWatcher.removeAllListeners() @@ -81,7 +81,7 @@ const buildMiniPageMenu = () => { }, { label: $t('RELOAD_APP'), - click () { + click() { app.relaunch() app.exit(0) } @@ -98,7 +98,7 @@ const buildMainPageMenu = (win: BrowserWindow) => { const template = [ { label: $t('ABOUT'), - click () { + click() { dialog.showMessageBox({ title: 'PicList', message: 'PicList', @@ -108,26 +108,26 @@ const buildMainPageMenu = (win: BrowserWindow) => { }, { label: $t('SHOW_PICBED_QRCODE'), - click () { + click() { win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE) } }, { label: $t('OPEN_TOOLBOX'), - click () { + click() { const window = windowManager.create(IWindowList.TOOLBOX_WINDOW) window?.show() } }, { label: $t('SHOW_DEVTOOLS'), - click () { + click() { win?.webContents?.openDevTools({ mode: 'detach' }) } }, { label: $t('FEEDBACK'), - click () { + click() { const url = 'https://github.com/Kuingsmile/PicList/issues' shell.openExternal(url) } @@ -176,10 +176,10 @@ const buildSecondPicBedMenu = () => { : undefined, click: !hasSubmenu ? function () { - picgo.saveConfig({ - [configPaths.picBed.secondUploader]: item.type - }) - } + picgo.saveConfig({ + [configPaths.picBed.secondUploader]: item.type + }) + } : undefined } }) @@ -233,15 +233,15 @@ const buildPicBedListMenu = () => { : undefined, click: !hasSubmenu ? function () { - picgo.saveConfig({ - [configPaths.picBed.current]: item.type, - [configPaths.picBed.uploader]: item.type - }) - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') + picgo.saveConfig({ + [configPaths.picBed.current]: item.type, + [configPaths.picBed.uploader]: item.type + }) + if (windowManager.has(IWindowList.SETTING_WINDOW)) { + windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') + } + setTrayToolTip(item.type) } - setTrayToolTip(item.type) - } : undefined } }) @@ -278,7 +278,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { { label: $t('ENABLE_PLUGIN'), enabled: !plugin.enabled, - click () { + click() { picgo.saveConfig({ [`picgoPlugins.${plugin.fullName}`]: true }) @@ -289,7 +289,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { { label: $t('DISABLE_PLUGIN'), enabled: plugin.enabled, - click () { + click() { picgo.saveConfig({ [`picgoPlugins.${plugin.fullName}`]: false }) @@ -307,7 +307,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { }, { label: $t('UNINSTALL_PLUGIN'), - click () { + click() { const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) handlePluginUninstall(plugin.fullName) @@ -315,7 +315,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { }, { label: $t('UPDATE_PLUGIN'), - click () { + click() { const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) handlePluginUpdate(plugin.fullName) @@ -328,7 +328,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { label: $t('CONFIG_THING', { c: `${i} - ${plugin.config[i].fullName || plugin.config[i].name}` }), - click () { + click() { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const currentType = i const configName = plugin.config[i].fullName || plugin.config[i].name @@ -346,7 +346,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { const pluginTransformer = plugin.config.transformer.name const obj = { label: `${currentTransformer === pluginTransformer ? $t('DISABLE') : $t('ENABLE')}transformer - ${plugin.config.transformer.name}`, - click () { + click() { const transformer = plugin.config.transformer.name const currentTransformer = picgo.getConfig(configPaths.picBed.transformer) || 'path' if (currentTransformer === transformer) { @@ -371,7 +371,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { for (const i of plugin.guiMenu) { menu.push({ label: i.label, - async click () { + async click() { const picgPlugin = await 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 70976b97..485b1e70 100644 --- a/src/main/events/rpc/index.ts +++ b/src/main/events/rpc/index.ts @@ -37,12 +37,12 @@ class RPCServer implements IRPCServer { } } - start () { + start() { ipcMain.on(RPC_ACTIONS, this.rpcEventHandler) ipcMain.handle(RPC_ACTIONS_INVOKE, this.rpcEventHandlerWithResponse) } - use (routes: IRPCRoutes) { + use(routes: IRPCRoutes) { for (const [action, route] of routes) { if (route.type === IRPCType.SEND) { this.routes.set(action, route) @@ -52,7 +52,7 @@ class RPCServer implements IRPCServer { } } - stop () { + stop() { ipcMain.off(RPC_ACTIONS, this.rpcEventHandler) } } diff --git a/src/main/events/rpc/router.ts b/src/main/events/rpc/router.ts index 526b21bf..76c33543 100644 --- a/src/main/events/rpc/router.ts +++ b/src/main/events/rpc/router.ts @@ -21,7 +21,7 @@ export class RPCRouter implements IRPCRouter { return this } - routes () { + routes() { return this.routeMap } } diff --git a/src/main/events/rpc/routes/picbed/delete.ts b/src/main/events/rpc/routes/picbed/delete.ts index b87be701..4df31abd 100644 --- a/src/main/events/rpc/routes/picbed/delete.ts +++ b/src/main/events/rpc/routes/picbed/delete.ts @@ -1,15 +1,15 @@ -import ALLApi from 'apis/delete/allApi' - -import type { IIPCEvent } from '#/types/rpc' -import type { ImgInfo } from '#/types/types' -import { IRPCActionType, IRPCType } from '~/utils/enum' - -export default [ - { - action: IRPCActionType.DELETE_ALL_API, - handler: async (_: IIPCEvent, args:[item: ImgInfo]) => { - return await ALLApi.delete(args[0]) - }, - type: IRPCType.INVOKE - } -] +import ALLApi from 'apis/delete/allApi' + +import type { IIPCEvent } from '#/types/rpc' +import type { ImgInfo } from '#/types/types' +import { IRPCActionType, IRPCType } from '~/utils/enum' + +export default [ + { + action: IRPCActionType.DELETE_ALL_API, + handler: async (_: IIPCEvent, args: [item: ImgInfo]) => { + return await ALLApi.delete(args[0]) + }, + type: IRPCType.INVOKE + } +] diff --git a/src/main/events/rpc/routes/plugin/utils.ts b/src/main/events/rpc/routes/plugin/utils.ts index d684d24f..24687abe 100644 --- a/src/main/events/rpc/routes/plugin/utils.ts +++ b/src/main/events/rpc/routes/plugin/utils.ts @@ -85,11 +85,15 @@ const getPluginList = async (): Promise => { }, uploader: { name: uploaderName, - config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo)) + config: handleConfigWithFunction( + getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo) + ) }, transformer: { name: transformerName, - config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo)) + config: handleConfigWithFunction( + getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo) + ) } }, enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`), diff --git a/src/main/events/rpc/routes/toolbox/checkFile.ts b/src/main/events/rpc/routes/toolbox/checkFile.ts index ac2aaa60..5fd8ce78 100644 --- a/src/main/events/rpc/routes/toolbox/checkFile.ts +++ b/src/main/events/rpc/routes/toolbox/checkFile.ts @@ -10,9 +10,7 @@ import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils' import { T as $t } from '~/i18n' import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum' -export const checkFileMap: IToolboxCheckerMap< - string -> = { +export const checkFileMap: IToolboxCheckerMap = { [IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => { const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN) sendToolboxRes(event, { @@ -62,9 +60,7 @@ export const checkFileMap: IToolboxCheckerMap< } } -export const fixFileMap: IToolboxFixMap< - string -> = { +export const fixFileMap: IToolboxFixMap = { [IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => { try { fs.unlinkSync(dbPathChecker()) diff --git a/src/main/events/rpc/routes/toolbox/checkProxy.ts b/src/main/events/rpc/routes/toolbox/checkProxy.ts index 2b66be70..ea818221 100644 --- a/src/main/events/rpc/routes/toolbox/checkProxy.ts +++ b/src/main/events/rpc/routes/toolbox/checkProxy.ts @@ -1,89 +1,89 @@ -import { dbPathChecker } from '@core/datastore/dbChecker' -import axios, { AxiosRequestConfig } from 'axios' -import fs from 'fs-extra' -import { IConfig } from 'piclist' -import tunnel from 'tunnel' - -import type { IToolboxCheckerMap } from '#/types/rpc' -import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils' -import { T as $t } from '~/i18n' -import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum' - -function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null { - if (proxyStr) { - try { - const proxyOptions = new URL(proxyStr) - return { - host: proxyOptions.hostname, - port: parseInt(proxyOptions.port || '0', 10), - protocol: proxyOptions.protocol - } - } catch (e) {} - } - return null -} - -const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY) - -export const checkProxyMap: IToolboxCheckerMap = { - [IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async event => { - sendToolboxRes(event, { - status: IToolboxItemCheckStatus.LOADING - }) - const configFilePath = dbPathChecker() - if (fs.existsSync(configFilePath)) { - let config: IConfig | undefined - try { - config = (await fs.readJSON(configFilePath)) as IConfig - } catch (e) {} - if (!config) { - return sendToolboxRes(event, { - status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') - }) - } - - const proxy = config.picBed?.proxy - if (!proxy) { - return sendToolboxRes(event, { - status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') - }) - } else { - const proxyOptions = getProxy(proxy) - if (!proxyOptions) { - return sendToolboxRes(event, { - status: IToolboxItemCheckStatus.ERROR, - msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT') - }) - } else { - const httpsAgent = tunnel.httpsOverHttp({ - proxy: { - host: proxyOptions.host, - port: proxyOptions.port - } - }) - try { - await axios.get('https://www.google.com', { - httpsAgent - }) - return sendToolboxRes(event, { - status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_SUCCESS_TIPS') - }) - } catch (e) { - return sendToolboxRes(event, { - status: IToolboxItemCheckStatus.ERROR, - msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING') - }) - } - } - } - } - - sendToolboxRes(event, { - status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') - }) - } -} +import { dbPathChecker } from '@core/datastore/dbChecker' +import axios, { AxiosRequestConfig } from 'axios' +import fs from 'fs-extra' +import { IConfig } from 'piclist' +import tunnel from 'tunnel' + +import type { IToolboxCheckerMap } from '#/types/rpc' +import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils' +import { T as $t } from '~/i18n' +import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum' + +function getProxy(proxyStr: string): AxiosRequestConfig['proxy'] | null { + if (proxyStr) { + try { + const proxyOptions = new URL(proxyStr) + return { + host: proxyOptions.hostname, + port: parseInt(proxyOptions.port || '0', 10), + protocol: proxyOptions.protocol + } + } catch (e) {} + } + return null +} + +const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY) + +export const checkProxyMap: IToolboxCheckerMap = { + [IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async event => { + sendToolboxRes(event, { + status: IToolboxItemCheckStatus.LOADING + }) + const configFilePath = dbPathChecker() + if (fs.existsSync(configFilePath)) { + let config: IConfig | undefined + try { + config = (await fs.readJSON(configFilePath)) as IConfig + } catch (e) {} + if (!config) { + return sendToolboxRes(event, { + status: IToolboxItemCheckStatus.SUCCESS, + msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') + }) + } + + const proxy = config.picBed?.proxy + if (!proxy) { + return sendToolboxRes(event, { + status: IToolboxItemCheckStatus.SUCCESS, + msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') + }) + } else { + const proxyOptions = getProxy(proxy) + if (!proxyOptions) { + return sendToolboxRes(event, { + status: IToolboxItemCheckStatus.ERROR, + msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT') + }) + } else { + const httpsAgent = tunnel.httpsOverHttp({ + proxy: { + host: proxyOptions.host, + port: proxyOptions.port + } + }) + try { + await axios.get('https://www.google.com', { + httpsAgent + }) + return sendToolboxRes(event, { + status: IToolboxItemCheckStatus.SUCCESS, + msg: $t('TOOLBOX_CHECK_PROXY_SUCCESS_TIPS') + }) + } catch (e) { + return sendToolboxRes(event, { + status: IToolboxItemCheckStatus.ERROR, + msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING') + }) + } + } + } + } + + sendToolboxRes(event, { + status: IToolboxItemCheckStatus.SUCCESS, + msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') + }) + } +} diff --git a/src/main/events/rpc/routes/toolbox/utils.ts b/src/main/events/rpc/routes/toolbox/utils.ts index 52c79e57..9f0dd22d 100644 --- a/src/main/events/rpc/routes/toolbox/utils.ts +++ b/src/main/events/rpc/routes/toolbox/utils.ts @@ -3,7 +3,7 @@ import { IpcMainEvent } from 'electron' import type { IToolboxCheckRes } from '#/types/rpc' import { IRPCActionType } from '~/utils/enum' -export function sendToolboxResWithType (type: string) { +export function sendToolboxResWithType(type: string) { return (event: IpcMainEvent, res?: Omit) => { return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, { ...res, diff --git a/src/main/fileServer/index.ts b/src/main/fileServer/index.ts index e1dae7c7..28e72dae 100644 --- a/src/main/fileServer/index.ts +++ b/src/main/fileServer/index.ts @@ -12,7 +12,7 @@ const serverPort = 36699 let server: http.Server -export function startFileServer () { +export function startFileServer() { server = http.createServer((req, res) => { const requestPath = req.url?.split('?')[0] const filePath = path.join(imgFilePath, decodeURIComponent(requestPath as string)) @@ -36,7 +36,7 @@ export function startFileServer () { }) } -export function stopFileServer () { +export function stopFileServer() { server.close(() => { logger.info('File server is stopped') }) diff --git a/src/main/i18n/index.ts b/src/main/i18n/index.ts index 100987be..43d8920f 100644 --- a/src/main/i18n/index.ts +++ b/src/main/i18n/index.ts @@ -33,18 +33,18 @@ class I18nManager { readonly defaultLanguage: string = 'zh-CN' private i18nFileList: II18nItem[] = builtinI18nList - setOutterI18nFolder (folder: string) { + setOutterI18nFolder(folder: string) { this.outterI18nFolder = folder } - addI18nFile (file: string, label: string) { + addI18nFile(file: string, label: string) { this.i18nFileList.push({ label, value: file }) } - private getLocales (lang: string): ILocales { + private getLocales(lang: string): ILocales { if (this.localesMap.has(lang)) { return this.localesMap.get(lang)! } @@ -71,13 +71,13 @@ class I18nManager { } } - setCurrentLanguage (lang: string) { + setCurrentLanguage(lang: string) { const locales = this.getLocales(lang) this.currentLanguage = lang this.initI18n(lang, locales) } - private initI18n (lang: string = this.defaultLanguage, locales: ILocales) { + private initI18n(lang: string = this.defaultLanguage, locales: ILocales) { const objectAdapter = new ObjectAdapter({ [lang]: locales }) @@ -87,15 +87,15 @@ class I18nManager { }) } - T (key: ILocalesKey, args: IStringKeyMap = {}): string { + T(key: ILocalesKey, args: IStringKeyMap = {}): string { return this.i18n?.translate(key, args) || key } - get languageList () { + get languageList() { return this.i18nFileList } - getCurrentLocales () { + getCurrentLocales() { return { lang: this.currentLanguage, locales: this.getLocales(this.currentLanguage) diff --git a/src/main/index.ts b/src/main/index.ts index 49e08dce..3631fcfc 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,3 +1,3 @@ -import { lifeCycle } from '~/lifeCycle' - -lifeCycle.launchApp() +import { lifeCycle } from '~/lifeCycle' + +lifeCycle.launchApp() diff --git a/src/main/lifeCycle/errorHandler.ts b/src/main/lifeCycle/errorHandler.ts index c19ce1a9..9e1d04f2 100644 --- a/src/main/lifeCycle/errorHandler.ts +++ b/src/main/lifeCycle/errorHandler.ts @@ -24,9 +24,9 @@ process.on('unhandledRejection', (error: any) => { }) // acconrding to https://github.com/Molunerfinn/PicGo/commit/7363be798cfef11e980934e542817ff1d6c04389#diff-896d0db4fbd446798fbffec14d456b4cd98d4c72c46856c770a585fa7ab0926f -function bootstrapEPIPESuppression () { +function bootstrapEPIPESuppression() { let suppressing = false - function logEPIPEErrorOnce () { + function logEPIPEErrorOnce() { if (suppressing) { return } @@ -41,11 +41,11 @@ function bootstrapEPIPESuppression () { bootstrapEPIPESuppression() -function epipeBomb (stream: any, callback: any) { +function epipeBomb(stream: any, callback: any) { if (stream == null) stream = process.stdout if (callback == null) callback = process.exit - function epipeFilter (err: any) { + function epipeFilter(err: any) { if (err.code === 'EPIPE') return callback() // If there's more than one error handler (ie, us), diff --git a/src/main/lifeCycle/fixPath.ts b/src/main/lifeCycle/fixPath.ts index cacd747f..10f192d2 100644 --- a/src/main/lifeCycle/fixPath.ts +++ b/src/main/lifeCycle/fixPath.ts @@ -1,6 +1,6 @@ import { shellPathSync } from 'shell-path' -export default function fixPath () { +export default function fixPath() { if (process.platform === 'win32') { return } diff --git a/src/main/lifeCycle/index.ts b/src/main/lifeCycle/index.ts index 9f57e514..32b07aa8 100644 --- a/src/main/lifeCycle/index.ts +++ b/src/main/lifeCycle/index.ts @@ -1,354 +1,360 @@ -import '~/lifeCycle/errorHandler' - -import path from 'node:path' - -import bus from '@core/bus' -import db from '@core/datastore' -import picgo from '@core/picgo' -import logger from '@core/picgo/logger' -import { remoteNoticeHandler } from 'apis/app/remoteNotice' -import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler' -import { createTray, setDockMenu } from 'apis/app/system' -import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis' -import windowManager from 'apis/app/window/windowManager' -import axios from 'axios' -import { app, dialog, globalShortcut, Notification, protocol, screen, shell } from 'electron' -import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer' -import updater from 'electron-updater' -import fs from 'fs-extra' - -import busEventList from '~/events/busEventList' -import { rpcServer } from '~/events/rpc' -import { startFileServer, stopFileServer } from '~/fileServer' -import { T as $t } from '~/i18n' -import fixPath from '~/lifeCycle/fixPath' -import UpDownTaskQueue from '~/manage/datastore/upDownTaskQueue' -import getManageApi from '~/manage/Main' -import { clearTempFolder } from '~/manage/utils/common' -import server from '~/server/index' -import webServer from '~/server/webServer' -import beforeOpen from '~/utils/beforeOpen' -import clipboardPoll from '~/utils/clipboardPoll' -import { configPaths } from '~/utils/configPaths' -import { II18nLanguage, IRemoteNoticeTriggerHook, ISartMode, IWindowList } from '~/utils/enum' -import { getUploadFiles } from '~/utils/handleArgv' -import { initI18n } from '~/utils/handleI18n' -import { notificationList } from '~/utils/notification' -import { MemoryMonitor } from '~/utils/performanceOptimizer' -import { CLIPBOARD_IMAGE_FOLDER } from '~/utils/static' -import updateChecker from '~/utils/updateChecker' - -const isDevelopment = process.env.NODE_ENV !== 'production' - -const handleStartUpFiles = (argv: string[], cwd: string) => { - const files = getUploadFiles(argv, cwd, logger) - - if (files === null) { - logger.info('cli -> uploading file from clipboard') - uploadClipboardFiles() - return true - } - - if (files.length > 0) { - logger.info('cli -> uploading files from cli', ...files.map(file => file.path)) - const win = windowManager.getAvailableWindow() - uploadChoosedFiles(win.webContents, files) - return true - } - - return false -} - -updater.autoUpdater.setFeedURL({ - provider: 'generic', - url: 'https://release.piclist.cn/latest', - channel: 'latest' -}) - -updater.autoUpdater.autoDownload = false - -updater.autoUpdater.on('update-available', async (info: updater.UpdateInfo) => { - const lang = db.get(configPaths.settings.language) || II18nLanguage.ZH_CN - let updateLog = '' - try { - const url = - lang === II18nLanguage.ZH_CN - ? 'https://release.piclist.cn/currentVersion.md' - : 'https://release.piclist.cn/currentVersion_en.md' - const res = await axios.get(url) - updateLog = res.data - } catch (e: any) { - logger.error(e) - } - - const maxLogLength = 800 - let displayLog = updateLog - let truncatedNote = '' - - if (updateLog.length > maxLogLength) { - const truncatePoint = updateLog.lastIndexOf('\n', maxLogLength) - displayLog = updateLog.substring(0, truncatePoint > 0 ? truncatePoint : maxLogLength) - truncatedNote = - lang === II18nLanguage.ZH_CN - ? '\n\n... (更多详情请查看完整更新日志)' - : '\n\n... (See full changelog for more details)' - } - - dialog - .showMessageBox({ - type: 'info', - title: $t('FIND_NEW_VERSION'), - buttons: ['Yes', 'Go to download page'], - message: - $t('TIPS_FIND_NEW_VERSION', { - v: info.version - }) + - '\n\n' + - displayLog + - truncatedNote, - checkboxLabel: $t('NO_MORE_NOTICE'), - checkboxChecked: false - }) - .then(result => { - if (result.response === 0) { - updater.autoUpdater.downloadUpdate() - } else { - shell.openExternal('https://github.com/Kuingsmile/PicList/releases/latest') - } - db.set(configPaths.settings.showUpdateTip, !result.checkboxChecked) - }) - .catch(err => { - logger.error(err) - }) -}) - -updater.autoUpdater.on('download-progress', progressObj => { - const percent = { - progress: progressObj.percent - } - const window = windowManager.get(IWindowList.SETTING_WINDOW)! - window.webContents.send('updateProgress', percent) -}) - -updater.autoUpdater.on('update-downloaded', () => { - dialog - .showMessageBox({ - type: 'info', - title: $t('UPDATE_DOWNLOADED'), - buttons: ['Yes', 'No'], - message: $t('TIPS_UPDATE_DOWNLOADED') - }) - .then(result => { - const window = windowManager.get(IWindowList.SETTING_WINDOW)! - window.webContents.send('updateProgress', { progress: 100 }) - if (result.response === 0) { - updater.autoUpdater.quitAndInstall() - } - }) - .catch(err => { - logger.error(err) - }) -}) - -updater.autoUpdater.on('error', err => { - logger.error(err) -}) - -class LifeCycle { - async #beforeReady () { - protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }]) - // fix the $PATH in macOS & linux - fixPath() - beforeOpen() - getManageApi() - UpDownTaskQueue.getInstance() - initI18n() - rpcServer.start() - busEventList.listen() - - if (process.env.NODE_ENV === 'development') { - MemoryMonitor.start(30000) - } - } - - #onReady () { - const readyFunction = async () => { - if (process.env.NODE_ENV !== 'production') { - installExtension(VUEJS_DEVTOOLS).catch(err => { - logger.error('An error occurred: ', err) - }) - } - windowManager.create(IWindowList.TRAY_WINDOW) - windowManager.create(IWindowList.SETTING_WINDOW) - const isAutoListenClipboard = db.get(configPaths.settings.isAutoListenClipboard) || false - const ClipboardWatcher = clipboardPoll - if (isAutoListenClipboard) { - db.set(configPaths.settings.isListeningClipboard, true) - ClipboardWatcher.startListening() - ClipboardWatcher.on('change', () => { - picgo.log.info('clipboard changed') - uploadClipboardFiles() - }) - } else { - db.set(configPaths.settings.isListeningClipboard, false) - } - const isHideDock = db.get(configPaths.settings.isHideDock) || false - let startMode = db.get(configPaths.settings.startMode) || ISartMode.QUIET - if (process.platform === 'darwin' && startMode === ISartMode.MINI) { - startMode = ISartMode.QUIET - } - const currentPicBed = db.get(configPaths.picBed.uploader) || db.get(configPaths.picBed.current) || 'smms' - const currentPicBedConfig = db.get(`picBed.${currentPicBed}`)?._configName || 'Default' - const tooltip = `${currentPicBed} ${currentPicBedConfig}` - if (process.platform === 'darwin') { - isHideDock ? app.dock?.hide() : setDockMenu() - startMode !== ISartMode.NO_TRAY && createTray(tooltip) - } else { - createTray(tooltip) - } - db.set(configPaths.needReload, false) - updateChecker() - // 不需要阻塞 - process.nextTick(() => { - shortKeyHandler.init() - }) - server.startup() - webServer.start() - startFileServer() - if (process.env.NODE_ENV !== 'development') { - handleStartUpFiles(process.argv, process.cwd()) - } - - if (notificationList && notificationList.length > 0) { - while (notificationList.length) { - const option = notificationList.pop() - const notice = new Notification(option!) - notice.show() - } - } - await remoteNoticeHandler.init() - remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.APP_START) - if (startMode === ISartMode.MINI && process.platform !== 'darwin') { - windowManager.create(IWindowList.MINI_WINDOW) - 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) { - if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) { - miniWindow.setPosition(width - 100, height - 100) - db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100]) - } else if (lastPosition[0] + miniWindow.getSize()[0] > width || lastPosition[1] + miniWindow.getSize()[1] > height) { - miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]) - db.set(configPaths.settings.miniWindowPosition, [width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]]) - } else { - 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() - } else if (startMode === ISartMode.MAIN) { - const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! - settingWindow.show() - settingWindow.focus() - } - const clipboardDir = path.join(picgo.baseDir, CLIPBOARD_IMAGE_FOLDER) - fs.emptyDir(clipboardDir) - } - app.whenReady().then(readyFunction) - } - - #onRunning () { - app.on('second-instance', (_, commandLine, workingDirectory) => { - logger.info('detect second instance') - const result = handleStartUpFiles(commandLine, workingDirectory) - if (!result) { - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! - if (settingWindow.isMinimized()) { - settingWindow.restore() - } - settingWindow.focus() - } - } - }) - app.on('activate', () => { - if (!windowManager.has(IWindowList.TRAY_WINDOW)) { - windowManager.create(IWindowList.TRAY_WINDOW) - } - if (!windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.create(IWindowList.SETTING_WINDOW) - } - }) - app.setLoginItemSettings({ - openAtLogin: db.get(configPaths.settings.autoStart) || false - }) - if (process.platform === 'win32') { - app.setAppUserModelId('com.kuingsmile.piclist') - } - - if (process.env.XDG_CURRENT_DESKTOP && process.env.XDG_CURRENT_DESKTOP.includes('Unity')) { - process.env.XDG_CURRENT_DESKTOP = 'Unity' - } - } - - #onQuit () { - app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit() - } - }) - - app.on('will-quit', () => { - UpDownTaskQueue.getInstance().persist() - clearTempFolder() - globalShortcut.unregisterAll() - bus.removeAllListeners() - server.shutdown() - webServer.stop() - stopFileServer() - MemoryMonitor.stop() - }) - // Exit cleanly on request from parent process in development mode. - if (isDevelopment) { - if (process.platform === 'win32') { - process.on('message', data => { - if (data === 'graceful-exit') { - app.quit() - } - }) - } else { - process.on('SIGTERM', () => { - app.quit() - }) - } - } - } - - async launchApp () { - const gotTheLock = app.requestSingleInstanceLock() - if (!gotTheLock) { - app.quit() - } else { - await this.#beforeReady() - this.#onReady() - this.#onRunning() - this.#onQuit() - } - } -} - -const lifeCycle = new LifeCycle() - -export { lifeCycle } +import '~/lifeCycle/errorHandler' + +import path from 'node:path' + +import bus from '@core/bus' +import db from '@core/datastore' +import picgo from '@core/picgo' +import logger from '@core/picgo/logger' +import { remoteNoticeHandler } from 'apis/app/remoteNotice' +import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler' +import { createTray, setDockMenu } from 'apis/app/system' +import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis' +import windowManager from 'apis/app/window/windowManager' +import axios from 'axios' +import { app, dialog, globalShortcut, Notification, protocol, screen, shell } from 'electron' +import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer' +import updater from 'electron-updater' +import fs from 'fs-extra' + +import busEventList from '~/events/busEventList' +import { rpcServer } from '~/events/rpc' +import { startFileServer, stopFileServer } from '~/fileServer' +import { T as $t } from '~/i18n' +import fixPath from '~/lifeCycle/fixPath' +import UpDownTaskQueue from '~/manage/datastore/upDownTaskQueue' +import getManageApi from '~/manage/Main' +import { clearTempFolder } from '~/manage/utils/common' +import server from '~/server/index' +import webServer from '~/server/webServer' +import beforeOpen from '~/utils/beforeOpen' +import clipboardPoll from '~/utils/clipboardPoll' +import { configPaths } from '~/utils/configPaths' +import { II18nLanguage, IRemoteNoticeTriggerHook, ISartMode, IWindowList } from '~/utils/enum' +import { getUploadFiles } from '~/utils/handleArgv' +import { initI18n } from '~/utils/handleI18n' +import { notificationList } from '~/utils/notification' +import { MemoryMonitor } from '~/utils/performanceOptimizer' +import { CLIPBOARD_IMAGE_FOLDER } from '~/utils/static' +import updateChecker from '~/utils/updateChecker' + +const isDevelopment = process.env.NODE_ENV !== 'production' + +const handleStartUpFiles = (argv: string[], cwd: string) => { + const files = getUploadFiles(argv, cwd, logger) + + if (files === null) { + logger.info('cli -> uploading file from clipboard') + uploadClipboardFiles() + return true + } + + if (files.length > 0) { + logger.info('cli -> uploading files from cli', ...files.map(file => file.path)) + const win = windowManager.getAvailableWindow() + uploadChoosedFiles(win.webContents, files) + return true + } + + return false +} + +updater.autoUpdater.setFeedURL({ + provider: 'generic', + url: 'https://release.piclist.cn/latest', + channel: 'latest' +}) + +updater.autoUpdater.autoDownload = false + +updater.autoUpdater.on('update-available', async (info: updater.UpdateInfo) => { + const lang = db.get(configPaths.settings.language) || II18nLanguage.ZH_CN + let updateLog = '' + try { + const url = + lang === II18nLanguage.ZH_CN + ? 'https://release.piclist.cn/currentVersion.md' + : 'https://release.piclist.cn/currentVersion_en.md' + const res = await axios.get(url) + updateLog = res.data + } catch (e: any) { + logger.error(e) + } + + const maxLogLength = 800 + let displayLog = updateLog + let truncatedNote = '' + + if (updateLog.length > maxLogLength) { + const truncatePoint = updateLog.lastIndexOf('\n', maxLogLength) + displayLog = updateLog.substring(0, truncatePoint > 0 ? truncatePoint : maxLogLength) + truncatedNote = + lang === II18nLanguage.ZH_CN + ? '\n\n... (更多详情请查看完整更新日志)' + : '\n\n... (See full changelog for more details)' + } + + dialog + .showMessageBox({ + type: 'info', + title: $t('FIND_NEW_VERSION'), + buttons: ['Yes', 'Go to download page'], + message: + $t('TIPS_FIND_NEW_VERSION', { + v: info.version + }) + + '\n\n' + + displayLog + + truncatedNote, + checkboxLabel: $t('NO_MORE_NOTICE'), + checkboxChecked: false + }) + .then(result => { + if (result.response === 0) { + updater.autoUpdater.downloadUpdate() + } else { + shell.openExternal('https://github.com/Kuingsmile/PicList/releases/latest') + } + db.set(configPaths.settings.showUpdateTip, !result.checkboxChecked) + }) + .catch(err => { + logger.error(err) + }) +}) + +updater.autoUpdater.on('download-progress', progressObj => { + const percent = { + progress: progressObj.percent + } + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + window.webContents.send('updateProgress', percent) +}) + +updater.autoUpdater.on('update-downloaded', () => { + dialog + .showMessageBox({ + type: 'info', + title: $t('UPDATE_DOWNLOADED'), + buttons: ['Yes', 'No'], + message: $t('TIPS_UPDATE_DOWNLOADED') + }) + .then(result => { + const window = windowManager.get(IWindowList.SETTING_WINDOW)! + window.webContents.send('updateProgress', { progress: 100 }) + if (result.response === 0) { + updater.autoUpdater.quitAndInstall() + } + }) + .catch(err => { + logger.error(err) + }) +}) + +updater.autoUpdater.on('error', err => { + logger.error(err) +}) + +class LifeCycle { + async #beforeReady() { + protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }]) + // fix the $PATH in macOS & linux + fixPath() + beforeOpen() + getManageApi() + UpDownTaskQueue.getInstance() + initI18n() + rpcServer.start() + busEventList.listen() + + if (process.env.NODE_ENV === 'development') { + MemoryMonitor.start(30000) + } + } + + #onReady() { + const readyFunction = async () => { + if (process.env.NODE_ENV !== 'production') { + installExtension(VUEJS_DEVTOOLS).catch(err => { + logger.error('An error occurred: ', err) + }) + } + windowManager.create(IWindowList.TRAY_WINDOW) + windowManager.create(IWindowList.SETTING_WINDOW) + const isAutoListenClipboard = db.get(configPaths.settings.isAutoListenClipboard) || false + const ClipboardWatcher = clipboardPoll + if (isAutoListenClipboard) { + db.set(configPaths.settings.isListeningClipboard, true) + ClipboardWatcher.startListening() + ClipboardWatcher.on('change', () => { + picgo.log.info('clipboard changed') + uploadClipboardFiles() + }) + } else { + db.set(configPaths.settings.isListeningClipboard, false) + } + const isHideDock = db.get(configPaths.settings.isHideDock) || false + let startMode = db.get(configPaths.settings.startMode) || ISartMode.QUIET + if (process.platform === 'darwin' && startMode === ISartMode.MINI) { + startMode = ISartMode.QUIET + } + const currentPicBed = db.get(configPaths.picBed.uploader) || db.get(configPaths.picBed.current) || 'smms' + const currentPicBedConfig = db.get(`picBed.${currentPicBed}`)?._configName || 'Default' + const tooltip = `${currentPicBed} ${currentPicBedConfig}` + if (process.platform === 'darwin') { + isHideDock ? app.dock?.hide() : setDockMenu() + startMode !== ISartMode.NO_TRAY && createTray(tooltip) + } else { + createTray(tooltip) + } + db.set(configPaths.needReload, false) + updateChecker() + // 不需要阻塞 + process.nextTick(() => { + shortKeyHandler.init() + }) + server.startup() + webServer.start() + startFileServer() + if (process.env.NODE_ENV !== 'development') { + handleStartUpFiles(process.argv, process.cwd()) + } + + if (notificationList && notificationList.length > 0) { + while (notificationList.length) { + const option = notificationList.pop() + const notice = new Notification(option!) + notice.show() + } + } + await remoteNoticeHandler.init() + remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.APP_START) + if (startMode === ISartMode.MINI && process.platform !== 'darwin') { + windowManager.create(IWindowList.MINI_WINDOW) + 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) { + if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) { + miniWindow.setPosition(width - 100, height - 100) + db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100]) + } else if ( + lastPosition[0] + miniWindow.getSize()[0] > width || + lastPosition[1] + miniWindow.getSize()[1] > height + ) { + miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]) + db.set(configPaths.settings.miniWindowPosition, [ + width - miniWindow.getSize()[0], + height - miniWindow.getSize()[1] + ]) + } else { + 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() + } else if (startMode === ISartMode.MAIN) { + const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! + settingWindow.show() + settingWindow.focus() + } + const clipboardDir = path.join(picgo.baseDir, CLIPBOARD_IMAGE_FOLDER) + fs.emptyDir(clipboardDir) + } + app.whenReady().then(readyFunction) + } + + #onRunning() { + app.on('second-instance', (_, commandLine, workingDirectory) => { + logger.info('detect second instance') + const result = handleStartUpFiles(commandLine, workingDirectory) + if (!result) { + if (windowManager.has(IWindowList.SETTING_WINDOW)) { + const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! + if (settingWindow.isMinimized()) { + settingWindow.restore() + } + settingWindow.focus() + } + } + }) + app.on('activate', () => { + if (!windowManager.has(IWindowList.TRAY_WINDOW)) { + windowManager.create(IWindowList.TRAY_WINDOW) + } + if (!windowManager.has(IWindowList.SETTING_WINDOW)) { + windowManager.create(IWindowList.SETTING_WINDOW) + } + }) + app.setLoginItemSettings({ + openAtLogin: db.get(configPaths.settings.autoStart) || false + }) + if (process.platform === 'win32') { + app.setAppUserModelId('com.kuingsmile.piclist') + } + + if (process.env.XDG_CURRENT_DESKTOP && process.env.XDG_CURRENT_DESKTOP.includes('Unity')) { + process.env.XDG_CURRENT_DESKTOP = 'Unity' + } + } + + #onQuit() { + app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } + }) + + app.on('will-quit', () => { + UpDownTaskQueue.getInstance().persist() + clearTempFolder() + globalShortcut.unregisterAll() + bus.removeAllListeners() + server.shutdown() + webServer.stop() + stopFileServer() + MemoryMonitor.stop() + }) + // Exit cleanly on request from parent process in development mode. + if (isDevelopment) { + if (process.platform === 'win32') { + process.on('message', data => { + if (data === 'graceful-exit') { + app.quit() + } + }) + } else { + process.on('SIGTERM', () => { + app.quit() + }) + } + } + } + + async launchApp() { + const gotTheLock = app.requestSingleInstanceLock() + if (!gotTheLock) { + app.quit() + } else { + await this.#beforeReady() + this.#onReady() + this.#onRunning() + this.#onQuit() + } + } +} + +const lifeCycle = new LifeCycle() + +export { lifeCycle } diff --git a/src/main/manage/apis/aliyun.ts b/src/main/manage/apis/aliyun.ts index 81613306..5cd9d0bd 100644 --- a/src/main/manage/apis/aliyun.ts +++ b/src/main/manage/apis/aliyun.ts @@ -28,7 +28,7 @@ class AliyunApi { timeOut = 30000 logger: ManageLogger - constructor (accessKeyId: string, accessKeySecret: string, logger: ManageLogger) { + constructor(accessKeyId: string, accessKeySecret: string, logger: ManageLogger) { this.ctx = new OSS({ accessKeyId, accessKeySecret, @@ -39,7 +39,7 @@ class AliyunApi { this.logger = logger } - formatFolder (item: string, slicedPrefix: string, urlPrefix: string): any { + formatFolder(item: string, slicedPrefix: string, urlPrefix: string): any { return { key: item, url: `${urlPrefix}/${item}`, @@ -54,7 +54,7 @@ class AliyunApi { } } - formatFile (item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any { + formatFile(item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any { const fileName = item.name.replace(slicedPrefix, '') return { ...item, @@ -71,7 +71,7 @@ class AliyunApi { } } - getCanonicalizedOSSHeaders (headers: IStringKeyMap) { + getCanonicalizedOSSHeaders(headers: IStringKeyMap) { const lowerCaseHeaders = Object.keys(headers).reduce((acc, key) => { acc[key.toLowerCase()] = headers[key] return acc @@ -84,7 +84,7 @@ class AliyunApi { return canonicalizedOSSHeaders } - authorization ( + authorization( method: string, canonicalizedResource: string, headers: IStringKeyMap, @@ -96,7 +96,7 @@ class AliyunApi { return `OSS ${this.accessKeyId}:${hmacSha1Base64(this.accessKeySecret, stringToSign)}` } - getNewCtx (region: string, bucket: string) { + getNewCtx(region: string, bucket: string) { return new OSS({ accessKeyId: this.accessKeyId, accessKeySecret: this.accessKeySecret, @@ -109,7 +109,7 @@ class AliyunApi { /** * 获取存储桶列表 */ - async getBucketList (): Promise { + async getBucketList(): Promise { const getBuckets = async (marker?: string) => { const res = (await this.ctx.listBuckets({ marker, @@ -143,7 +143,7 @@ class AliyunApi { /** * 获取自定义域名 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const headers = { Date: new Date().toUTCString() } @@ -186,7 +186,7 @@ class AliyunApi { * @description * acl: private | publicRead | publicReadWrite */ - async createBucket (configMap: IStringKeyMap): Promise { + async createBucket(configMap: IStringKeyMap): Promise { const client = new OSS({ accessKeyId: this.accessKeyId, accessKeySecret: this.accessKeySecret, @@ -207,7 +207,7 @@ class AliyunApi { return res?.res?.status === 200 } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, @@ -262,7 +262,7 @@ class AliyunApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, @@ -336,7 +336,7 @@ class AliyunApi { * customUrl: string * } */ - async getBucketFileList (configMap: IStringKeyMap): Promise { + async getBucketFileList(configMap: IStringKeyMap): Promise { const { bucketName: bucket, bucketConfig: { Location: region }, @@ -393,7 +393,7 @@ class AliyunApi { * newKey: string * } */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, oldKey, newKey } = configMap const client = this.getNewCtx(region, bucketName) const copyRes = (await client.copy(newKey, oldKey)) as any @@ -413,7 +413,7 @@ class AliyunApi { * key: string * } */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const client = this.getNewCtx(region, bucketName) const res = (await client.delete(key)) as any @@ -424,7 +424,7 @@ class AliyunApi { * 删除文件夹 * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const client = this.getNewCtx(region, bucketName) let marker @@ -486,7 +486,7 @@ class AliyunApi { * customUrl: string * } */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName, region, key, expires, customUrl } = configMap const client = this.getNewCtx(region, bucketName) const res = client.signatureUrl(key, { @@ -499,7 +499,7 @@ class AliyunApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap // fileArray = [{ // bucketName: string, @@ -586,7 +586,7 @@ class AliyunApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const client = this.getNewCtx(region, bucketName) const res = (await client.put(key, Buffer.from(''))) as any @@ -597,7 +597,7 @@ class AliyunApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/apis/github.ts b/src/main/manage/apis/github.ts index 6831d55e..63154d0f 100644 --- a/src/main/manage/apis/github.ts +++ b/src/main/manage/apis/github.ts @@ -29,7 +29,7 @@ class GithubApi { baseUrl = 'https://api.github.com' commonHeaders: IStringKeyMap - constructor (token: string, username: string, proxy: string | undefined, logger: ManageLogger) { + constructor(token: string, username: string, proxy: string | undefined, logger: ManageLogger) { this.logger = logger this.token = token.startsWith('Bearer ') ? token : `Bearer ${token}`.trim() this.username = username @@ -41,7 +41,7 @@ class GithubApi { } } - formatFolder (item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) { + formatFolder(item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) { const key = `${slicedPrefix ? `${slicedPrefix}/` : ''}${item.path}/` let rawUrl = '' const placeholders = ['{username}', '{repo}', '{branch}', '{path}'] @@ -78,7 +78,7 @@ class GithubApi { } } - formatFile (item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) { + formatFile(item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) { let rawUrl = '' const placeholders = ['{username}', '{repo}', '{branch}', '{path}'] const key = slicedPrefix === '' ? item.path : `${slicedPrefix}/${item.path}` @@ -119,7 +119,7 @@ class GithubApi { /** * get repo list */ - async getBucketList (): Promise { + async getBucketList(): Promise { let initPage = 1 let res const result = [] as any[] @@ -156,7 +156,7 @@ class GithubApi { /** * 获取branch列表 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const { bucketName: repo } = param let initPage = 1 let res @@ -184,7 +184,7 @@ class GithubApi { return result } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '') @@ -235,7 +235,7 @@ class GithubApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '') @@ -285,7 +285,7 @@ class GithubApi { * key: string * } */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName: repo, githubBranch: branch, key, DeleteHash: sha } = configMap const body = { message: 'deleted by PicList', @@ -303,7 +303,7 @@ class GithubApi { * create a new tree to delete a folder * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName: repo, githubBranch: branch, key } = configMap // get sha of the branch const refRes = (await got( @@ -412,7 +412,7 @@ class GithubApi { * customUrl: string * } */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName: repo, customUrl: branch, key, rawUrl, githubPrivate: isPrivate } = configMap if (!isPrivate) return rawUrl const res = (await got( @@ -436,7 +436,7 @@ class GithubApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName: repo, githubBranch: branch, key } = configMap const newFileKey = `${trimPath(key)}/.gitkeep` const base64Content = Buffer.from('created by PicList').toString('base64') @@ -456,7 +456,7 @@ class GithubApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -505,7 +505,7 @@ class GithubApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/apis/imgur.ts b/src/main/manage/apis/imgur.ts index de00fb9c..36c995a4 100644 --- a/src/main/manage/apis/imgur.ts +++ b/src/main/manage/apis/imgur.ts @@ -31,7 +31,7 @@ class ImgurApi { idHeaders: any baseUrl = 'https://api.imgur.com/3' - constructor (userName: string, accessToken: string, proxy: any, logger: ManageLogger) { + constructor(userName: string, accessToken: string, proxy: any, logger: ManageLogger) { this.userName = userName this.accessToken = accessToken.startsWith('Bearer ') ? accessToken : `Bearer ${accessToken}` this.proxy = proxy @@ -42,7 +42,7 @@ class ImgurApi { } } - formatFile (item: any) { + formatFile(item: any) { const fileName = path.basename(item.link) const isImg = isImage(fileName) return { @@ -64,7 +64,7 @@ class ImgurApi { /** * get repo list */ - async getBucketList (): Promise { + async getBucketList(): Promise { let initPage = 0 let res const result = [] as any[] @@ -93,7 +93,7 @@ class ImgurApi { return finalResult } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketConfig: { Location: albumHash }, @@ -153,7 +153,7 @@ class ImgurApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { DeleteHash: deleteHash } = configMap const res = (await got( `${this.baseUrl}/account/${this.userName}/image/${deleteHash}`, @@ -166,7 +166,7 @@ class ImgurApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -226,7 +226,7 @@ class ImgurApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/apis/local.ts b/src/main/manage/apis/local.ts index dfc94f0b..b9985f97 100644 --- a/src/main/manage/apis/local.ts +++ b/src/main/manage/apis/local.ts @@ -17,7 +17,7 @@ class LocalApi { logger: ManageLogger isWindows: boolean - constructor (logger: ManageLogger) { + constructor(logger: ManageLogger) { this.logger = logger this.isWindows = process.platform === 'win32' } @@ -25,12 +25,12 @@ class LocalApi { logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'LocalApi', method })) // windows 系统下将路径转换为 unix 风格 - transPathToUnix (filePath: string | undefined) { + transPathToUnix(filePath: string | undefined) { if (!filePath) return '' return this.isWindows ? filePath.split(path.sep).join(path.posix.sep) : filePath.replace(/^\/+/, '') } - transBack (filePath: string | undefined) { + transBack(filePath: string | undefined) { if (!filePath) return '' return this.isWindows ? filePath @@ -40,7 +40,7 @@ class LocalApi { : `/${filePath.replace(/^\/+|\/+$/g, '')}` } - formatFolder (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) { + formatFolder(item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) { const key = `${this.transPathToUnix(filePath)}/`.replace(/\/+$/, '/') return { ...item, @@ -57,7 +57,7 @@ class LocalApi { } } - formatFile (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string, isDownload = false) { + formatFile(item: fs.Stats, urlPrefix: string, fileName: string, filePath: string, isDownload = false) { const key = isDownload ? filePath : this.transPathToUnix(filePath) return { ...item, @@ -74,7 +74,7 @@ class LocalApi { } } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl = '', cancelToken } = configMap const urlPrefix = customUrl.replace(/\/+$/, '') @@ -114,7 +114,7 @@ class LocalApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { customUrl = '', cancelToken, baseDir } = configMap let prefix = configMap.prefix @@ -170,7 +170,7 @@ class LocalApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { oldKey, newKey } = configMap let result = false try { @@ -182,7 +182,7 @@ class LocalApi { return result } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -194,7 +194,7 @@ class LocalApi { return result } - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -208,7 +208,7 @@ class LocalApi { return result } - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -250,7 +250,7 @@ class LocalApi { return true } - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -264,7 +264,7 @@ class LocalApi { return result } - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { diff --git a/src/main/manage/apis/qiniu.ts b/src/main/manage/apis/qiniu.ts index 9b7c67db..933695ad 100644 --- a/src/main/manage/apis/qiniu.ts +++ b/src/main/manage/apis/qiniu.ts @@ -33,14 +33,14 @@ class QiniuApi { getBucketDomain: 'https://uc.qiniuapi.com/v2/domains' } - constructor (accessKey: string, secretKey: string, logger: ManageLogger) { + constructor(accessKey: string, secretKey: string, logger: ManageLogger) { this.mac = new qiniu.auth.digest.Mac(accessKey, secretKey) this.accessKey = accessKey this.secretKey = secretKey this.logger = logger } - formatFolder (item: string, slicedPrefix: string, urlPrefix: string) { + formatFolder(item: string, slicedPrefix: string, urlPrefix: string) { return { Key: item, key: item, @@ -54,7 +54,7 @@ class QiniuApi { } } - formatFile (item: any, slicedPrefix: string, urlPrefix: string) { + formatFile(item: any, slicedPrefix: string, urlPrefix: string) { const fileName = item.key.replace(slicedPrefix, '') return { ...item, @@ -69,7 +69,7 @@ class QiniuApi { } } - authorization ( + authorization( method: string, urlPath: string, host: string, @@ -98,7 +98,7 @@ class QiniuApi { /** * 获取存储桶列表 */ - async getBucketList (): Promise { + async getBucketList(): Promise { const host = this.hostList.getBucketList const authorization = qiniu.util.generateAccessToken(this.mac, host, undefined) const res = await axios.get(host, { @@ -128,7 +128,7 @@ class QiniuApi { /** * 获取存储桶详细信息 */ - async getBucketInfo (param: IStringKeyMap): Promise { + async getBucketInfo(param: IStringKeyMap): Promise { const { bucketName } = param const urlPath = `/v2/bucketInfo?bucket=${bucketName}&fs=true` const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json') @@ -160,7 +160,7 @@ class QiniuApi { /** * 获取自定义域名 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const { bucketName } = param const host = this.hostList.getBucketDomain const authorization = qiniu.util.generateAccessToken(this.mac, `${host}?tbl=${bucketName}`, undefined) @@ -180,7 +180,7 @@ class QiniuApi { /** * 修改存储桶权限 */ - async setBucketAclPolicy (param: IStringKeyMap): Promise { + async setBucketAclPolicy(param: IStringKeyMap): Promise { // 0: 公开访问 1: 私有访问 const { bucketName } = param let { isPrivate } = param @@ -213,7 +213,7 @@ class QiniuApi { * acl: boolean // 是否公开访问 * } */ - async createBucket (configMap: IStringKeyMap): Promise { + async createBucket(configMap: IStringKeyMap): Promise { const { BucketName, region, acl } = configMap const urlPath = `/mkbucketv3/${BucketName}/region/${region}` const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json') @@ -235,7 +235,7 @@ class QiniuApi { : false } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap let marker = undefined as any @@ -297,7 +297,7 @@ class QiniuApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap let marker = undefined as any @@ -380,7 +380,7 @@ class QiniuApi { * customUrl: string * } */ - async getBucketFileList (configMap: IStringKeyMap): Promise { + async getBucketFileList(configMap: IStringKeyMap): Promise { const { bucketName: bucket, prefix, marker, itemsPerPage, customUrl: urlPrefix } = configMap const slicedPrefix = prefix.slice(1) const config = new qiniu.conf.Config() @@ -440,7 +440,7 @@ class QiniuApi { * key: string * } */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, key } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -463,7 +463,7 @@ class QiniuApi { * 删除文件夹 * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, key } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -535,7 +535,7 @@ class QiniuApi { * newKey: string * } */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, oldKey, newKey } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -574,7 +574,7 @@ class QiniuApi { * customUrl: string * } */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { key, expires, customUrl } = configMap const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -588,7 +588,7 @@ class QiniuApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -667,7 +667,7 @@ class QiniuApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, key } = configMap const putPolicy = new qiniu.rs.PutPolicy({ scope: `${bucketName}:${key}` @@ -694,7 +694,7 @@ class QiniuApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/apis/s3plist.ts b/src/main/manage/apis/s3plist.ts index 29f89082..76e06135 100644 --- a/src/main/manage/apis/s3plist.ts +++ b/src/main/manage/apis/s3plist.ts @@ -46,7 +46,7 @@ class S3plistApi { secretAccessKey: string bucketName: string - constructor ( + constructor( accessKeyId: string, secretAccessKey: string, endpoint: string | undefined, @@ -75,7 +75,7 @@ class S3plistApi { this.proxy = formatHttpProxy(proxy, 'string') as string | undefined } - async getDogeCloudToken () { + async getDogeCloudToken() { if (!this.dogeCloudSupport) return const token = (await getTempToken(this.accessKeyId, this.secretAccessKey)) as DogecloudToken if (Object.keys(token).length === 0) { @@ -88,7 +88,7 @@ class S3plistApi { } } - setAgent (proxy: string | undefined, sslEnabled: boolean): NodeHttpHandler { + setAgent(proxy: string | undefined, sslEnabled: boolean): NodeHttpHandler { const agent = getAgent(proxy, sslEnabled) const commonOptions: AgentOptions = { keepAlive: true, @@ -98,26 +98,26 @@ class S3plistApi { const extraOptions = sslEnabled ? { rejectUnauthorized: false } : {} return sslEnabled ? new NodeHttpHandler({ - httpsAgent: agent.https - ? agent.https - : new https.Agent({ - ...commonOptions, - ...extraOptions - }) - }) + httpsAgent: agent.https + ? agent.https + : new https.Agent({ + ...commonOptions, + ...extraOptions + }) + }) : new NodeHttpHandler({ - httpAgent: agent.http - ? agent.http - : new http.Agent({ - ...commonOptions, - ...extraOptions - }) - }) + httpAgent: agent.http + ? agent.http + : new http.Agent({ + ...commonOptions, + ...extraOptions + }) + }) } logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'S3plistApi', method })) - formatFolder (item: CommonPrefix, slicedPrefix: string, urlPrefix: string): any { + formatFolder(item: CommonPrefix, slicedPrefix: string, urlPrefix: string): any { return { Key: item.Prefix, url: `${urlPrefix}/${item.Prefix}`, @@ -132,7 +132,7 @@ class S3plistApi { } } - formatFile (item: _Object, slicedPrefix: string, urlPrefix: string): any { + formatFile(item: _Object, slicedPrefix: string, urlPrefix: string): any { const fileName = item.Key?.replace(slicedPrefix, '') return { ...item, @@ -148,7 +148,7 @@ class S3plistApi { } } - async putPublicAccess (bucketName: string, client: S3Client) { + async putPublicAccess(bucketName: string, client: S3Client) { const input = { Bucket: bucketName, PublicAccessBlockConfiguration: { @@ -175,11 +175,11 @@ class S3plistApi { * acl: string * } */ - async createBucket (configMap: IStringKeyMap): Promise { + async createBucket(configMap: IStringKeyMap): Promise { const { BucketName, region, acl, endpoint } = configMap try { await this.getDogeCloudToken() - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const command = new ListBucketsCommand({}) @@ -234,7 +234,7 @@ class S3plistApi { /** * 获取存储桶列表 */ - async getBucketList (): Promise { + async getBucketList(): Promise { if (this.dogeCloudSupport) { try { const res = await dogecloudApi('/oss/bucket/list.json', {}, false, this.accessKeyId, this.secretAccessKey) @@ -255,7 +255,7 @@ class S3plistApi { } return [] } - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig const result: IStringKeyMap[] = [] const endpoint = (options.endpoint as string) || '' options.region = endpoint.includes('cloudflarestorage') ? 'auto' : 'us-east-1' @@ -305,7 +305,7 @@ class S3plistApi { return result } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, @@ -331,7 +331,7 @@ class S3plistApi { } try { do { - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const command = new ListObjectsV2Command({ @@ -369,7 +369,7 @@ class S3plistApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, @@ -396,7 +396,7 @@ class S3plistApi { try { await this.getDogeCloudToken() do { - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const command = new ListObjectsV2Command({ @@ -439,7 +439,7 @@ class S3plistApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async getBucketFileList (configMap: IStringKeyMap): Promise { + async getBucketFileList(configMap: IStringKeyMap): Promise { const { bucketName: bucket, bucketConfig: { Location: region }, @@ -457,10 +457,10 @@ class S3plistApi { } try { await this.getDogeCloudToken() - const options = ({ - - ...this.baseOptions, region: String(region) || 'us-east-1' - }) as S3ClientConfig + const options = { + ...this.baseOptions, + region: String(region) || 'us-east-1' + } as S3ClientConfig const client = new S3Client(options) const command = new ListObjectsV2Command({ Bucket: bucket, @@ -495,15 +495,15 @@ class S3plistApi { * newKey: string * } */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, oldKey, newKey } = configMap let result = false try { await this.getDogeCloudToken() - const options = ({ - - ...this.baseOptions, region: String(region) || 'us-east-1' - }) as S3ClientConfig + const options = { + ...this.baseOptions, + region: String(region) || 'us-east-1' + } as S3ClientConfig const client = new S3Client(options) const command = new CopyObjectCommand({ Bucket: bucketName, @@ -540,12 +540,12 @@ class S3plistApi { * key: string * } */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let result = false try { await this.getDogeCloudToken() - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const command = new DeleteObjectCommand({ @@ -568,7 +568,7 @@ class S3plistApi { * 删除文件夹 * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let marker let result = false @@ -581,7 +581,7 @@ class S3plistApi { try { await this.getDogeCloudToken() do { - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const command = new ListObjectsV2Command({ @@ -616,7 +616,7 @@ class S3plistApi { } if (allFileList.Contents.length > 0) { const cycle = Math.ceil(allFileList.Contents.length / 1000) - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) for (let i = 0; i < cycle; i++) { @@ -657,11 +657,11 @@ class S3plistApi { * customUrl: string * } */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName, region, key, expires } = configMap try { await this.getDogeCloudToken() - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const signedUrl = await getSignedUrl( @@ -685,12 +685,12 @@ class S3plistApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let result = false try { await this.getDogeCloudToken() - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const command = new PutObjectCommand({ @@ -713,7 +713,7 @@ class S3plistApi { * upload file * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap // fileArray = [{ // bucketName: string, @@ -764,7 +764,7 @@ class S3plistApi { }) continue } - const options = ({ ...this.baseOptions }) as S3ClientConfig + const options = { ...this.baseOptions } as S3ClientConfig options.region = String(region) || 'us-east-1' const client = new S3Client(options) const fileStream = fs.createReadStream(filePath) @@ -825,7 +825,7 @@ class S3plistApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/apis/sftp.ts b/src/main/manage/apis/sftp.ts index bc35e431..778250dc 100644 --- a/src/main/manage/apis/sftp.ts +++ b/src/main/manage/apis/sftp.ts @@ -44,7 +44,7 @@ class SftpApi { passphrase: string } - constructor ( + constructor( host: string, port: Undefinable, username: Undefinable, @@ -94,7 +94,7 @@ class SftpApi { return `0${result}` } - formatFolder (item: listDirResult, urlPrefix: string, isWebPath = false) { + formatFolder(item: listDirResult, urlPrefix: string, isWebPath = false) { const key = item.key let url: string if (isWebPath) { @@ -121,7 +121,7 @@ class SftpApi { } } - formatFile (item: listDirResult, urlPrefix: string, isWebPath = false) { + formatFile(item: listDirResult, urlPrefix: string, isWebPath = false) { const key = item.key return { ...item, @@ -151,7 +151,7 @@ class SftpApi { } } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken } = configMap const urlPrefix = customUrl || `${this.host}:${this.port}` @@ -191,7 +191,7 @@ class SftpApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - formatLSResult (res: string, cwd: string): listDirResult[] { + formatLSResult(res: string, cwd: string): listDirResult[] { const result = [] as listDirResult[] const resArray = res.trim().split('\n') resArray.slice(resArray[0].startsWith('total') ? 1 : 0).forEach((item: string) => { @@ -217,7 +217,7 @@ class SftpApi { return result } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken, baseDir } = configMap let urlPrefix = customUrl || `${this.host}:${this.port}` @@ -276,7 +276,7 @@ class SftpApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { oldKey, newKey } = configMap let result = false try { @@ -290,7 +290,7 @@ class SftpApi { return result } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -304,7 +304,7 @@ class SftpApi { return result } - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -321,7 +321,7 @@ class SftpApi { return result } - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -376,7 +376,7 @@ class SftpApi { return true } - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -390,7 +390,7 @@ class SftpApi { return result } - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { diff --git a/src/main/manage/apis/smms.ts b/src/main/manage/apis/smms.ts index 9a069ab8..e6acc8c0 100644 --- a/src/main/manage/apis/smms.ts +++ b/src/main/manage/apis/smms.ts @@ -21,7 +21,7 @@ class SmmsApi { logger: ManageLogger timeout = 30000 - constructor (token: string, logger: ManageLogger) { + constructor(token: string, logger: ManageLogger) { this.token = token this.axiosInstance = axios.create({ baseURL: this.baseUrl, @@ -37,7 +37,7 @@ class SmmsApi { this.logger = logger } - formatFile (item: any) { + formatFile(item: any) { return { ...item, Key: item.path, @@ -54,7 +54,7 @@ class SmmsApi { } } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { cancelToken } = configMap let marker = 1 @@ -123,7 +123,7 @@ class SmmsApi { * customUrl: string * } */ - async getBucketFileList ({ currentPage }: IStringKeyMap): Promise { + async getBucketFileList({ currentPage }: IStringKeyMap): Promise { const result = { fullList: [] as any, isTruncated: false, @@ -162,7 +162,7 @@ class SmmsApi { * DeleteHash: string * } */ - async deleteBucketFile ({ DeleteHash }: IStringKeyMap): Promise { + async deleteBucketFile({ DeleteHash }: IStringKeyMap): Promise { const res = await this.axiosInstance(`/delete/${DeleteHash}`, { method: 'GET', params: { @@ -177,7 +177,7 @@ class SmmsApi { * 上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -214,7 +214,7 @@ class SmmsApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/apis/tcyun.ts b/src/main/manage/apis/tcyun.ts index bdee2474..eafdd1ac 100644 --- a/src/main/manage/apis/tcyun.ts +++ b/src/main/manage/apis/tcyun.ts @@ -17,7 +17,7 @@ class TcyunApi { ctx: COS logger: ManageLogger - constructor (secretId: string, secretKey: string, logger: ManageLogger) { + constructor(secretId: string, secretKey: string, logger: ManageLogger) { this.ctx = new COS({ SecretId: secretId, SecretKey: secretKey @@ -25,7 +25,7 @@ class TcyunApi { this.logger = logger } - formatFolder (item: { Prefix: string }, slicedPrefix: string, urlPrefix: string) { + formatFolder(item: { Prefix: string }, slicedPrefix: string, urlPrefix: string) { return { ...item, key: item.Prefix, @@ -40,7 +40,7 @@ class TcyunApi { } } - formatFile (item: COS.CosObject, slicedPrefix: string, urlPrefix: string): any { + formatFile(item: COS.CosObject, slicedPrefix: string, urlPrefix: string): any { return { ...item, key: item.Key, @@ -58,7 +58,7 @@ class TcyunApi { /** * 获取存储桶列表 */ - async getBucketList (): Promise { + async getBucketList(): Promise { const res = await this.ctx.getService({}) return res?.Buckets || [] } @@ -66,7 +66,7 @@ class TcyunApi { /** * 获取自定义域名 */ - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { const { bucketName, region } = param const res = await this.ctx.getBucketDomain({ Bucket: bucketName, @@ -87,7 +87,7 @@ class TcyunApi { * @description * acl: private | publicRead | publicReadWrite */ - async createBucket (configMap: IStringKeyMap): Promise { + async createBucket(configMap: IStringKeyMap): Promise { const res = await this.ctx.putBucket({ ACL: configMap.acl, Bucket: configMap.BucketName, @@ -96,7 +96,7 @@ class TcyunApi { return res?.statusCode === 200 } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, @@ -150,7 +150,7 @@ class TcyunApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, @@ -221,7 +221,7 @@ class TcyunApi { * customUrl: string * } */ - async getBucketFileList (configMap: IStringKeyMap): Promise { + async getBucketFileList(configMap: IStringKeyMap): Promise { const { bucketName: bucket, bucketConfig: { Location: region }, @@ -272,7 +272,7 @@ class TcyunApi { * newKey: string * } */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, oldKey, newKey } = configMap const copyRes = await this.ctx.putObjectCopy({ Bucket: bucketName, @@ -301,7 +301,7 @@ class TcyunApi { * key: string * } */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const res = await this.ctx.deleteObject({ Bucket: bucketName, @@ -315,7 +315,7 @@ class TcyunApi { * 删除文件夹 * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap let marker let res: any @@ -346,7 +346,9 @@ class TcyunApi { region, key: item.Prefix })) - ) { return false } + ) { + return false + } } const cycles = Math.ceil(allFileList.Contents.length / 1000) for (let i = 0; i < cycles; i++) { @@ -371,7 +373,7 @@ class TcyunApi { * customUrl: string * } */ - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { bucketName, region, key, expires, customUrl } = configMap const res = this.ctx.getObjectUrl( { @@ -390,7 +392,7 @@ class TcyunApi { * 高级上传文件 * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap // fileArray = [{ // bucketName: string, @@ -470,7 +472,7 @@ class TcyunApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, region, key } = configMap const res = await this.ctx.putObject({ Bucket: bucketName, @@ -485,7 +487,7 @@ class TcyunApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray } = configMap // fileArray = [{ // bucketName: string, diff --git a/src/main/manage/apis/upyun.ts b/src/main/manage/apis/upyun.ts index eac881c6..dfc8da58 100644 --- a/src/main/manage/apis/upyun.ts +++ b/src/main/manage/apis/upyun.ts @@ -34,7 +34,7 @@ class UpyunApi { stopMarker = 'g2gCZAAEbmV4dGQAA2VvZg' logger: ManageLogger - constructor ( + constructor( bucket: string, operator: string, password: string, @@ -52,7 +52,7 @@ class UpyunApi { this.expireTime = expireTime || 24 * 60 * 60 } - getAntiLeechParam (key: string): string { + getAntiLeechParam(key: string): string { const uri = `/${key}`.replace(/%2F/g, '/').replace(/^\/+/g, '/') const now = Math.round(new Date().getTime() / 1000) const expire = this.expireTime ? now + parseInt(this.expireTime.toString(), 10) : now + 1800 @@ -61,7 +61,7 @@ class UpyunApi { return `_upt=${upt}` } - formatFolder (item: any, slicedPrefix: string, urlPrefix: string) { + formatFolder(item: any, slicedPrefix: string, urlPrefix: string) { const key = `${slicedPrefix}${item.name}/` let url = `${urlPrefix}/${key}` if (this.antiLeechToken) { @@ -82,7 +82,7 @@ class UpyunApi { } } - formatFile (item: any, slicedPrefix: string, urlPrefix: string) { + formatFile(item: any, slicedPrefix: string, urlPrefix: string) { const key = `${slicedPrefix}${item.name}` let url = `${urlPrefix}/${key}` if (this.antiLeechToken) { @@ -102,7 +102,7 @@ class UpyunApi { } } - authorization (method: string, uri: string, contentMd5: string, operator: string, password: string) { + authorization(method: string, uri: string, contentMd5: string, operator: string, password: string) { return `UPYUN ${operator}:${hmacSha1Base64( md5(password, 'hex'), `${method.toUpperCase()}&${encodeURI(uri)}&${new Date().toUTCString()}${contentMd5 ? `&${contentMd5}` : ''}` @@ -112,11 +112,11 @@ class UpyunApi { /** * 获取空间列表 */ - async getBucketList (): Promise { + async getBucketList(): Promise { return this.bucket } - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken } = configMap const slicedPrefix = prefix.slice(1) @@ -168,7 +168,7 @@ class UpyunApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketName: bucket, prefix, cancelToken } = configMap const slicedPrefix = prefix.slice(1) @@ -227,7 +227,7 @@ class UpyunApi { * customUrl: string * } */ - async getBucketFileList (configMap: IStringKeyMap): Promise { + async getBucketFileList(configMap: IStringKeyMap): Promise { const { bucketName: bucket, prefix, marker, itemsPerPage } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `http://${bucket}.test.upcdn.net` @@ -264,7 +264,7 @@ class UpyunApi { * newKey: string * } */ - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const oldKey = configMap.oldKey let newKey = configMap.newKey const method = 'PUT' @@ -297,7 +297,7 @@ class UpyunApi { * key: string * } */ - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap const res = await this.cli.deleteFile(key) return res @@ -307,7 +307,7 @@ class UpyunApi { * delete bucket folder * @param configMap */ - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let marker = '' let isTruncated @@ -370,7 +370,7 @@ class UpyunApi { * axiso:onUploadProgress not work in nodejs , use got instead * @param configMap */ - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() fileArray.forEach((item: any) => { @@ -426,7 +426,7 @@ class UpyunApi { * 新建文件夹 * @param configMap */ - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap const res = await this.cli.makeDir(`/${key}`) return res @@ -436,7 +436,7 @@ class UpyunApi { * 下载文件 * @param configMap */ - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/apis/webdavplist.ts b/src/main/manage/apis/webdavplist.ts index 19cf3eaf..ed819eaa 100644 --- a/src/main/manage/apis/webdavplist.ts +++ b/src/main/manage/apis/webdavplist.ts @@ -28,7 +28,7 @@ class WebdavplistApi { agent: https.Agent | http.Agent ctx: WebDAVClient - constructor ( + constructor( endpoint: string, username: string, password: string, @@ -62,7 +62,7 @@ class WebdavplistApi { logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'WebdavplistApi', method })) - formatFolder (item: FileStat, urlPrefix: string, isWebPath = false) { + formatFolder(item: FileStat, urlPrefix: string, isWebPath = false) { const key = item.filename.replace(/^\/+/, '') return { ...item, @@ -79,7 +79,7 @@ class WebdavplistApi { } } - formatFile (item: FileStat, urlPrefix: string, isWebPath = false) { + formatFile(item: FileStat, urlPrefix: string, isWebPath = false) { const key = item.filename.replace(/^\/+/, '') return { ...item, @@ -98,7 +98,7 @@ class WebdavplistApi { isRequestSuccess = (code: number) => code >= 200 && code < 300 - async getBucketListRecursively (configMap: IStringKeyMap): Promise { + async getBucketListRecursively(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken } = configMap const urlPrefix = customUrl || this.endpoint @@ -138,7 +138,7 @@ class WebdavplistApi { ipcMain.removeAllListeners(cancelDownloadLoadingFileList) } - async getBucketListBackstage (configMap: IStringKeyMap): Promise { + async getBucketListBackstage(configMap: IStringKeyMap): Promise { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { prefix, customUrl, cancelToken, baseDir } = configMap let urlPrefix = customUrl || this.endpoint @@ -197,7 +197,7 @@ class WebdavplistApi { ipcMain.removeAllListeners('cancelLoadingFileList') } - async renameBucketFile (configMap: IStringKeyMap): Promise { + async renameBucketFile(configMap: IStringKeyMap): Promise { const { oldKey, newKey } = configMap let result = false try { @@ -209,7 +209,7 @@ class WebdavplistApi { return result } - async deleteBucketFile (configMap: IStringKeyMap): Promise { + async deleteBucketFile(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -221,7 +221,7 @@ class WebdavplistApi { return result } - async deleteBucketFolder (configMap: IStringKeyMap): Promise { + async deleteBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -233,7 +233,7 @@ class WebdavplistApi { return result } - async getPreSignedUrl (configMap: IStringKeyMap): Promise { + async getPreSignedUrl(configMap: IStringKeyMap): Promise { const { key } = configMap let result = '' try { @@ -245,7 +245,7 @@ class WebdavplistApi { return result } - async uploadBucketFile (configMap: IStringKeyMap): Promise { + async uploadBucketFile(configMap: IStringKeyMap): Promise { const { fileArray } = configMap const instance = UpDownTaskQueue.getInstance() for (const item of fileArray) { @@ -306,7 +306,7 @@ class WebdavplistApi { return true } - async createBucketFolder (configMap: IStringKeyMap): Promise { + async createBucketFolder(configMap: IStringKeyMap): Promise { const { key } = configMap let result = false try { @@ -320,7 +320,7 @@ class WebdavplistApi { return result } - async downloadBucketFile (configMap: IStringKeyMap): Promise { + async downloadBucketFile(configMap: IStringKeyMap): Promise { const { downloadPath, fileArray, maxDownloadFileCount } = configMap const instance = UpDownTaskQueue.getInstance() const promises = [] as any diff --git a/src/main/manage/datastore/db.ts b/src/main/manage/datastore/db.ts index 51b0f302..16482f72 100644 --- a/src/main/manage/datastore/db.ts +++ b/src/main/manage/datastore/db.ts @@ -9,7 +9,7 @@ interface IJSON { class ManageDB { readonly #ctx: IManageApiType readonly #db: JSONStore - constructor (ctx: IManageApiType) { + constructor(ctx: IManageApiType) { this.#ctx = ctx this.#db = new JSONStore(this.#ctx.configPath) const initParams: IStringKeyMap = { @@ -28,37 +28,37 @@ class ManageDB { } } - read (flush?: boolean): IJSON { + read(flush?: boolean): IJSON { return this.#db.read(flush) } - get (key: string = ''): any { + get(key: string = ''): any { this.read(true) return this.#db.get(key) } - set (key: string, value: any): void { + set(key: string, value: any): void { this.read(true) return this.#db.set(key, value) } - has (key: string): boolean { + has(key: string): boolean { this.read(true) return this.#db.has(key) } - unset (key: string, value: any): boolean { + unset(key: string, value: any): boolean { this.read(true) return this.#db.unset(key, value) } - saveConfig (config: Partial): void { + saveConfig(config: Partial): void { Object.keys(config).forEach((name: string) => { this.set(name, config[name]) }) } - removeConfig (config: IManageConfigType): void { + removeConfig(config: IManageConfigType): void { Object.keys(config).forEach((name: string) => { this.unset(name, config[name]) }) diff --git a/src/main/manage/datastore/dbChecker.ts b/src/main/manage/datastore/dbChecker.ts index f32c1bbf..c02d9c03 100644 --- a/src/main/manage/datastore/dbChecker.ts +++ b/src/main/manage/datastore/dbChecker.ts @@ -21,7 +21,7 @@ const errorMsg = { brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP') } -function manageDbChecker () { +function manageDbChecker() { if (process.type !== 'renderer') { const manageConfigFilePath = managePathChecker() if (!fs.existsSync(manageConfigFilePath)) { @@ -72,7 +72,7 @@ function manageDbChecker () { /** * Get manage config path */ -function managePathChecker (): string { +function managePathChecker(): string { if (_configFilePath) { return _configFilePath } @@ -113,7 +113,7 @@ function managePathChecker (): string { } } -function managePathDir () { +function managePathDir() { return path.dirname(managePathChecker()) } diff --git a/src/main/manage/datastore/upDownTaskQueue.ts b/src/main/manage/datastore/upDownTaskQueue.ts index 4c197a15..4f3bb26a 100644 --- a/src/main/manage/datastore/upDownTaskQueue.ts +++ b/src/main/manage/datastore/upDownTaskQueue.ts @@ -18,38 +18,38 @@ class UpDownTaskQueue { private persistPath = path.join(app.getPath('userData'), 'UpDownTaskQueue.json') - private constructor () { + private constructor() { this.restore() } - static getInstance () { + static getInstance() { if (!UpDownTaskQueue.instance) { UpDownTaskQueue.instance = new UpDownTaskQueue() } return UpDownTaskQueue.instance } - getUploadTaskQueue () { + getUploadTaskQueue() { return UpDownTaskQueue.getInstance().uploadTaskQueue } - getDownloadTaskQueue () { + getDownloadTaskQueue() { return UpDownTaskQueue.getInstance().downloadTaskQueue } - getUploadTask (taskId: string) { + getUploadTask(taskId: string) { return UpDownTaskQueue.getInstance().uploadTaskQueue.find(item => item.id === taskId) } - getAllUploadTask () { + getAllUploadTask() { return UpDownTaskQueue.getInstance().uploadTaskQueue } - addUploadTask (task: IUploadTask) { + addUploadTask(task: IUploadTask) { UpDownTaskQueue.getInstance().uploadTaskQueue.push(task) } - updateUploadTask (task: Partial) { + updateUploadTask(task: Partial) { const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === task.id) if (taskIndex !== -1) { const taskKeys = Object.keys(task) @@ -61,33 +61,33 @@ class UpDownTaskQueue { } } - removeUploadTask (taskId: string) { + removeUploadTask(taskId: string) { const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === taskId) if (taskIndex !== -1) { UpDownTaskQueue.getInstance().uploadTaskQueue.splice(taskIndex, 1) } } - removeDownloadTask (taskId: string) { + removeDownloadTask(taskId: string) { const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === taskId) if (taskIndex !== -1) { UpDownTaskQueue.getInstance().downloadTaskQueue.splice(taskIndex, 1) } } - getDownloadTask (taskId: string) { + getDownloadTask(taskId: string) { return UpDownTaskQueue.getInstance().downloadTaskQueue.find(item => item.id === taskId) } - getAllDownloadTask () { + getAllDownloadTask() { return UpDownTaskQueue.getInstance().downloadTaskQueue } - addDownloadTask (task: IDownloadTask) { + addDownloadTask(task: IDownloadTask) { UpDownTaskQueue.getInstance().downloadTaskQueue.push(task) } - updateDownloadTask (task: Partial) { + updateDownloadTask(task: Partial) { const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === task.id) if (taskIndex !== -1) { const taskKeys = Object.keys(task) @@ -99,11 +99,11 @@ class UpDownTaskQueue { } } - clearUploadTaskQueue () { + clearUploadTaskQueue() { UpDownTaskQueue.getInstance().uploadTaskQueue = [] } - removeUploadedTask () { + removeUploadedTask() { UpDownTaskQueue.getInstance().uploadTaskQueue = UpDownTaskQueue.getInstance().uploadTaskQueue.filter( item => item.status !== uploadTaskSpecialStatus.uploaded && @@ -112,7 +112,7 @@ class UpDownTaskQueue { ) } - removeDownloadedTask () { + removeDownloadedTask() { UpDownTaskQueue.getInstance().downloadTaskQueue = UpDownTaskQueue.getInstance().downloadTaskQueue.filter( item => item.status !== downloadTaskSpecialStatus.downloaded && @@ -121,16 +121,16 @@ class UpDownTaskQueue { ) } - clearDownloadTaskQueue () { + clearDownloadTaskQueue() { UpDownTaskQueue.getInstance().downloadTaskQueue = [] } - clearAllTaskQueue () { + clearAllTaskQueue() { this.clearUploadTaskQueue() this.clearDownloadTaskQueue() } - persist () { + persist() { try { this.checkPersistPath() fs.writeFileSync( @@ -145,7 +145,7 @@ class UpDownTaskQueue { } } - private restore () { + private restore() { try { this.checkPersistPath() const persistData = JSON.parse(fs.readFileSync(this.persistPath, { encoding: 'utf-8' })) @@ -157,7 +157,7 @@ class UpDownTaskQueue { } } - private checkPersistPath () { + private checkPersistPath() { if (!fs.existsSync(this.persistPath)) { fs.writeFileSync( this.persistPath, diff --git a/src/main/manage/manageApi.ts b/src/main/manage/manageApi.ts index 5f98f313..2e0b2cd6 100644 --- a/src/main/manage/manageApi.ts +++ b/src/main/manage/manageApi.ts @@ -26,7 +26,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { logger: ManageLogger currentPicBedConfig: IPicBedMangeConfig - constructor (currentPicBed: string = '') { + constructor(currentPicBed: string = '') { super() this.currentPicBed = currentPicBed || 'placeholder' this.configPath = managePathChecker() @@ -36,7 +36,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.currentPicBedConfig = this.getPicBedConfig(this.currentPicBed) } - getMsgParam (method: string) { + getMsgParam(method: string) { return { class: 'ManageApi', method, @@ -44,11 +44,11 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - errorMsg (err: any, param: IStringKeyMap) { + errorMsg(err: any, param: IStringKeyMap) { this.logger.error(formatError(err, param)) } - createClient () { + createClient() { const name = this.currentPicBedConfig.picBedName switch (name) { case 'aliyun': @@ -127,11 +127,11 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - private getPicBedConfig (picBedName: string): IPicBedMangeConfig { + private getPicBedConfig(picBedName: string): IPicBedMangeConfig { return this.getConfig(`picBed.${picBedName}`) } - private initConfigPath (): void { + private initConfigPath(): void { if (this.configPath === '') { this.configPath = `${homedir()}/.piclist/manage.json` } @@ -146,7 +146,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - private initconfig (): void { + private initconfig(): void { this.db = new ManageDB(this) this._config = this.db.read(true) as IManageConfigType } @@ -158,7 +158,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { return get(this._config, name) } - saveConfig (config: IStringKeyMap): void { + saveConfig(config: IStringKeyMap): void { if (!isInputConfigValid(config)) { this.logger.warn('the format of config is invalid, please provide object') return @@ -167,7 +167,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.db.saveConfig(config) } - removeConfig (key: string, propName: string): void { + removeConfig(key: string, propName: string): void { if (!key || !propName) { return } @@ -175,7 +175,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.db.unset(key, propName) } - setConfig (config: IStringKeyMap): void { + setConfig(config: IStringKeyMap): void { if (!isInputConfigValid(config)) { this.logger.warn('the format of config is invalid, please provide object') return @@ -185,12 +185,12 @@ export class ManageApi extends EventEmitter implements IManageApiType { }) } - unsetConfig (key: string, propName: string): void { + unsetConfig(key: string, propName: string): void { if (!key || !propName) return unset(this.getConfig(key), propName) } - async getBucketList (param?: IStringKeyMap | undefined): Promise { + async getBucketList(param?: IStringKeyMap | undefined): Promise { let client const name = this.currentPicBedConfig.picBedName.replace('plist', '') switch (this.currentPicBedConfig.picBedName) { @@ -232,12 +232,12 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async getBucketInfo (param?: IStringKeyMap | undefined): Promise { + async getBucketInfo(param?: IStringKeyMap | undefined): Promise { console.log(param) return {} } - async getBucketDomain (param: IStringKeyMap): Promise { + async getBucketDomain(param: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -262,7 +262,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async createBucket (param?: IStringKeyMap): Promise { + async createBucket(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -281,32 +281,32 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async deleteBucket (param?: IStringKeyMap): Promise { + async deleteBucket(param?: IStringKeyMap): Promise { console.log(param) return false } - async getOperatorList (param?: IStringKeyMap): Promise { + async getOperatorList(param?: IStringKeyMap): Promise { console.log(param) return [] } - async addOperator (param?: IStringKeyMap): Promise { + async addOperator(param?: IStringKeyMap): Promise { console.log(param) return false } - async deleteOperator (param?: IStringKeyMap): Promise { + async deleteOperator(param?: IStringKeyMap): Promise { console.log(param) return false } - async getBucketAclPolicy (param?: IStringKeyMap): Promise { + async getBucketAclPolicy(param?: IStringKeyMap): Promise { console.log(param) return {} } - async setBucketAclPolicy (param?: IStringKeyMap): Promise { + async setBucketAclPolicy(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'qiniu': @@ -322,7 +322,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async getBucketListRecursively (param?: IStringKeyMap): Promise { + async getBucketListRecursively(param?: IStringKeyMap): Promise { let client let window const defaultResult = { @@ -365,7 +365,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { * @param param * @returns */ - async getBucketListBackstage (param?: IStringKeyMap): Promise { + async getBucketListBackstage(param?: IStringKeyMap): Promise { let client let window const defaultResult = { @@ -412,7 +412,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { * isDir: 是否是文件夹 * fileSize: 文件大小 **/ - async getBucketFileList (param?: IStringKeyMap): Promise { + async getBucketFileList(param?: IStringKeyMap): Promise { const defaultResponse = { fullList: [] as any, isTruncated: false, @@ -439,7 +439,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async deleteBucketFile (param?: IStringKeyMap): Promise { + async deleteBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -466,7 +466,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async deleteBucketFolder (param?: IStringKeyMap): Promise { + async deleteBucketFolder(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -490,7 +490,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async renameBucketFile (param?: IStringKeyMap): Promise { + async renameBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -513,7 +513,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async downloadBucketFile (param?: IStringKeyMap): Promise { + async downloadBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -540,12 +540,12 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async copyMoveBucketFile (param?: IStringKeyMap): Promise { + async copyMoveBucketFile(param?: IStringKeyMap): Promise { console.log(param) return false } - async createBucketFolder (param?: IStringKeyMap): Promise { + async createBucketFolder(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -569,7 +569,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async uploadBucketFile (param?: IStringKeyMap): Promise { + async uploadBucketFile(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': @@ -595,7 +595,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { } } - async getPreSignedUrl (param?: IStringKeyMap): Promise { + async getPreSignedUrl(param?: IStringKeyMap): Promise { let client switch (this.currentPicBedConfig.picBedName) { case 'tcyun': diff --git a/src/main/manage/utils/common.ts b/src/main/manage/utils/common.ts index d697b211..e1bd179f 100644 --- a/src/main/manage/utils/common.ts +++ b/src/main/manage/utils/common.ts @@ -34,7 +34,7 @@ export const getFSFile = async (filePath: string, stream: boolean = false): Prom } } -export function isInputConfigValid (config: any): boolean { +export function isInputConfigValid(config: any): boolean { return typeof config === 'object' && !Array.isArray(config) && Object.keys(config).length > 0 } @@ -280,7 +280,7 @@ export const getInnerAgent = (proxy: any, sslEnabled: boolean = true) => { } } -export function getOptions ( +export function getOptions( method?: string, headers?: IStringKeyMap, searchParams?: IStringKeyMap, @@ -309,14 +309,14 @@ export class ConcurrencyPromisePool { runningNum: number results: any[] - constructor (limit: number) { + constructor(limit: number) { this.limit = limit this.queue = [] this.runningNum = 0 this.results = [] } - all (promises: any[] = []) { + all(promises: any[] = []) { return new Promise((resolve, reject) => { for (const promise of promises) { this._run(promise, resolve, reject) @@ -324,7 +324,7 @@ export class ConcurrencyPromisePool { }) } - _run (promise: any, resolve: any, reject: any) { + _run(promise: any, resolve: any, reject: any) { if (this.runningNum >= this.limit) { this.queue.push(promise) return diff --git a/src/main/manage/utils/dogeAPI.ts b/src/main/manage/utils/dogeAPI.ts index 918a9464..faacb30f 100644 --- a/src/main/manage/utils/dogeAPI.ts +++ b/src/main/manage/utils/dogeAPI.ts @@ -12,7 +12,7 @@ export interface DogecloudToken { sessionToken: string } -export async function dogecloudApi ( +export async function dogecloudApi( apiPath: string, data = {}, jsonMode: boolean = false, @@ -45,7 +45,7 @@ export async function dogecloudApi ( } } -export async function getTempToken (accessKey: string, secretKey: string): Promise { +export async function getTempToken(accessKey: string, secretKey: string): Promise { const dogeTempToken = (await picgo.getConfig('Credentials.doge-token')) || ({} as any) if (dogeTempToken.token && dogeTempToken.expires > Date.now() + 7200000) { return dogeTempToken.token diff --git a/src/main/manage/utils/logger.ts b/src/main/manage/utils/logger.ts index 94f48540..abcb8c7d 100644 --- a/src/main/manage/utils/logger.ts +++ b/src/main/manage/utils/logger.ts @@ -24,11 +24,11 @@ export class ManageLogger implements ILogger { #logLevel!: string #logPath!: string - constructor (ctx: IManageApiType) { + constructor(ctx: IManageApiType) { this.#ctx = ctx } - #handleLog (type: string, ...msg: ILogArgvTypeWithError[]): void { + #handleLog(type: string, ...msg: ILogArgvTypeWithError[]): void { const logHeader = chalk[this.#level[type] as ILogColor](`[PicList ${type.toUpperCase()}]`) console.log(logHeader, ...msg) this.#logLevel = this.#ctx.getConfig(configPaths.settings.logLevel) @@ -53,7 +53,7 @@ export class ManageLogger implements ILogger { }, 0) } - #checkLogFileIsLarge (logPath: string): { + #checkLogFileIsLarge(logPath: string): { isLarge: boolean logFileSize?: number logFileSizeLimit?: number @@ -76,14 +76,14 @@ export class ManageLogger implements ILogger { } } - #recreateLogFile (logPath: string): void { + #recreateLogFile(logPath: string): void { if (fs.existsSync(logPath)) { fs.unlinkSync(logPath) fs.createFileSync(logPath) } } - #handleWriteLog (logPath: string, type: string, ...msg: ILogArgvTypeWithError[]): void { + #handleWriteLog(logPath: string, type: string, ...msg: ILogArgvTypeWithError[]): void { try { if (this.#checkLogLevel(type, this.#logLevel)) { let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicList ${type.toUpperCase()}] ` @@ -98,7 +98,7 @@ export class ManageLogger implements ILogger { } } - #formatLogItem (item: ILogArgvTypeWithError, type: string): string { + #formatLogItem(item: ILogArgvTypeWithError, type: string): string { let result = '' if (item instanceof Error && type === 'error') { result += `\n------Error Stack Begin------\n${util.format(item?.stack)}\n-------Error Stack End------- ` @@ -114,7 +114,7 @@ export class ManageLogger implements ILogger { return result } - #checkLogLevel (type: string, level: undefined | string | string[]): boolean { + #checkLogLevel(type: string, level: undefined | string | string[]): boolean { if (level === undefined || level === 'all') { return true } @@ -124,23 +124,23 @@ export class ManageLogger implements ILogger { return type === level } - success (...msq: ILogArgvType[]): void { + success(...msq: ILogArgvType[]): void { return this.#handleLog(ILogType.success, ...msq) } - info (...msq: ILogArgvType[]): void { + info(...msq: ILogArgvType[]): void { return this.#handleLog(ILogType.info, ...msq) } - error (...msq: ILogArgvTypeWithError[]): void { + error(...msq: ILogArgvTypeWithError[]): void { return this.#handleLog(ILogType.error, ...msq) } - warn (...msq: ILogArgvType[]): void { + warn(...msq: ILogArgvType[]): void { return this.#handleLog(ILogType.warn, ...msq) } - debug (...msq: ILogArgvType[]): void { + debug(...msq: ILogArgvType[]): void { if (process.env.NODE_ENV === 'development') { this.#handleLog(ILogType.info, ...msq) } diff --git a/src/main/server/index.ts b/src/main/server/index.ts index 0e56980b..723be8c7 100644 --- a/src/main/server/index.ts +++ b/src/main/server/index.ts @@ -41,12 +41,12 @@ class Server { #httpServer: http.Server #config: IServerConfig - constructor () { + constructor() { this.#config = this.getConfigWithDefaults() this.#httpServer = http.createServer(this.#handleRequest) } - getConfigWithDefaults () { + getConfigWithDefaults() { let config = picgo.getConfig(configPaths.settings.server) if (!this.#isValidConfig(config)) { config = { port: DEFAULT_PORT, host: DEFAULT_HOST, enable: true } @@ -55,7 +55,7 @@ class Server { return config } - #isValidConfig (config: IObj | undefined) { + #isValidConfig(config: IObj | undefined) { return config && config.port && config.host && config.enable !== undefined } @@ -198,20 +198,20 @@ class Server { }) } - startup () { + startup() { if (this.#config.enable) { this.#listen(this.#config.port) } } - shutdown (hasStarted?: boolean) { + shutdown(hasStarted?: boolean) { this.#httpServer.close() if (!hasStarted) { logger.info('[PicList Server] shutdown') } } - restart () { + restart() { this.shutdown() this.#config = this.getConfigWithDefaults() this.startup() diff --git a/src/main/server/router.ts b/src/main/server/router.ts index 8d1b80f0..b69624b1 100644 --- a/src/main/server/router.ts +++ b/src/main/server/router.ts @@ -5,27 +5,27 @@ type HttpMethod = 'GET' | 'POST' class Router { #router = new Map>() - #addRoute (method: HttpMethod, url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + #addRoute(method: HttpMethod, url: string, callback: routeHandler, urlparams?: URLSearchParams): void { if (!this.#router.has(url)) { this.#router.set(url, new Map()) } this.#router.get(url)!.set(method, { handler: callback, urlparams }) } - get (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + get(url: string, callback: routeHandler, urlparams?: URLSearchParams): void { this.#addRoute('GET', url, callback, urlparams) } - post (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + post(url: string, callback: routeHandler, urlparams?: URLSearchParams): void { this.#addRoute('POST', url, callback, urlparams) } - any (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { + any(url: string, callback: routeHandler, urlparams?: URLSearchParams): void { this.#addRoute('GET', url, callback, urlparams) this.#addRoute('POST', url, callback, urlparams) } - getHandler (url: string, method: HttpMethod) { + getHandler(url: string, method: HttpMethod) { if (this.#router.has(url)) { const methods = this.#router.get(url)! if (methods.has(method)) { diff --git a/src/main/server/routerManager.ts b/src/main/server/routerManager.ts index 2b61d058..e2689412 100644 --- a/src/main/server/routerManager.ts +++ b/src/main/server/routerManager.ts @@ -1,234 +1,234 @@ -import http from 'node:http' -import path from 'node:path' - -import { dbPathDir } from '@core/datastore/dbChecker' -import picgo from '@core/picgo' -import logger from '@core/picgo/logger' -import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis' -import windowManager from 'apis/app/window/windowManager' -import { app } from 'electron' -import fs from 'fs-extra' -import { marked } from 'marked' - -import type { IHttpResponse, IStringKeyMap } from '#/types/types' -import { markdownContent } from '~/server/apiDoc' -import router from '~/server/router' -import { deleteChoosedFiles, handleResponse } from '~/server/utils' -import { AESHelper } from '~/utils/aesHelper' -import { configPaths } from '~/utils/configPaths' -import { changeCurrentUploader } from '~/utils/handleUploaderConfig' - -const appPath = app.getPath('userData') -const serverTempDir = path.join(appPath, 'serverTemp') - -const STORE_PATH = dbPathDir() -const LOG_PATH = path.join(STORE_PATH, 'piclist.log') - -const errorMessage = `upload error. see ${LOG_PATH} for more detail.` -const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.` - -async function responseForGet ({ response }: { response: http.ServerResponse }) { - response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }) - const htmlContent = marked(markdownContent) - response.write(htmlContent) - response.end() -} - -router.get('/', responseForGet) -router.get('/upload', responseForGet) - -router.post( - '/upload', - async ({ - response, - list = [], - urlparams - }: { - response: IHttpResponse - list?: string[] - urlparams?: URLSearchParams - }): Promise => { - try { - const picbed = urlparams?.get('picbed') - const passedKey = urlparams?.get('key') - const serverKey = picgo.getConfig(configPaths.settings.serverKey) || '' - const useShortUrl = picgo.getConfig(configPaths.settings.useShortUrl) - if (serverKey && passedKey !== serverKey) { - handleResponse({ - response, - body: { - success: false, - message: 'server key is uncorrect' - } - }) - return - } - let currentPicBedType = '' - let currentPicBedConfig = {} as IStringKeyMap - let currentPicBedConfigId = '' - let needRestore = false - if (picbed) { - const currentPicBed = picgo.getConfig('picBed') || ({} as IStringKeyMap) - currentPicBedType = currentPicBed.uploader || currentPicBed.current || 'smms' - currentPicBedConfig = currentPicBed[currentPicBedType] || ({} as IStringKeyMap) - currentPicBedConfigId = currentPicBedConfig._id - const configName = urlparams?.get('configName') || currentPicBed[picbed]?._configName - if (picbed === currentPicBedType && configName === currentPicBedConfig._configName) { - // do nothing - } else { - needRestore = true - const picBeds = picgo.getConfig('uploader') - const currentPicBedList = picBeds?.[picbed]?.configList - if (currentPicBedList) { - const currentConfig = currentPicBedList?.find((item: any) => item._configName === configName) - if (currentConfig) { - changeCurrentUploader(picbed, currentConfig, currentConfig._id) - } - } - } - } - if (list.length === 0) { - // upload with clipboard - logger.info('[PicList Server] upload clipboard file') - const result = await uploadClipboardFiles() - const res = useShortUrl ? result.fullResult.shortUrl || result.url : result.url - const fullResult = result.fullResult - fullResult.imgUrl = useShortUrl ? fullResult.shortUrl || fullResult.imgUrl : fullResult.imgUrl - logger.info('[PicList Server] upload result:', res) - if (res) { - const treatedFullResult = { - isEncrypted: 1, - EncryptedData: new AESHelper().encrypt(JSON.stringify(fullResult)), - ...fullResult - } - delete treatedFullResult.config - handleResponse({ - response, - body: { - success: true, - result: [res], - fullResult: [treatedFullResult] - } - }) - } else { - handleResponse({ - response, - body: { - success: false, - message: errorMessage - } - }) - } - } else { - logger.info('[PicList Server] upload files in list') - // upload with files - const pathList = list.map(item => { - return { - path: item - } - }) - const win = windowManager.getAvailableWindow() - const result = await uploadChoosedFiles(win.webContents, pathList) - const res = result.map(item => { - return useShortUrl ? item.fullResult.shortUrl || item.url : item.url - }) - const fullResult = result.map((item: any) => { - const treatedItem = { - isEncrypted: 1, - EncryptedData: new AESHelper().encrypt(JSON.stringify(item.fullResult)), - ...item.fullResult - } - delete treatedItem.config - treatedItem.imgUrl = useShortUrl ? treatedItem.shortUrl || treatedItem.imgUrl : treatedItem.imgUrl - return treatedItem - }) - logger.info('[PicList Server] upload result', res.join(' ; ')) - if (res.length) { - handleResponse({ - response, - body: { - success: true, - result: res, - fullResult - } - }) - } else { - handleResponse({ - response, - body: { - success: false, - message: errorMessage - } - }) - } - } - fs.emptyDirSync(serverTempDir) - if (needRestore) { - changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId) - } - } catch (err: any) { - logger.error(err) - handleResponse({ - response, - body: { - success: false, - message: errorMessage - } - }) - } - } -) - -router.post( - '/delete', - async ({ response, list = [] }: { response: IHttpResponse; list?: IStringKeyMap[] }): Promise => { - if (list.length === 0) { - handleResponse({ - response, - body: { - success: false, - message: 'no file to delete' - } - }) - return - } - try { - const aesHelper = new AESHelper() - const treatList = list.map(item => { - if (!item.isEncrypted) return item - return JSON.parse(aesHelper.decrypt(item.EncryptedData)) - }) - const result = await deleteChoosedFiles(treatList) - const successCount = result.filter(item => item).length - const failCount = result.length - successCount - handleResponse({ - response, - body: { - success: !!successCount, - message: successCount ? `delete success: ${successCount}, fail: ${failCount}` : deleteErrorMessage - } - }) - } catch (err: any) { - logger.error(err) - handleResponse({ - response, - body: { - success: false, - message: deleteErrorMessage - } - }) - } - } -) - -router.any('/heartbeat', async ({ response }: { response: IHttpResponse }) => { - handleResponse({ - response, - body: { - success: true, - result: 'alive' - } - }) -}) - -export default router +import http from 'node:http' +import path from 'node:path' + +import { dbPathDir } from '@core/datastore/dbChecker' +import picgo from '@core/picgo' +import logger from '@core/picgo/logger' +import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis' +import windowManager from 'apis/app/window/windowManager' +import { app } from 'electron' +import fs from 'fs-extra' +import { marked } from 'marked' + +import type { IHttpResponse, IStringKeyMap } from '#/types/types' +import { markdownContent } from '~/server/apiDoc' +import router from '~/server/router' +import { deleteChoosedFiles, handleResponse } from '~/server/utils' +import { AESHelper } from '~/utils/aesHelper' +import { configPaths } from '~/utils/configPaths' +import { changeCurrentUploader } from '~/utils/handleUploaderConfig' + +const appPath = app.getPath('userData') +const serverTempDir = path.join(appPath, 'serverTemp') + +const STORE_PATH = dbPathDir() +const LOG_PATH = path.join(STORE_PATH, 'piclist.log') + +const errorMessage = `upload error. see ${LOG_PATH} for more detail.` +const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.` + +async function responseForGet({ response }: { response: http.ServerResponse }) { + response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }) + const htmlContent = marked(markdownContent) + response.write(htmlContent) + response.end() +} + +router.get('/', responseForGet) +router.get('/upload', responseForGet) + +router.post( + '/upload', + async ({ + response, + list = [], + urlparams + }: { + response: IHttpResponse + list?: string[] + urlparams?: URLSearchParams + }): Promise => { + try { + const picbed = urlparams?.get('picbed') + const passedKey = urlparams?.get('key') + const serverKey = picgo.getConfig(configPaths.settings.serverKey) || '' + const useShortUrl = picgo.getConfig(configPaths.settings.useShortUrl) + if (serverKey && passedKey !== serverKey) { + handleResponse({ + response, + body: { + success: false, + message: 'server key is uncorrect' + } + }) + return + } + let currentPicBedType = '' + let currentPicBedConfig = {} as IStringKeyMap + let currentPicBedConfigId = '' + let needRestore = false + if (picbed) { + const currentPicBed = picgo.getConfig('picBed') || ({} as IStringKeyMap) + currentPicBedType = currentPicBed.uploader || currentPicBed.current || 'smms' + currentPicBedConfig = currentPicBed[currentPicBedType] || ({} as IStringKeyMap) + currentPicBedConfigId = currentPicBedConfig._id + const configName = urlparams?.get('configName') || currentPicBed[picbed]?._configName + if (picbed === currentPicBedType && configName === currentPicBedConfig._configName) { + // do nothing + } else { + needRestore = true + const picBeds = picgo.getConfig('uploader') + const currentPicBedList = picBeds?.[picbed]?.configList + if (currentPicBedList) { + const currentConfig = currentPicBedList?.find((item: any) => item._configName === configName) + if (currentConfig) { + changeCurrentUploader(picbed, currentConfig, currentConfig._id) + } + } + } + } + if (list.length === 0) { + // upload with clipboard + logger.info('[PicList Server] upload clipboard file') + const result = await uploadClipboardFiles() + const res = useShortUrl ? result.fullResult.shortUrl || result.url : result.url + const fullResult = result.fullResult + fullResult.imgUrl = useShortUrl ? fullResult.shortUrl || fullResult.imgUrl : fullResult.imgUrl + logger.info('[PicList Server] upload result:', res) + if (res) { + const treatedFullResult = { + isEncrypted: 1, + EncryptedData: new AESHelper().encrypt(JSON.stringify(fullResult)), + ...fullResult + } + delete treatedFullResult.config + handleResponse({ + response, + body: { + success: true, + result: [res], + fullResult: [treatedFullResult] + } + }) + } else { + handleResponse({ + response, + body: { + success: false, + message: errorMessage + } + }) + } + } else { + logger.info('[PicList Server] upload files in list') + // upload with files + const pathList = list.map(item => { + return { + path: item + } + }) + const win = windowManager.getAvailableWindow() + const result = await uploadChoosedFiles(win.webContents, pathList) + const res = result.map(item => { + return useShortUrl ? item.fullResult.shortUrl || item.url : item.url + }) + const fullResult = result.map((item: any) => { + const treatedItem = { + isEncrypted: 1, + EncryptedData: new AESHelper().encrypt(JSON.stringify(item.fullResult)), + ...item.fullResult + } + delete treatedItem.config + treatedItem.imgUrl = useShortUrl ? treatedItem.shortUrl || treatedItem.imgUrl : treatedItem.imgUrl + return treatedItem + }) + logger.info('[PicList Server] upload result', res.join(' ; ')) + if (res.length) { + handleResponse({ + response, + body: { + success: true, + result: res, + fullResult + } + }) + } else { + handleResponse({ + response, + body: { + success: false, + message: errorMessage + } + }) + } + } + fs.emptyDirSync(serverTempDir) + if (needRestore) { + changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId) + } + } catch (err: any) { + logger.error(err) + handleResponse({ + response, + body: { + success: false, + message: errorMessage + } + }) + } + } +) + +router.post( + '/delete', + async ({ response, list = [] }: { response: IHttpResponse; list?: IStringKeyMap[] }): Promise => { + if (list.length === 0) { + handleResponse({ + response, + body: { + success: false, + message: 'no file to delete' + } + }) + return + } + try { + const aesHelper = new AESHelper() + const treatList = list.map(item => { + if (!item.isEncrypted) return item + return JSON.parse(aesHelper.decrypt(item.EncryptedData)) + }) + const result = await deleteChoosedFiles(treatList) + const successCount = result.filter(item => item).length + const failCount = result.length - successCount + handleResponse({ + response, + body: { + success: !!successCount, + message: successCount ? `delete success: ${successCount}, fail: ${failCount}` : deleteErrorMessage + } + }) + } catch (err: any) { + logger.error(err) + handleResponse({ + response, + body: { + success: false, + message: deleteErrorMessage + } + }) + } + } +) + +router.any('/heartbeat', async ({ response }: { response: IHttpResponse }) => { + handleResponse({ + response, + body: { + success: true, + result: 'alive' + } + }) +}) + +export default router diff --git a/src/main/server/webServer/index.ts b/src/main/server/webServer/index.ts index 47532c33..85fd8e92 100644 --- a/src/main/server/webServer/index.ts +++ b/src/main/server/webServer/index.ts @@ -11,7 +11,7 @@ import { configPaths } from '~/utils/configPaths' const defaultPath = process.platform === 'win32' ? 'C:\\Users' : '/' -function generateDirectoryListingHtml (files: any[], requestPath: any) { +function generateDirectoryListingHtml(files: any[], requestPath: any) { let html = '

Directory Listing

    ' files.forEach((file: string) => { const filePath = path.join(requestPath, file) @@ -21,7 +21,7 @@ function generateDirectoryListingHtml (files: any[], requestPath: any) { return html } -function serveDirectory (res: http.ServerResponse, filePath: fs.PathLike, requestPath: any) { +function serveDirectory(res: http.ServerResponse, filePath: fs.PathLike, requestPath: any) { fs.readdir(filePath, (err, files) => { if (err) { res.writeHead(500) @@ -33,7 +33,7 @@ function serveDirectory (res: http.ServerResponse, filePath: fs.PathLike, reques }) } -function serveFile (res: http.ServerResponse, filePath: fs.PathLike) { +function serveFile(res: http.ServerResponse, filePath: fs.PathLike) { const readStream = fs.createReadStream(filePath) readStream.pipe(res) readStream.on('error', () => { @@ -46,12 +46,12 @@ class WebServer { #server!: http.Server #config!: IStringKeyMap - constructor () { + constructor() { this.loadConfig() this.initServer() } - loadConfig (): void { + loadConfig(): void { this.#config = { enableWebServer: picgo.getConfig(configPaths.settings.enableWebServer) || false, webServerHost: picgo.getConfig(configPaths.settings.webServerHost) || '0.0.0.0', @@ -60,7 +60,7 @@ class WebServer { } } - initServer (): void { + initServer(): void { this.#server = http.createServer((req, res) => { const requestPath = req.url?.split('?')[0] const filePath = path.join(this.#config.webServerPath, decodeURIComponent(requestPath || '')) @@ -79,7 +79,7 @@ class WebServer { }) } - start () { + start() { if (this.#config.enableWebServer) { this.#server .listen( @@ -99,13 +99,13 @@ class WebServer { } } - stop () { + stop() { this.#server.close(() => { logger.info('Web server is stopped') }) } - restart () { + restart() { this.stop() this.loadConfig() this.initServer() diff --git a/src/main/utils/aesHelper.ts b/src/main/utils/aesHelper.ts index f3fec416..73a304e1 100644 --- a/src/main/utils/aesHelper.ts +++ b/src/main/utils/aesHelper.ts @@ -1,75 +1,60 @@ -import crypto from 'node:crypto' - -import picgo from '@core/picgo' - -import { configPaths } from '~/utils/configPaths' - -export class AESHelper { - static readonly #SALT = Buffer.from('a8b3c4d2e4f5098712345678feedc0de', 'hex') - static readonly #ITERATIONS = 100_000 - static readonly #KEYLEN = 32 - static readonly #DIGEST = 'sha512' as const - static readonly #ALGO = 'aes-256-cbc' - static readonly #IV_LENGTH = 16 - static readonly #SEP = ':' - - static #keyCache = new Map() - - readonly key: Buffer - - constructor (password?: string) { - const pwd = - password ?? - picgo.getConfig(configPaths.settings.aesPassword) ?? - 'aesPassword' - this.key = AESHelper.#deriveKey(pwd) - } - - static #deriveKey (password: string): Buffer { - const cached = this.#keyCache.get(password) - if (cached) return cached - const key = crypto.pbkdf2Sync( - password, - this.#SALT, - this.#ITERATIONS, - this.#KEYLEN, - this.#DIGEST - ) - this.#keyCache.set(password, key) - return key - } - - encrypt (plainText: string): string { - const iv = crypto.randomBytes(AESHelper.#IV_LENGTH) - const cipher = crypto.createCipheriv(AESHelper.#ALGO, this.key, iv) - const encrypted = Buffer.concat([ - cipher.update(plainText, 'utf8'), - cipher.final() - ]) - return `${iv.toString('hex')}${AESHelper.#SEP}${encrypted.toString('hex')}` - } - - decrypt (encryptedData: string): string { - if (!encryptedData) return '{}' - - const sepIndex = encryptedData.indexOf(AESHelper.#SEP) - if (sepIndex <= 0) return '{}' - - const ivHex = encryptedData.slice(0, sepIndex) - const encryptedHex = encryptedData.slice(sepIndex + 1) - - try { - const iv = Buffer.from(ivHex, 'hex') - if (iv.length !== AESHelper.#IV_LENGTH) return '{}' - - const decipher = crypto.createDecipheriv(AESHelper.#ALGO, this.key, iv) - const decrypted = Buffer.concat([ - decipher.update(Buffer.from(encryptedHex, 'hex')), - decipher.final() - ]) - return decrypted.toString('utf8') - } catch { - return '{}' - } - } -} +import crypto from 'node:crypto' + +import picgo from '@core/picgo' + +import { configPaths } from '~/utils/configPaths' + +export class AESHelper { + static readonly #SALT = Buffer.from('a8b3c4d2e4f5098712345678feedc0de', 'hex') + static readonly #ITERATIONS = 100_000 + static readonly #KEYLEN = 32 + static readonly #DIGEST = 'sha512' as const + static readonly #ALGO = 'aes-256-cbc' + static readonly #IV_LENGTH = 16 + static readonly #SEP = ':' + + static #keyCache = new Map() + + readonly key: Buffer + + constructor(password?: string) { + const pwd = password ?? picgo.getConfig(configPaths.settings.aesPassword) ?? 'aesPassword' + this.key = AESHelper.#deriveKey(pwd) + } + + static #deriveKey(password: string): Buffer { + const cached = this.#keyCache.get(password) + if (cached) return cached + const key = crypto.pbkdf2Sync(password, this.#SALT, this.#ITERATIONS, this.#KEYLEN, this.#DIGEST) + this.#keyCache.set(password, key) + return key + } + + encrypt(plainText: string): string { + const iv = crypto.randomBytes(AESHelper.#IV_LENGTH) + const cipher = crypto.createCipheriv(AESHelper.#ALGO, this.key, iv) + const encrypted = Buffer.concat([cipher.update(plainText, 'utf8'), cipher.final()]) + return `${iv.toString('hex')}${AESHelper.#SEP}${encrypted.toString('hex')}` + } + + decrypt(encryptedData: string): string { + if (!encryptedData) return '{}' + + const sepIndex = encryptedData.indexOf(AESHelper.#SEP) + if (sepIndex <= 0) return '{}' + + const ivHex = encryptedData.slice(0, sepIndex) + const encryptedHex = encryptedData.slice(sepIndex + 1) + + try { + const iv = Buffer.from(ivHex, 'hex') + if (iv.length !== AESHelper.#IV_LENGTH) return '{}' + + const decipher = crypto.createDecipheriv(AESHelper.#ALGO, this.key, iv) + const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedHex, 'hex')), decipher.final()]) + return decrypted.toString('utf8') + } catch { + return '{}' + } + } +} diff --git a/src/main/utils/beforeOpen.ts b/src/main/utils/beforeOpen.ts index 3e7ff2b1..fd670a96 100644 --- a/src/main/utils/beforeOpen.ts +++ b/src/main/utils/beforeOpen.ts @@ -13,7 +13,7 @@ const configPath = dbPathChecker() const CONFIG_DIR = path.dirname(configPath) const __dirname = path.dirname(fileURLToPath(import.meta.url)) -function beforeOpen () { +function beforeOpen() { if (process.platform === 'darwin') { resolveMacWorkFlow() } @@ -21,7 +21,7 @@ function beforeOpen () { resolveOtherI18nFiles() } -function copyFileOutsideOfElectronAsar (sourceInAsarArchive: string, destOutsideAsarArchive: string) { +function copyFileOutsideOfElectronAsar(sourceInAsarArchive: string, destOutsideAsarArchive: string) { if (fs.existsSync(sourceInAsarArchive)) { // file will be copied if (fs.statSync(sourceInAsarArchive).isFile()) { @@ -45,16 +45,21 @@ function copyFileOutsideOfElectronAsar (sourceInAsarArchive: string, destOutside /** * macOS 右键菜单 */ -function resolveMacWorkFlow () { +function resolveMacWorkFlow() { const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow` try { - copyFileOutsideOfElectronAsar(path.join(__dirname, '../../resources', 'Upload pictures with PicList.workflow').replace('app.asar', 'app.asar.unpacked'), dest) + copyFileOutsideOfElectronAsar( + path + .join(__dirname, '../../resources', 'Upload pictures with PicList.workflow') + .replace('app.asar', 'app.asar.unpacked'), + dest + ) } catch (e) { console.log(e) } } -function diffFilesAndUpdate (filePath1: string, filePath2: string) { +function diffFilesAndUpdate(filePath1: string, filePath2: string) { try { const file1 = fs.existsSync(filePath1) && fs.readFileSync(filePath1) const file2 = fs.existsSync(filePath1) && fs.readFileSync(filePath2) @@ -71,7 +76,7 @@ function diffFilesAndUpdate (filePath1: string, filePath2: string) { /** * 初始化剪贴板生成图片的脚本 */ -function resolveClipboardImageGenerator () { +function resolveClipboardImageGenerator() { const clipboardFiles = getClipboardFiles() if (!fs.pathExistsSync(path.join(CONFIG_DIR, 'windows10.ps1'))) { clipboardFiles.forEach(item => { @@ -84,7 +89,7 @@ function resolveClipboardImageGenerator () { }) } - function getClipboardFiles () { + function getClipboardFiles() { const files = ['linux.sh', 'mac.applescript', 'windows.ps1', 'windows10.ps1', 'wsl.sh'] return files.map(item => { @@ -99,7 +104,7 @@ function resolveClipboardImageGenerator () { /** * 初始化其他语言文件 */ -function resolveOtherI18nFiles () { +function resolveOtherI18nFiles() { const i18nFolder = path.join(CONFIG_DIR, 'i18n') if (!fs.pathExistsSync(i18nFolder)) { fs.mkdirSync(i18nFolder) diff --git a/src/main/utils/clipboardPoll.ts b/src/main/utils/clipboardPoll.ts index 684fc83d..66c249d8 100644 --- a/src/main/utils/clipboardPoll.ts +++ b/src/main/utils/clipboardPoll.ts @@ -9,13 +9,13 @@ class ClipboardWatcher extends EventEmitter { timer: NodeJS.Timeout | null lastImageHash: string | null - constructor () { + constructor() { super() this.lastImageHash = null this.timer = null } - startListening (watchDelay = 1000) { + startListening(watchDelay = 1000) { this.stopListening(false) this.timer = setInterval(() => { @@ -34,7 +34,7 @@ class ClipboardWatcher extends EventEmitter { logger.info('Start to watch clipboard') } - stopListening (isLog = true) { + stopListening(isLog = true) { if (this.timer) { clearInterval(this.timer) this.timer = null @@ -43,7 +43,7 @@ class ClipboardWatcher extends EventEmitter { isLog && logger.info('Stop to watch clipboard') } - getImageHash (image: NativeImage): string { + getImageHash(image: NativeImage): string { const buffer = image.toBitmap() return crypto.createHash('md5').update(buffer).digest('hex') } diff --git a/src/main/utils/common.ts b/src/main/utils/common.ts index e185ddcc..16774c6f 100644 --- a/src/main/utils/common.ts +++ b/src/main/utils/common.ts @@ -1,323 +1,323 @@ -import path from 'node:path' - -import db from '@core/datastore' -import logger from '@core/picgo/logger' -import axios from 'axios' -import { clipboard, Notification, Tray } from 'electron' -import FormData from 'form-data' -import fs from 'fs-extra' -import { isReactive, isRef, toRaw, unref } from 'vue' - -import type { IHTTPProxy, IPrivateShowNotificationOption, IStringKeyMap } from '#/types/types' -import { configPaths } from '~/utils/configPaths' -import { IShortUrlServer } from '~/utils/enum' - -/** - * get raw data from reactive or ref - */ -export const getRawData = (args: any): any => { - if (isRef(args)) return unref(args) - if (isReactive(args)) return toRaw(args) - if (Array.isArray(args)) return args.map(getRawData) - if (typeof args === 'object' && args !== null) { - const data = {} as Record - for (const key in args) { - data[key] = getRawData(args[key]) - } - return data - } - return args -} - -const getExtension = (fileName: string) => path.extname(fileName).slice(1) - -export const isImage = (fileName: string) => - ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'svg', 'avif'].includes(getExtension(fileName)) - -export let tray: Tray - -export const setTray = (t: Tray) => { - tray = t -} - -export const getTray = () => tray - -export function setTrayToolTip (title: string): void { - if (tray) { - tray.setToolTip(title) - } -} - -export const handleCopyUrl = (str: string): void => { - if (db.get(configPaths.settings.autoCopy) !== false) { - clipboard.writeText(str) - } -} - -/** - * show notification - * @param options - */ -export const showNotification = ( - options: IPrivateShowNotificationOption = { - title: '', - body: '', - clickToCopy: false, - copyContent: '', - clickFn: () => {} - } -) => { - const notification = new Notification({ - title: options.title, - body: options.body - }) - const handleClick = () => { - if (options.clickToCopy) { - clipboard.writeText(options.copyContent || options.body) - } - if (options.clickFn) { - options.clickFn() - } - } - notification.once('click', handleClick) - notification.once('close', () => { - notification.removeListener('click', handleClick) - }) - notification.show() -} - -/** - * macOS public.file-url will get encoded file path, - * so we need to decode it - */ -export const ensureFilePath = (filePath: string, prefix = 'file://'): string => { - filePath = filePath.replace(prefix, '') - if (fs.existsSync(filePath)) { - return `${prefix}${filePath}` - } - filePath = decodeURIComponent(filePath) - if (fs.existsSync(filePath)) { - return `${prefix}${filePath}` - } - return '' -} - -/** - * for builtin clipboard to get image path from clipboard - * @returns - */ -export const getClipboardFilePath = (): string => { - // TODO: linux support - const img = clipboard.readImage() - const platform = process.platform - - if (!img.isEmpty() && platform === 'darwin') { - let imgPath = clipboard.read('public.file-url') // will get file://xxx/xxx - imgPath = ensureFilePath(imgPath) - return imgPath ? imgPath.replace('file://', '') : '' - } - - if (img.isEmpty() && platform === 'win32') { - const imgPath = clipboard - .readBuffer('FileNameW') - ?.toString('ucs2') - ?.replace(RegExp(String.fromCharCode(0), 'g'), '') - return imgPath || '' - } - - return '' -} - -const c1nApi = 'https://c1n.cn/link/short' - -const createC1NShortUrl = async (url: string) => { - const c1nToken = db.get(configPaths.settings.c1nToken) || '' - if (!c1nToken) { - logger.warn('c1n token is not set') - return url - } - try { - const form = new FormData() - form.append('url', url) - const res = await axios.post(c1nApi, form, { - headers: { - token: c1nToken - } - }) - if (res.status >= 200 && res.status < 300 && res.data?.code === 0) { - return res.data.data - } - } catch (e: any) { - logger.error(e) - } - return url -} - -const createYOURLSShortLink = async (url: string) => { - let domain = db.get(configPaths.settings.yourlsDomain) || '' - const signature = db.get(configPaths.settings.yourlsSignature) || '' - - if (!domain || !signature) { - logger.warn('Yourls server or signature is not set') - return url - } - if (!/^https?:\/\//.test(domain)) { - domain = `http://${domain}` - } - const params = new URLSearchParams({ - signature, - action: 'shorturl', - format: 'json', - url - }) - try { - const res = await axios.get(`${domain}/yourls-api.php?${params.toString()}`) - if (res.data?.shorturl) { - return res.data.shorturl - } - } catch (e: any) { - if (e.response?.data?.message?.includes('already exists in database')) { - return e.response.data.shorturl - } - logger.error(e) - } - - return url -} - -const createShortUrlForCFWorker = async (url: string) => { - let cfWorkerHost = db.get(configPaths.settings.cfWorkerHost) || '' - cfWorkerHost = cfWorkerHost.replace(/\/$/, '') - if (!cfWorkerHost) { - logger.warn('CF Worker host is not set') - return url - } - - try { - const res = await axios.post(cfWorkerHost, { url }) - if (res.data?.status === 200 && res.data?.key?.startsWith('/')) { - return `${cfWorkerHost}${res.data.key}` - } - } catch (e: any) { - logger.error(e) - } - - return url -} - -const createShortUrlFromSink = async (url: string) => { - let sinkDomain = db.get(configPaths.settings.sinkDomain) || '' - const sinkToken = db.get(configPaths.settings.sinkToken) || '' - if (!sinkDomain || !sinkToken) { - logger.warn('Sink domain or token is not set') - return url - } - if (!/^https?:\/\//.test(sinkDomain)) { - sinkDomain = `http://${sinkDomain}` - } - if (sinkDomain.endsWith('/')) { - sinkDomain = sinkDomain.slice(0, -1) - } - try { - const res = await axios.post( - `${sinkDomain}/api/link/create`, - { url }, - { headers: { Authorization: `Bearer ${sinkToken}` } } - ) - if (res.data?.link?.slug) { - return `${sinkDomain}/${res.data.link.slug}` - } - } catch (e: any) { - logger.error(e) - } - return url -} - -export const generateShortUrl = async (url: string) => { - const server = db.get(configPaths.settings.shortUrlServer) || IShortUrlServer.C1N - switch (server) { - case IShortUrlServer.C1N: - return createC1NShortUrl(url) - case IShortUrlServer.YOURLS: - return createYOURLSShortLink(url) - case IShortUrlServer.CFWORKER: - return createShortUrlForCFWorker(url) - case IShortUrlServer.SINK: - return createShortUrlFromSink(url) - default: - return url - } -} - -export const isUrl = (url: string): boolean => { - try { - return Boolean(new URL(url)) - } catch { - return false - } -} - -export const isUrlEncode = (url: string): boolean => { - url = url || '' - try { - return url !== decodeURI(url) - } catch { - return false - } -} - -export const handleUrlEncode = (url: string): string => (isUrlEncode(url) ? url : encodeURI(url)) - -export const handleUrlEncodeWithSetting = (url: string) => - db.get(configPaths.settings.encodeOutputURL) ? handleUrlEncode(url) : url - -export const handleStreamlinePluginName = (name: string) => name.replace(/(@[^/]+\/)?picgo-plugin-/, '') -export const simpleClone = (obj: any) => JSON.parse(JSON.stringify(obj)) -export const enforceNumber = (num: number | string) => (isNaN(+num) ? 0 : +num) - -export const trimValues = ( - obj: T -): { [K in keyof T]: T[K] extends string ? string : T[K] } => { - return Object.fromEntries( - Object.entries(obj).map(([key, value]) => [key, typeof value === 'string' ? value.trim() : value]) - ) as { [K in keyof T]: T[K] extends string ? string : T[K] } -} - -export const formatEndpoint = (endpoint: string, sslEnabled: boolean): string => { - const hasProtocol = /^https?:\/\//.test(endpoint) - if (!hasProtocol) { - return `${sslEnabled ? 'https' : 'http'}://${endpoint}` - } - return sslEnabled ? endpoint.replace(/^http:\/\//, 'https://') : endpoint.replace(/^https:\/\//, 'http://') -} - -export const formatHttpProxy = ( - proxy: string | undefined, - type: 'object' | 'string' -): IHTTPProxy | undefined | string => { - if (!proxy) return undefined - if (/^https?:\/\//.test(proxy)) { - const { protocol, hostname, port } = new URL(proxy) - return type === 'string' - ? `${protocol}//${hostname}:${port}` - : { - host: hostname, - port: Number(port), - protocol: protocol.slice(0, -1) - } - } - const [host, port] = proxy.split(':') - return type === 'string' - ? `http://${host}:${port}` - : { - host, - port: port ? Number(port) : 80, - protocol: 'http' - } -} - -export function encodeFilePath (filePath: string) { - return filePath.replace(/\\/g, '/').split('/').map(encodeURIComponent).join('/') -} - -export const trimPath = (path: string) => path.replace(/^\/+|\/+$/g, '').replace(/\/+/g, '/') +import path from 'node:path' + +import db from '@core/datastore' +import logger from '@core/picgo/logger' +import axios from 'axios' +import { clipboard, Notification, Tray } from 'electron' +import FormData from 'form-data' +import fs from 'fs-extra' +import { isReactive, isRef, toRaw, unref } from 'vue' + +import type { IHTTPProxy, IPrivateShowNotificationOption, IStringKeyMap } from '#/types/types' +import { configPaths } from '~/utils/configPaths' +import { IShortUrlServer } from '~/utils/enum' + +/** + * get raw data from reactive or ref + */ +export const getRawData = (args: any): any => { + if (isRef(args)) return unref(args) + if (isReactive(args)) return toRaw(args) + if (Array.isArray(args)) return args.map(getRawData) + if (typeof args === 'object' && args !== null) { + const data = {} as Record + for (const key in args) { + data[key] = getRawData(args[key]) + } + return data + } + return args +} + +const getExtension = (fileName: string) => path.extname(fileName).slice(1) + +export const isImage = (fileName: string) => + ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'svg', 'avif'].includes(getExtension(fileName)) + +export let tray: Tray + +export const setTray = (t: Tray) => { + tray = t +} + +export const getTray = () => tray + +export function setTrayToolTip(title: string): void { + if (tray) { + tray.setToolTip(title) + } +} + +export const handleCopyUrl = (str: string): void => { + if (db.get(configPaths.settings.autoCopy) !== false) { + clipboard.writeText(str) + } +} + +/** + * show notification + * @param options + */ +export const showNotification = ( + options: IPrivateShowNotificationOption = { + title: '', + body: '', + clickToCopy: false, + copyContent: '', + clickFn: () => {} + } +) => { + const notification = new Notification({ + title: options.title, + body: options.body + }) + const handleClick = () => { + if (options.clickToCopy) { + clipboard.writeText(options.copyContent || options.body) + } + if (options.clickFn) { + options.clickFn() + } + } + notification.once('click', handleClick) + notification.once('close', () => { + notification.removeListener('click', handleClick) + }) + notification.show() +} + +/** + * macOS public.file-url will get encoded file path, + * so we need to decode it + */ +export const ensureFilePath = (filePath: string, prefix = 'file://'): string => { + filePath = filePath.replace(prefix, '') + if (fs.existsSync(filePath)) { + return `${prefix}${filePath}` + } + filePath = decodeURIComponent(filePath) + if (fs.existsSync(filePath)) { + return `${prefix}${filePath}` + } + return '' +} + +/** + * for builtin clipboard to get image path from clipboard + * @returns + */ +export const getClipboardFilePath = (): string => { + // TODO: linux support + const img = clipboard.readImage() + const platform = process.platform + + if (!img.isEmpty() && platform === 'darwin') { + let imgPath = clipboard.read('public.file-url') // will get file://xxx/xxx + imgPath = ensureFilePath(imgPath) + return imgPath ? imgPath.replace('file://', '') : '' + } + + if (img.isEmpty() && platform === 'win32') { + const imgPath = clipboard + .readBuffer('FileNameW') + ?.toString('ucs2') + ?.replace(RegExp(String.fromCharCode(0), 'g'), '') + return imgPath || '' + } + + return '' +} + +const c1nApi = 'https://c1n.cn/link/short' + +const createC1NShortUrl = async (url: string) => { + const c1nToken = db.get(configPaths.settings.c1nToken) || '' + if (!c1nToken) { + logger.warn('c1n token is not set') + return url + } + try { + const form = new FormData() + form.append('url', url) + const res = await axios.post(c1nApi, form, { + headers: { + token: c1nToken + } + }) + if (res.status >= 200 && res.status < 300 && res.data?.code === 0) { + return res.data.data + } + } catch (e: any) { + logger.error(e) + } + return url +} + +const createYOURLSShortLink = async (url: string) => { + let domain = db.get(configPaths.settings.yourlsDomain) || '' + const signature = db.get(configPaths.settings.yourlsSignature) || '' + + if (!domain || !signature) { + logger.warn('Yourls server or signature is not set') + return url + } + if (!/^https?:\/\//.test(domain)) { + domain = `http://${domain}` + } + const params = new URLSearchParams({ + signature, + action: 'shorturl', + format: 'json', + url + }) + try { + const res = await axios.get(`${domain}/yourls-api.php?${params.toString()}`) + if (res.data?.shorturl) { + return res.data.shorturl + } + } catch (e: any) { + if (e.response?.data?.message?.includes('already exists in database')) { + return e.response.data.shorturl + } + logger.error(e) + } + + return url +} + +const createShortUrlForCFWorker = async (url: string) => { + let cfWorkerHost = db.get(configPaths.settings.cfWorkerHost) || '' + cfWorkerHost = cfWorkerHost.replace(/\/$/, '') + if (!cfWorkerHost) { + logger.warn('CF Worker host is not set') + return url + } + + try { + const res = await axios.post(cfWorkerHost, { url }) + if (res.data?.status === 200 && res.data?.key?.startsWith('/')) { + return `${cfWorkerHost}${res.data.key}` + } + } catch (e: any) { + logger.error(e) + } + + return url +} + +const createShortUrlFromSink = async (url: string) => { + let sinkDomain = db.get(configPaths.settings.sinkDomain) || '' + const sinkToken = db.get(configPaths.settings.sinkToken) || '' + if (!sinkDomain || !sinkToken) { + logger.warn('Sink domain or token is not set') + return url + } + if (!/^https?:\/\//.test(sinkDomain)) { + sinkDomain = `http://${sinkDomain}` + } + if (sinkDomain.endsWith('/')) { + sinkDomain = sinkDomain.slice(0, -1) + } + try { + const res = await axios.post( + `${sinkDomain}/api/link/create`, + { url }, + { headers: { Authorization: `Bearer ${sinkToken}` } } + ) + if (res.data?.link?.slug) { + return `${sinkDomain}/${res.data.link.slug}` + } + } catch (e: any) { + logger.error(e) + } + return url +} + +export const generateShortUrl = async (url: string) => { + const server = db.get(configPaths.settings.shortUrlServer) || IShortUrlServer.C1N + switch (server) { + case IShortUrlServer.C1N: + return createC1NShortUrl(url) + case IShortUrlServer.YOURLS: + return createYOURLSShortLink(url) + case IShortUrlServer.CFWORKER: + return createShortUrlForCFWorker(url) + case IShortUrlServer.SINK: + return createShortUrlFromSink(url) + default: + return url + } +} + +export const isUrl = (url: string): boolean => { + try { + return Boolean(new URL(url)) + } catch { + return false + } +} + +export const isUrlEncode = (url: string): boolean => { + url = url || '' + try { + return url !== decodeURI(url) + } catch { + return false + } +} + +export const handleUrlEncode = (url: string): string => (isUrlEncode(url) ? url : encodeURI(url)) + +export const handleUrlEncodeWithSetting = (url: string) => + db.get(configPaths.settings.encodeOutputURL) ? handleUrlEncode(url) : url + +export const handleStreamlinePluginName = (name: string) => name.replace(/(@[^/]+\/)?picgo-plugin-/, '') +export const simpleClone = (obj: any) => JSON.parse(JSON.stringify(obj)) +export const enforceNumber = (num: number | string) => (isNaN(+num) ? 0 : +num) + +export const trimValues = ( + obj: T +): { [K in keyof T]: T[K] extends string ? string : T[K] } => { + return Object.fromEntries( + Object.entries(obj).map(([key, value]) => [key, typeof value === 'string' ? value.trim() : value]) + ) as { [K in keyof T]: T[K] extends string ? string : T[K] } +} + +export const formatEndpoint = (endpoint: string, sslEnabled: boolean): string => { + const hasProtocol = /^https?:\/\//.test(endpoint) + if (!hasProtocol) { + return `${sslEnabled ? 'https' : 'http'}://${endpoint}` + } + return sslEnabled ? endpoint.replace(/^http:\/\//, 'https://') : endpoint.replace(/^https:\/\//, 'http://') +} + +export const formatHttpProxy = ( + proxy: string | undefined, + type: 'object' | 'string' +): IHTTPProxy | undefined | string => { + if (!proxy) return undefined + if (/^https?:\/\//.test(proxy)) { + const { protocol, hostname, port } = new URL(proxy) + return type === 'string' + ? `${protocol}//${hostname}:${port}` + : { + host: hostname, + port: Number(port), + protocol: protocol.slice(0, -1) + } + } + const [host, port] = proxy.split(':') + return type === 'string' + ? `http://${host}:${port}` + : { + host, + port: port ? Number(port) : 80, + protocol: 'http' + } +} + +export function encodeFilePath(filePath: string) { + return filePath.replace(/\\/g, '/').split('/').map(encodeURIComponent).join('/') +} + +export const trimPath = (path: string) => path.replace(/^\/+|\/+$/g, '').replace(/\/+/g, '/') diff --git a/src/main/utils/configPaths.ts b/src/main/utils/configPaths.ts index 92cb6fb1..010ee375 100644 --- a/src/main/utils/configPaths.ts +++ b/src/main/utils/configPaths.ts @@ -1,188 +1,206 @@ -import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist' - -import type { IAliYunConfig, IAwsS3PListUserConfig, IGitHubConfig, IImgurConfig, ILocalConfig, ILskyConfig, IPicBedType, IQiniuConfig, IServerConfig, ISftpPlistConfig, IShortKeyConfig, ISMMSConfig, ISyncConfig, ITcYunConfig, IUploaderConfig, IUpYunConfig, IWebdavPlistConfig } from '#/types/types' - -export type manualPageOpenType = 'window' | 'browser' - -interface IPicGoPlugins { - [key: `picgo-plugin-${string}`]: boolean -} - -export interface IConfigStruct { - picBed: { - uploader: string - current?: string - smms?: ISMMSConfig - qiniu?: IQiniuConfig - upyun?: IUpYunConfig - tcyun?: ITcYunConfig - github?: IGitHubConfig - aliyun?: IAliYunConfig - imgur?: IImgurConfig - webdavplist?: IWebdavPlistConfig - local?: ILocalConfig - sftpplist?: ISftpPlistConfig - lskyplist?: ILskyConfig - 'aws-s3-plist': IAwsS3PListUserConfig - proxy?: string - transformer?: string - list: IPicBedType[] - [others: string]: any - } - settings: { - shortKey: { - [key: string]: IShortKeyConfig - } - logLevel: string[] - logPath: string - logFileSizeLimit: number - isAutoListenClipboard: boolean - isListeningClipboard: boolean - showUpdateTip: boolean - miniWindowPosition: [number, number] - miniWindowOntop: boolean - mainWindowWidth: number - mainWindowHeight: number - isHideDock: boolean - autoCloseMiniWindow: boolean - autoCloseMainWindow: boolean - isCustomMiniIcon: boolean - customMiniIcon: string - startMode: string - autoRename: boolean - deleteCloudFile: boolean - server: IServerConfig - serverKey: string - pasteStyle: string - aesPassword: string - rename: boolean - sync: ISyncConfig - tempDirPath: string - language: string - customLink: string - manualPageOpen: manualPageOpenType - encodeOutputURL: boolean - useShortUrl: boolean - shortUrlServer: string - c1nToken: string - cfWorkerHost: string - yourlsDomain: string - yourlsSignature: string - sinkDomain: string - sinkToken: string - isSilentNotice: boolean - proxy: string - registry: string - autoCopy: boolean - enableWebServer: boolean - webServerHost: string - webServerPort: number - webServerPath: string - deleteLocalFile: boolean - uploadResultNotification: boolean - uploadNotification: boolean - useBuiltinClipboard: boolean - autoStart: boolean - autoImport: boolean - autoImportPicBed: string[] - } - needReload: boolean - picgoPlugins: IPicGoPlugins - uploader: IUploaderConfig - buildIn: { - compress: IBuildInCompressOptions - watermark: IBuildInWaterMarkOptions - rename: { - enable: boolean - format: string - } - skipProcess: { - skipProcessExtList: string - } - } - debug: boolean - PICGO_ENV: string -} - -export const configPaths = { - picBed: { - current: 'picBed.current', - uploader: 'picBed.uploader', - secondUploader: 'picBed.secondUploader', - secondUploaderId: 'picBed.secondUploaderId', - secondUploaderConfig: 'picBed.secondUploaderConfig', - proxy: 'picBed.proxy', - transformer: 'picBed.transformer', - list: 'picBed.list' - }, - settings: { - shortKey: { - _path: 'settings.shortKey', - 'picgo:upload': 'settings.shortKey[picgo:upload]' - }, - logLevel: 'settings.logLevel', - logPath: 'settings.logPath', - logFileSizeLimit: 'settings.logFileSizeLimit', - isAutoListenClipboard: 'settings.isAutoListenClipboard', - isListeningClipboard: 'settings.isListeningClipboard', - showUpdateTip: 'settings.showUpdateTip', - miniWindowPosition: 'settings.miniWindowPosition', - miniWindowOntop: 'settings.miniWindowOntop', - isHideDock: 'settings.isHideDock', - mainWindowWidth: 'settings.mainWindowWidth', - mainWindowHeight: 'settings.mainWindowHeight', - autoCloseMiniWindow: 'settings.autoCloseMiniWindow', - autoCloseMainWindow: 'settings.autoCloseMainWindow', - isCustomMiniIcon: 'settings.isCustomMiniIcon', - customMiniIcon: 'settings.customMiniIcon', - startMode: 'settings.startMode', - autoRename: 'settings.autoRename', - deleteCloudFile: 'settings.deleteCloudFile', - server: 'settings.server', - serverKey: 'settings.serverKey', - pasteStyle: 'settings.pasteStyle', - aesPassword: 'settings.aesPassword', - rename: 'settings.rename', - sync: 'settings.sync', - tempDirPath: 'settings.tempDirPath', - language: 'settings.language', - customLink: 'settings.customLink', - manualPageOpen: 'settings.manualPageOpen', - encodeOutputURL: 'settings.encodeOutputURL', - useShortUrl: 'settings.useShortUrl', - shortUrlServer: 'settings.shortUrlServer', - c1nToken: 'settings.c1nToken', - cfWorkerHost: 'settings.cfWorkerHost', - yourlsDomain: 'settings.yourlsDomain', - yourlsSignature: 'settings.yourlsSignature', - sinkDomain: 'settings.sinkDomain', - sinkToken: 'settings.sinkToken', - isSilentNotice: 'settings.isSilentNotice', - proxy: 'settings.proxy', - registry: 'settings.registry', - autoCopy: 'settings.autoCopy', - enableWebServer: 'settings.enableWebServer', - webServerHost: 'settings.webServerHost', - webServerPort: 'settings.webServerPort', - webServerPath: 'settings.webServerPath', - deleteLocalFile: 'settings.deleteLocalFile', - uploadResultNotification: 'settings.uploadResultNotification', - uploadNotification: 'settings.uploadNotification', - useBuiltinClipboard: 'settings.useBuiltinClipboard', - autoStart: 'settings.autoStart', - autoImport: 'settings.autoImport', - autoImportPicBed: 'settings.autoImportPicBed', - enableSecondUploader: 'settings.enableSecondUploader' - }, - needReload: 'needReload', - picgoPlugins: 'picgoPlugins', - uploader: 'uploader', - buildIn: { - compress: 'buildIn.compress', - watermark: 'buildIn.watermark', - rename: 'buildIn.rename', - skipProcess: 'buildIn.skipProcess' - }, - debug: 'debug', - PICGO_ENV: 'PICGO_ENV' -} +import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist' + +import type { + IAliYunConfig, + IAwsS3PListUserConfig, + IGitHubConfig, + IImgurConfig, + ILocalConfig, + ILskyConfig, + IPicBedType, + IQiniuConfig, + IServerConfig, + ISftpPlistConfig, + IShortKeyConfig, + ISMMSConfig, + ISyncConfig, + ITcYunConfig, + IUploaderConfig, + IUpYunConfig, + IWebdavPlistConfig +} from '#/types/types' + +export type manualPageOpenType = 'window' | 'browser' + +interface IPicGoPlugins { + [key: `picgo-plugin-${string}`]: boolean +} + +export interface IConfigStruct { + picBed: { + uploader: string + current?: string + smms?: ISMMSConfig + qiniu?: IQiniuConfig + upyun?: IUpYunConfig + tcyun?: ITcYunConfig + github?: IGitHubConfig + aliyun?: IAliYunConfig + imgur?: IImgurConfig + webdavplist?: IWebdavPlistConfig + local?: ILocalConfig + sftpplist?: ISftpPlistConfig + lskyplist?: ILskyConfig + 'aws-s3-plist': IAwsS3PListUserConfig + proxy?: string + transformer?: string + list: IPicBedType[] + [others: string]: any + } + settings: { + shortKey: { + [key: string]: IShortKeyConfig + } + logLevel: string[] + logPath: string + logFileSizeLimit: number + isAutoListenClipboard: boolean + isListeningClipboard: boolean + showUpdateTip: boolean + miniWindowPosition: [number, number] + miniWindowOntop: boolean + mainWindowWidth: number + mainWindowHeight: number + isHideDock: boolean + autoCloseMiniWindow: boolean + autoCloseMainWindow: boolean + isCustomMiniIcon: boolean + customMiniIcon: string + startMode: string + autoRename: boolean + deleteCloudFile: boolean + server: IServerConfig + serverKey: string + pasteStyle: string + aesPassword: string + rename: boolean + sync: ISyncConfig + tempDirPath: string + language: string + customLink: string + manualPageOpen: manualPageOpenType + encodeOutputURL: boolean + useShortUrl: boolean + shortUrlServer: string + c1nToken: string + cfWorkerHost: string + yourlsDomain: string + yourlsSignature: string + sinkDomain: string + sinkToken: string + isSilentNotice: boolean + proxy: string + registry: string + autoCopy: boolean + enableWebServer: boolean + webServerHost: string + webServerPort: number + webServerPath: string + deleteLocalFile: boolean + uploadResultNotification: boolean + uploadNotification: boolean + useBuiltinClipboard: boolean + autoStart: boolean + autoImport: boolean + autoImportPicBed: string[] + } + needReload: boolean + picgoPlugins: IPicGoPlugins + uploader: IUploaderConfig + buildIn: { + compress: IBuildInCompressOptions + watermark: IBuildInWaterMarkOptions + rename: { + enable: boolean + format: string + } + skipProcess: { + skipProcessExtList: string + } + } + debug: boolean + PICGO_ENV: string +} + +export const configPaths = { + picBed: { + current: 'picBed.current', + uploader: 'picBed.uploader', + secondUploader: 'picBed.secondUploader', + secondUploaderId: 'picBed.secondUploaderId', + secondUploaderConfig: 'picBed.secondUploaderConfig', + proxy: 'picBed.proxy', + transformer: 'picBed.transformer', + list: 'picBed.list' + }, + settings: { + shortKey: { + _path: 'settings.shortKey', + 'picgo:upload': 'settings.shortKey[picgo:upload]' + }, + logLevel: 'settings.logLevel', + logPath: 'settings.logPath', + logFileSizeLimit: 'settings.logFileSizeLimit', + isAutoListenClipboard: 'settings.isAutoListenClipboard', + isListeningClipboard: 'settings.isListeningClipboard', + showUpdateTip: 'settings.showUpdateTip', + miniWindowPosition: 'settings.miniWindowPosition', + miniWindowOntop: 'settings.miniWindowOntop', + isHideDock: 'settings.isHideDock', + mainWindowWidth: 'settings.mainWindowWidth', + mainWindowHeight: 'settings.mainWindowHeight', + autoCloseMiniWindow: 'settings.autoCloseMiniWindow', + autoCloseMainWindow: 'settings.autoCloseMainWindow', + isCustomMiniIcon: 'settings.isCustomMiniIcon', + customMiniIcon: 'settings.customMiniIcon', + startMode: 'settings.startMode', + autoRename: 'settings.autoRename', + deleteCloudFile: 'settings.deleteCloudFile', + server: 'settings.server', + serverKey: 'settings.serverKey', + pasteStyle: 'settings.pasteStyle', + aesPassword: 'settings.aesPassword', + rename: 'settings.rename', + sync: 'settings.sync', + tempDirPath: 'settings.tempDirPath', + language: 'settings.language', + customLink: 'settings.customLink', + manualPageOpen: 'settings.manualPageOpen', + encodeOutputURL: 'settings.encodeOutputURL', + useShortUrl: 'settings.useShortUrl', + shortUrlServer: 'settings.shortUrlServer', + c1nToken: 'settings.c1nToken', + cfWorkerHost: 'settings.cfWorkerHost', + yourlsDomain: 'settings.yourlsDomain', + yourlsSignature: 'settings.yourlsSignature', + sinkDomain: 'settings.sinkDomain', + sinkToken: 'settings.sinkToken', + isSilentNotice: 'settings.isSilentNotice', + proxy: 'settings.proxy', + registry: 'settings.registry', + autoCopy: 'settings.autoCopy', + enableWebServer: 'settings.enableWebServer', + webServerHost: 'settings.webServerHost', + webServerPort: 'settings.webServerPort', + webServerPath: 'settings.webServerPath', + deleteLocalFile: 'settings.deleteLocalFile', + uploadResultNotification: 'settings.uploadResultNotification', + uploadNotification: 'settings.uploadNotification', + useBuiltinClipboard: 'settings.useBuiltinClipboard', + autoStart: 'settings.autoStart', + autoImport: 'settings.autoImport', + autoImportPicBed: 'settings.autoImportPicBed', + enableSecondUploader: 'settings.enableSecondUploader' + }, + needReload: 'needReload', + picgoPlugins: 'picgoPlugins', + uploader: 'uploader', + buildIn: { + compress: 'buildIn.compress', + watermark: 'buildIn.watermark', + rename: 'buildIn.rename', + skipProcess: 'buildIn.skipProcess' + }, + debug: 'debug', + PICGO_ENV: 'PICGO_ENV' +} diff --git a/src/main/utils/deleteFunc.ts b/src/main/utils/deleteFunc.ts index a51a2f17..4576d44d 100644 --- a/src/main/utils/deleteFunc.ts +++ b/src/main/utils/deleteFunc.ts @@ -1,98 +1,98 @@ -import crypto from 'node:crypto' -import http, { AgentOptions } from 'node:http' -import https from 'node:https' -import path from 'node:path' -import querystring from 'node:querystring' - -import type { S3ClientConfig } from '@aws-sdk/client-s3' -import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3' -import logger from '@core/picgo/logger' -import { NodeHttpHandler } from '@smithy/node-http-handler' -import axios from 'axios' -import type { ISftpPlistConfig } from 'piclist' - -import type { IObj, IStringKeyMap } from '#/types/types' -import { getAgent } from '~/manage/utils/common' -import SSHClient from '~/utils/sshClient' - -interface DogecloudTokenFull { - Credentials: { - accessKeyId: string - secretAccessKey: string - sessionToken: string - } - ExpiredAt: number - Buckets: { - name: string - s3Bucket: string - s3Endpoint: string - }[] -} - -const dogeRegionMap: IStringKeyMap = { - 'ap-shanghai': '0', - 'ap-beijing': '1', - 'ap-guangzhou': '2', - 'ap-chengdu': '3' -} - -async function dogecloudApi ( - apiPath: string, - data = {}, - jsonMode: boolean = false, - accessKey: string, - secretKey: string -) { - const body = jsonMode ? JSON.stringify(data) : querystring.encode(data) - const sign = crypto - .createHmac('sha1', secretKey) - .update(Buffer.from(apiPath + '\n' + body, 'utf8')) - .digest('hex') - const authorization = `TOKEN ${accessKey}:${sign}` - try { - const res = await axios.request({ - url: `https://api.dogecloud.com${apiPath}`, - method: 'POST', - data: body, - responseType: 'json', - headers: { - 'Content-Type': jsonMode ? 'application/json' : 'application/x-www-form-urlencoded', - Authorization: authorization - } - }) - if (res.data.code !== 200) { - throw new Error('API Error') - } - return res.data.data - } catch (err: any) { - throw new Error('API Error') - } -} - -async function getDogeToken (accessKey: string, secretKey: string): Promise { - try { - const data = await dogecloudApi( - '/auth/tmp_token.json', - { - channel: 'OSS_FULL', - scopes: ['*'] - }, - true, - accessKey, - secretKey - ) - return data - } catch (err: any) { - logger.error(err) - return {} - } -} - -export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode: boolean = false) { - try { - const { - url: rawUrl, - type, +import crypto from 'node:crypto' +import http, { AgentOptions } from 'node:http' +import https from 'node:https' +import path from 'node:path' +import querystring from 'node:querystring' + +import type { S3ClientConfig } from '@aws-sdk/client-s3' +import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3' +import logger from '@core/picgo/logger' +import { NodeHttpHandler } from '@smithy/node-http-handler' +import axios from 'axios' +import type { ISftpPlistConfig } from 'piclist' + +import type { IObj, IStringKeyMap } from '#/types/types' +import { getAgent } from '~/manage/utils/common' +import SSHClient from '~/utils/sshClient' + +interface DogecloudTokenFull { + Credentials: { + accessKeyId: string + secretAccessKey: string + sessionToken: string + } + ExpiredAt: number + Buckets: { + name: string + s3Bucket: string + s3Endpoint: string + }[] +} + +const dogeRegionMap: IStringKeyMap = { + 'ap-shanghai': '0', + 'ap-beijing': '1', + 'ap-guangzhou': '2', + 'ap-chengdu': '3' +} + +async function dogecloudApi( + apiPath: string, + data = {}, + jsonMode: boolean = false, + accessKey: string, + secretKey: string +) { + const body = jsonMode ? JSON.stringify(data) : querystring.encode(data) + const sign = crypto + .createHmac('sha1', secretKey) + .update(Buffer.from(apiPath + '\n' + body, 'utf8')) + .digest('hex') + const authorization = `TOKEN ${accessKey}:${sign}` + try { + const res = await axios.request({ + url: `https://api.dogecloud.com${apiPath}`, + method: 'POST', + data: body, + responseType: 'json', + headers: { + 'Content-Type': jsonMode ? 'application/json' : 'application/x-www-form-urlencoded', + Authorization: authorization + } + }) + if (res.data.code !== 200) { + throw new Error('API Error') + } + return res.data.data + } catch (err: any) { + throw new Error('API Error') + } +} + +async function getDogeToken(accessKey: string, secretKey: string): Promise { + try { + const data = await dogecloudApi( + '/auth/tmp_token.json', + { + channel: 'OSS_FULL', + scopes: ['*'] + }, + true, + accessKey, + secretKey + ) + return data + } catch (err: any) { + logger.error(err) + return {} + } +} + +export async function removeFileFromS3InMain(configMap: IStringKeyMap, dogeMode: boolean = false) { + try { + const { + url: rawUrl, + type, config: { accessKeyID, secretAccessKey, @@ -103,14 +103,14 @@ export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode proxy, urlPrefix } - } = configMap - let { - imgUrl, - config: { region } - } = configMap - if (type === 'aws-s3' || type === 'aws-s3-plist') { - imgUrl = rawUrl || imgUrl || '' - } + } = configMap + let { + imgUrl, + config: { region } + } = configMap + if (type === 'aws-s3' || type === 'aws-s3-plist') { + imgUrl = rawUrl || imgUrl || '' + } let fileKey if (urlPrefix && imgUrl.startsWith(urlPrefix)) { const urlPrefixObj = new URL(urlPrefix) @@ -126,159 +126,159 @@ export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode if (pathStyleAccess) { fileKey = fileKey.replace(/^[^/]+\//, '') } - } - const endpointUrl: string | undefined = endpoint - ? /^https?:\/\//.test(endpoint) - ? endpoint - : `http://${endpoint}` - : undefined - if (endpointUrl && endpointUrl.includes('cloudflarestorage')) { - region = region || 'auto' - } - const sslEnabled = endpointUrl ? endpointUrl.startsWith('https') : true - const agent = getAgent(proxy, sslEnabled) - const commonOptions: AgentOptions = { - keepAlive: true, - keepAliveMsecs: 1000, - scheduling: 'lifo' as 'lifo' | 'fifo' | undefined - } - const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {} - const handler = sslEnabled - ? new NodeHttpHandler({ - httpsAgent: agent.https - ? agent.https - : new https.Agent({ - ...commonOptions, - ...extraOptions - }) - }) - : new NodeHttpHandler({ - httpAgent: agent.http - ? agent.http - : new http.Agent({ - ...commonOptions, - ...extraOptions - }) - }) - const s3Options: S3ClientConfig = { - credentials: { - accessKeyId: accessKeyID, - secretAccessKey - }, - endpoint: endpointUrl, - tls: sslEnabled, - forcePathStyle: pathStyleAccess, - region, - requestHandler: handler - } - if (dogeMode) { - s3Options.credentials = { - accessKeyId: configMap.config.accessKeyID, - secretAccessKey: configMap.config.secretAccessKey, - sessionToken: configMap.config.sessionToken - } - } - let result: any - try { - fileKey = decodeURIComponent(fileKey) - } catch (err: any) {} - try { - const client = new S3Client(s3Options) - const command = new DeleteObjectCommand({ - Bucket: bucketName, - Key: fileKey - }) - result = await client.send(command) - } catch (err: any) { - s3Options.region = 'us-east-1' - const client = new S3Client(s3Options) - const command = new DeleteObjectCommand({ - Bucket: bucketName, - Key: fileKey - }) - result = await client.send(command) - } - return result.$metadata.httpStatusCode === 204 - } catch (err: any) { - logger.error(err) - return false - } -} - -export async function removeFileFromDogeInMain (configMap: IStringKeyMap) { - try { - const { - config: { bucketName, AccessKey, SecretKey } - } = configMap - const token = (await getDogeToken(AccessKey, SecretKey)) as DogecloudTokenFull - const bucket = token.Buckets?.find(item => item.name === bucketName || item.s3Bucket === bucketName) - const newConfigMap = { ...configMap } - newConfigMap.config = { - ...newConfigMap.config, - accessKeyID: token.Credentials?.accessKeyId, - secretAccessKey: token.Credentials?.secretAccessKey, - sessionToken: token.Credentials?.sessionToken, - endpoint: bucket?.s3Endpoint, - region: dogeRegionMap[bucket?.s3Endpoint?.split('.')[1] || 'ap-shanghai'], - bucketName: bucket?.s3Bucket - } - return await removeFileFromS3InMain(newConfigMap, true) - } catch (err: any) { - logger.error(err) - return false - } -} - -function createHuaweiAuthorization ( - bucketName: string, - path: string, - fileName: string, - accessKey: string, - secretKey: string, - date: string = new Date().toUTCString() -) { - const strToSign = `DELETE\n\n\n${date}\n/${bucketName}${path}/${fileName}` - const singature = crypto.createHmac('sha1', secretKey).update(strToSign).digest('base64') - return `OBS ${accessKey}:${singature}` -} - -export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) { - const { fileName, config } = configMap - const { accessKeyId, accessKeySecret, bucketName, endpoint } = config - let path = config.path || '/' - path = `/${path.replace(/^\/+|\/+$/, '')}` - path = path === '/' ? '' : path - const date = new Date().toUTCString() - const authorization = createHuaweiAuthorization(bucketName, path, fileName, accessKeyId, accessKeySecret, date) - try { - const res = await axios.request({ - url: `https://${bucketName}.${endpoint}${encodeURI(path)}/${encodeURIComponent(fileName)}`, - method: 'DELETE', - responseType: 'json', - headers: { - Host: `${bucketName}.${endpoint}`, - Date: date, - Authorization: authorization - } - }) - return res.status === 204 - } catch (error: any) { - logger.error(error) - 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) { - logger.error(err) - return false - } -} + } + const endpointUrl: string | undefined = endpoint + ? /^https?:\/\//.test(endpoint) + ? endpoint + : `http://${endpoint}` + : undefined + if (endpointUrl && endpointUrl.includes('cloudflarestorage')) { + region = region || 'auto' + } + const sslEnabled = endpointUrl ? endpointUrl.startsWith('https') : true + const agent = getAgent(proxy, sslEnabled) + const commonOptions: AgentOptions = { + keepAlive: true, + keepAliveMsecs: 1000, + scheduling: 'lifo' as 'lifo' | 'fifo' | undefined + } + const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {} + const handler = sslEnabled + ? new NodeHttpHandler({ + httpsAgent: agent.https + ? agent.https + : new https.Agent({ + ...commonOptions, + ...extraOptions + }) + }) + : new NodeHttpHandler({ + httpAgent: agent.http + ? agent.http + : new http.Agent({ + ...commonOptions, + ...extraOptions + }) + }) + const s3Options: S3ClientConfig = { + credentials: { + accessKeyId: accessKeyID, + secretAccessKey + }, + endpoint: endpointUrl, + tls: sslEnabled, + forcePathStyle: pathStyleAccess, + region, + requestHandler: handler + } + if (dogeMode) { + s3Options.credentials = { + accessKeyId: configMap.config.accessKeyID, + secretAccessKey: configMap.config.secretAccessKey, + sessionToken: configMap.config.sessionToken + } + } + let result: any + try { + fileKey = decodeURIComponent(fileKey) + } catch (err: any) {} + try { + const client = new S3Client(s3Options) + const command = new DeleteObjectCommand({ + Bucket: bucketName, + Key: fileKey + }) + result = await client.send(command) + } catch (err: any) { + s3Options.region = 'us-east-1' + const client = new S3Client(s3Options) + const command = new DeleteObjectCommand({ + Bucket: bucketName, + Key: fileKey + }) + result = await client.send(command) + } + return result.$metadata.httpStatusCode === 204 + } catch (err: any) { + logger.error(err) + return false + } +} + +export async function removeFileFromDogeInMain(configMap: IStringKeyMap) { + try { + const { + config: { bucketName, AccessKey, SecretKey } + } = configMap + const token = (await getDogeToken(AccessKey, SecretKey)) as DogecloudTokenFull + const bucket = token.Buckets?.find(item => item.name === bucketName || item.s3Bucket === bucketName) + const newConfigMap = { ...configMap } + newConfigMap.config = { + ...newConfigMap.config, + accessKeyID: token.Credentials?.accessKeyId, + secretAccessKey: token.Credentials?.secretAccessKey, + sessionToken: token.Credentials?.sessionToken, + endpoint: bucket?.s3Endpoint, + region: dogeRegionMap[bucket?.s3Endpoint?.split('.')[1] || 'ap-shanghai'], + bucketName: bucket?.s3Bucket + } + return await removeFileFromS3InMain(newConfigMap, true) + } catch (err: any) { + logger.error(err) + return false + } +} + +function createHuaweiAuthorization( + bucketName: string, + path: string, + fileName: string, + accessKey: string, + secretKey: string, + date: string = new Date().toUTCString() +) { + const strToSign = `DELETE\n\n\n${date}\n/${bucketName}${path}/${fileName}` + const singature = crypto.createHmac('sha1', secretKey).update(strToSign).digest('base64') + return `OBS ${accessKey}:${singature}` +} + +export async function removeFileFromHuaweiInMain(configMap: IStringKeyMap) { + const { fileName, config } = configMap + const { accessKeyId, accessKeySecret, bucketName, endpoint } = config + let path = config.path || '/' + path = `/${path.replace(/^\/+|\/+$/, '')}` + path = path === '/' ? '' : path + const date = new Date().toUTCString() + const authorization = createHuaweiAuthorization(bucketName, path, fileName, accessKeyId, accessKeySecret, date) + try { + const res = await axios.request({ + url: `https://${bucketName}.${endpoint}${encodeURI(path)}/${encodeURIComponent(fileName)}`, + method: 'DELETE', + responseType: 'json', + headers: { + Host: `${bucketName}.${endpoint}`, + Date: date, + Authorization: authorization + } + }) + return res.status === 204 + } catch (error: any) { + logger.error(error) + 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) { + logger.error(err) + return false + } +} diff --git a/src/main/utils/deleteLog.ts b/src/main/utils/deleteLog.ts index e3adf466..f226df7a 100644 --- a/src/main/utils/deleteLog.ts +++ b/src/main/utils/deleteLog.ts @@ -1,8 +1,8 @@ -export const deleteLog = (fileName?: string, type?: string, isSuccess = true, msg?: string) => { - console.log(`Delete ${fileName} on ${type} ${isSuccess ? 'success' : 'failed'}, message: ${msg || ''}`) -} - -export const deleteFailedLog = (fileName: string, type: string, error: any) => { - deleteLog(fileName, type, false) - console.error(error) -} +export const deleteLog = (fileName?: string, type?: string, isSuccess = true, msg?: string) => { + console.log(`Delete ${fileName} on ${type} ${isSuccess ? 'success' : 'failed'}, message: ${msg || ''}`) +} + +export const deleteFailedLog = (fileName: string, type: string, error: any) => { + deleteLog(fileName, type, false) + console.error(error) +} diff --git a/src/main/utils/digestAuth.ts b/src/main/utils/digestAuth.ts index 39da1cd8..d48d76b0 100644 --- a/src/main/utils/digestAuth.ts +++ b/src/main/utils/digestAuth.ts @@ -8,11 +8,11 @@ const AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]{1,10000})["']?/ let NC = 0 const NC_PAD = '00000000' -function md5 (text: crypto.BinaryLike) { +function md5(text: crypto.BinaryLike) { return crypto.createHash('md5').update(text).digest('hex') } -export function digestAuthHeader ( +export function digestAuthHeader( method: string, uri: string, wwwAuthenticate: string, @@ -70,7 +70,7 @@ export function digestAuthHeader ( return authstring } -export async function getAuthHeader (method: string, host: string, uri: string, username: string, password: string) { +export async function getAuthHeader(method: string, host: string, uri: string, username: string, password: string) { try { await axios.get(`${host}${uri}`) } catch (error: any) { diff --git a/src/main/utils/enum.ts b/src/main/utils/enum.ts index 380d1ccd..9ba4d5b1 100644 --- a/src/main/utils/enum.ts +++ b/src/main/utils/enum.ts @@ -1,242 +1,242 @@ -export const ILogType = { - success: 'success', - info: 'info', - warn: 'warn', - error: 'error' -} - -export const ICOREBuildInEvent = { - UPLOAD_PROGRESS: 'uploadProgress', - FAILED: 'failed', - BEFORE_TRANSFORM: 'beforeTransform', - BEFORE_UPLOAD: 'beforeUpload', - AFTER_UPLOAD: 'afterUpload', - FINISHED: 'finished', - INSTALL: 'install', - UNINSTALL: 'uninstall', - UPDATE: 'update', - NOTIFICATION: 'notification', - REMOVE: 'remove' -} - -export const IPicGoHelperType = { - afterUploadPlugins: 'afterUploadPlugins', - beforeTransformPlugins: 'beforeTransformPlugins', - beforeUploadPlugins: 'beforeUploadPlugins', - uploader: 'uploader', - transformer: 'transformer' -} - -export const IPasteStyle = { - MARKDOWN: 'markdown', - HTML: 'HTML', - URL: 'URL', - UBB: 'UBB', - CUSTOM: 'Custom' -} - -export const IWindowList = { - SETTING_WINDOW: 'SETTING_WINDOW', - TRAY_WINDOW: 'TRAY_WINDOW', - MINI_WINDOW: 'MINI_WINDOW', - RENAME_WINDOW: 'RENAME_WINDOW', - TOOLBOX_WINDOW: 'TOOLBOX_WINDOW' -} - -export const IRemoteNoticeActionType = { - OPEN_URL: 'OPEN_URL', - SHOW_NOTICE: 'SHOW_NOTICE', // notification - SHOW_DIALOG: 'SHOW_DIALOG', // dialog notice - COMMON: 'COMMON', - VOID: 'VOID', // do nothing - SHOW_MESSAGE_BOX: 'SHOW_MESSAGE_BOX' -} - -export const IRemoteNoticeTriggerHook = { - APP_START: 'APP_START', - SETTING_WINDOW_OPEN: 'SETTING_WINDOW_OPEN' -} - -export const IRemoteNoticeTriggerCount = { - ONCE: 'ONCE', // default - ALWAYS: 'ALWAYS' -} - -export const IRPCType = { - INVOKE: 'INVOKE', - SEND: 'SEND' -} - -export const IRPCActionType = { - // system rpc - RELOAD_APP: 'RELOAD_APP', - OPEN_URL: 'OPEN_URL', - OPEN_FILE: 'OPEN_FILE', - HIDE_DOCK: 'HIDE_DOCK', - SET_CURRENT_LANGUAGE: 'SET_CURRENT_LANGUAGE', - OPEN_WINDOW: 'OPEN_WINDOW', - OPEN_MINI_WINDOW: 'OPEN_MINI_WINDOW', - CLOSE_WINDOW: 'CLOSE_WINDOW', - MINIMIZE_WINDOW: 'MINIMIZE_WINDOW', - SHOW_MINI_PAGE_MENU: 'SHOW_MINI_PAGE_MENU', - SHOW_MAIN_PAGE_MENU: 'SHOW_MAIN_PAGE_MENU', - SHOW_UPLOAD_PAGE_MENU: 'SHOW_UPLOAD_PAGE_MENU', - SHOW_SECOND_UPLOADER_MENU: 'SHOW_SECOND_UPLOADER_MENU', - SHOW_PLUGIN_PAGE_MENU: 'SHOW_PLUGIN_PAGE_MENU', - SET_MINI_WINDOW_POS: 'SET_MINI_WINDOW_POS', - MINI_WINDOW_ON_TOP: 'MINI_WINDOW_ON_TOP', - MAIN_WINDOW_ON_TOP: 'MAIN_WINDOW_ON_TOP', - UPDATE_MINI_WINDOW_ICON: 'UPDATE_MINI_WINDOW_ICON', - REFRESH_SETTING_WINDOW: 'REFRESH_SETTING_WINDOW', - // picbed RPC - PICBED_GET_PICBED_CONFIG: 'PICBED_GET_PICBED_CONFIG', - PICBED_GET_CONFIG_LIST: 'PICBED_GET_CONFIG_LIST', - PICBED_DELETE_CONFIG: 'PICBED_DELETE_CONFIG', - UPLOADER_CHANGE_CURRENT: 'UPLOADER_CHANGE_CURRENT', - UPLOADER_SELECT: 'UPLOADER_SELECT', - UPLOADER_UPDATE_CONFIG: 'UPLOADER_UPDATE_CONFIG', - UPLOADER_RESET_CONFIG: 'UPLOADER_RESET_CONFIG', - DELETE_ALL_API: 'DELETE_ALL_API', - - // toolbox rpc - TOOLBOX_CHECK: 'TOOLBOX_CHECK', - TOOLBOX_CHECK_RES: 'TOOLBOX_CHECK_RES', - TOOLBOX_CHECK_FIX: 'TOOLBOX_CHECK_FIX', - - // main app setting rpc - PICLIST_GET_CONFIG: 'PICLIST_GET_CONFIG', - PICLIST_GET_CONFIG_SYNC: 'PICLIST_GET_CONFIG_SYNC', - PICLIST_SAVE_CONFIG: 'PICLIST_SAVE_CONFIG', - PICLIST_OPEN_FILE: 'PICLIST_OPEN_FILE', - PICLIST_OPEN_DIRECTORY: 'PICLIST_OPEN_DIRECTORY', - PICLIST_AUTO_START: 'PICLIST_AUTO_START', - - // shortkey setting rpc - SHORTKEY_UPDATE: 'SHORTKEY_UPDATE', - SHORTKEY_BIND_OR_UNBIND: 'SHORTKEY_BIND_OR_UNBIND', - SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE: 'SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE', - - // configuration setting rpc - CONFIGURE_MIGRATE_FROM_PICGO: 'CONFIGURE_MIGRATE_FROM_PICGO', - CONFIGURE_UPLOAD_COMMON_CONFIG: 'CONFIGURE_UPLOAD_COMMON_CONFIG', - CONFIGURE_UPLOAD_MANAGE_CONFIG: 'CONFIGURE_UPLOAD_MANAGE_CONFIG', - CONFIGURE_UPLOAD_ALL_CONFIG: 'CONFIGURE_UPLOAD_ALL_CONFIG', - CONFIGURE_DOWNLOAD_COMMON_CONFIG: 'CONFIGURE_DOWNLOAD_COMMON_CONFIG', - CONFIGURE_DOWNLOAD_MANAGE_CONFIG: 'CONFIGURE_DOWNLOAD_MANAGE_CONFIG', - CONFIGURE_DOWNLOAD_ALL_CONFIG: 'CONFIGURE_DOWNLOAD_ALL_CONFIG', - - // advanced setting rpc - ADVANCED_UPDATE_SERVER: 'ADVANCED_UPDATE_SERVER', - ADVANCED_STOP_WEB_SERVER: 'ADVANCED_STOP_WEB_SERVER', - ADVANCED_RESTART_WEB_SERVER: 'ADVANCED_RESTART_WEB_SERVER', - - // upload and main page rpc - MAIN_GET_PICBED: 'MAIN_GET_PICBED', - UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE: 'UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE', - UPLOAD_CHOOSED_FILES: 'UPLOAD_CHOOSED_FILES', - - // gallery rpc - GALLERY_PASTE_TEXT: 'GALLERY_PASTE_TEXT', - GALLERY_REMOVE_FILES: 'GALLERY_REMOVE_FILES', - GALLERY_GET_DB: 'GALLERY_GET_DB', - GALLERY_GET_BY_ID_DB: 'GALLERY_GET_BY_ID_DB', - GALLERY_UPDATE_BY_ID_DB: 'GALLERY_UPDATE_BY_ID_DB', - GALLERY_REMOVE_BY_ID_DB: 'GALLERY_REMOVE_BY_ID_DB', - GALLERY_INSERT_DB: 'GALLERY_INSERT_DB', - GALLERY_INSERT_DB_BATCH: 'GALLERY_INSERT_DB_BATCH', - // plugin rpc - PLUGIN_GET_LIST: 'PLUGIN_GET_LIST', - PLUGIN_INSTALL: 'PLUGIN_INSTALL', - PLUGIN_IMPORT_LOCAL: 'PLUGIN_IMPORT_LOCAL', - PLUGIN_UPDATE_ALL: 'PLUGIN_UPDATE_ALL', - - // tray rpc - TRAY_SET_TOOL_TIP: 'TRAY_SET_TOOL_TIP', - TRAY_GET_SHORT_URL: 'TRAY_GET_SHORT_URL', - TRAY_UPLOAD_CLIPBOARD_FILES: 'TRAY_UPLOAD_CLIPBOARD_FILES', - - // manage rpc - MANAGE_GET_CONFIG: 'MANAGE_GET_CONFIG', - MANAGE_SAVE_CONFIG: 'MANAGE_SAVE_CONFIG', - MANAGE_REMOVE_CONFIG: 'MANAGE_REMOVE_CONFIG', - MANAGE_GET_BUCKET_LIST: 'MANAGE_GET_BUCKET_LIST', - MANAGE_GET_BUCKET_LIST_BACKSTAGE: 'MANAGE_GET_BUCKET_LIST_BACKSTAGE', - MANAGE_GET_BUCKET_LIST_RECURSIVELY: 'MANAGE_GET_BUCKET_LIST_RECURSIVELY', - MANAGE_CREATE_BUCKET: 'MANAGE_CREATE_BUCKET', - MANAGE_GET_BUCKET_FILE_LIST: 'MANAGE_GET_BUCKET_FILE_LIST', - MANAGE_GET_BUCKET_DOMAIN: 'MANAGE_GET_BUCKET_DOMAIN', - MANAGE_SET_BUCKET_ACL_POLICY: 'MANAGE_SET_BUCKET_ACL_POLICY', - MANAGE_RENAME_BUCKET_FILE: 'MANAGE_RENAME_BUCKET_FILE', - MANAGE_DELETE_BUCKET_FILE: 'MANAGE_DELETE_BUCKET_FILE', - MANAGE_DELETE_BUCKET_FOLDER: 'MANAGE_DELETE_BUCKET_FOLDER', - MANAGE_GET_PRE_SIGNED_URL: 'MANAGE_GET_PRE_SIGNED_URL', - MANAGE_UPLOAD_BUCKET_FILE: 'MANAGE_UPLOAD_BUCKET_FILE', - MANAGE_DOWNLOAD_BUCKET_FILE: 'MANAGE_DOWNLOAD_BUCKET_FILE', - MANAGE_CREATE_BUCKET_FOLDER: 'MANAGE_CREATE_BUCKET_FOLDER', - MANAGE_OPEN_FILE_SELECT_DIALOG: 'MANAGE_OPEN_FILE_SELECT_DIALOG', - MANAGE_GET_UPLOAD_TASK_LIST: 'MANAGE_GET_UPLOAD_TASK_LIST', - MANAGE_GET_DOWNLOAD_TASK_LIST: 'MANAGE_GET_DOWNLOAD_TASK_LIST', - MANAGE_DELETE_UPLOADED_TASK: 'MANAGE_DELETE_UPLOADED_TASK', - MANAGE_DELETE_ALL_UPLOADED_TASK: 'MANAGE_DELETE_ALL_UPLOADED_TASK', - MANAGE_DELETE_DOWNLOADED_TASK: 'MANAGE_DELETE_DOWNLOADED_TASK', - MANAGE_DELETE_ALL_DOWNLOADED_TASK: 'MANAGE_DELETE_ALL_DOWNLOADED_TASK', - MANAGE_SELECT_DOWNLOAD_FOLDER: 'MANAGE_SELECT_DOWNLOAD_FOLDER', - MANAGE_GET_DEFAULT_DOWNLOAD_FOLDER: 'MANAGE_GET_DEFAULT_DOWNLOAD_FOLDER', - MANAGE_OPEN_DOWNLOADED_FOLDER: 'MANAGE_OPEN_DOWNLOADED_FOLDER', - MANAGE_OPEN_LOCAL_FILE: 'MANAGE_OPEN_LOCAL_FILE', - MANAGE_DOWNLOAD_FILE_FROM_URL: 'MANAGE_DOWNLOAD_FILE_FROM_URL', - MANAGE_CONVERT_PATH_TO_BASE64: 'MANAGE_CONVERT_PATH_TO_BASE64' -} - -export const IToolboxItemType = { - IS_CONFIG_FILE_BROKEN: 'IS_CONFIG_FILE_BROKEN', - IS_GALLERY_FILE_BROKEN: 'IS_GALLERY_FILE_BROKEN', - HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: 'HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD', - HAS_PROBLEM_WITH_PROXY: 'HAS_PROBLEM_WITH_PROXY' -} - -export const IToolboxItemCheckStatus = { - INIT: 'init', - LOADING: 'loading', - SUCCESS: 'success', - ERROR: 'error' -} - -export const ISartMode = { - QUIET: 'quiet', - MINI: 'mini', - MAIN: 'main', - NO_TRAY: 'no-tray' -} - -export const II18nLanguage = { - ZH_CN: 'zh-CN', - ZH_TW: 'zh-TW', - EN: 'en' -} - -export const IShortUrlServer = { - C1N: 'c1n', - YOURLS: 'yourls', - CFWORKER: 'cf_worker', - SINK: 'sink' -} - -export const commonTaskStatus = { - queuing: 'queuing', - failed: 'failed', - canceled: 'canceled', - paused: 'paused' -} - -// manage task status - -export const uploadTaskSpecialStatus = { - uploading: 'uploading', - uploaded: 'uploaded' -} - -export const downloadTaskSpecialStatus = { - downloading: 'downloading', - downloaded: 'downloaded' -} +export const ILogType = { + success: 'success', + info: 'info', + warn: 'warn', + error: 'error' +} + +export const ICOREBuildInEvent = { + UPLOAD_PROGRESS: 'uploadProgress', + FAILED: 'failed', + BEFORE_TRANSFORM: 'beforeTransform', + BEFORE_UPLOAD: 'beforeUpload', + AFTER_UPLOAD: 'afterUpload', + FINISHED: 'finished', + INSTALL: 'install', + UNINSTALL: 'uninstall', + UPDATE: 'update', + NOTIFICATION: 'notification', + REMOVE: 'remove' +} + +export const IPicGoHelperType = { + afterUploadPlugins: 'afterUploadPlugins', + beforeTransformPlugins: 'beforeTransformPlugins', + beforeUploadPlugins: 'beforeUploadPlugins', + uploader: 'uploader', + transformer: 'transformer' +} + +export const IPasteStyle = { + MARKDOWN: 'markdown', + HTML: 'HTML', + URL: 'URL', + UBB: 'UBB', + CUSTOM: 'Custom' +} + +export const IWindowList = { + SETTING_WINDOW: 'SETTING_WINDOW', + TRAY_WINDOW: 'TRAY_WINDOW', + MINI_WINDOW: 'MINI_WINDOW', + RENAME_WINDOW: 'RENAME_WINDOW', + TOOLBOX_WINDOW: 'TOOLBOX_WINDOW' +} + +export const IRemoteNoticeActionType = { + OPEN_URL: 'OPEN_URL', + SHOW_NOTICE: 'SHOW_NOTICE', // notification + SHOW_DIALOG: 'SHOW_DIALOG', // dialog notice + COMMON: 'COMMON', + VOID: 'VOID', // do nothing + SHOW_MESSAGE_BOX: 'SHOW_MESSAGE_BOX' +} + +export const IRemoteNoticeTriggerHook = { + APP_START: 'APP_START', + SETTING_WINDOW_OPEN: 'SETTING_WINDOW_OPEN' +} + +export const IRemoteNoticeTriggerCount = { + ONCE: 'ONCE', // default + ALWAYS: 'ALWAYS' +} + +export const IRPCType = { + INVOKE: 'INVOKE', + SEND: 'SEND' +} + +export const IRPCActionType = { + // system rpc + RELOAD_APP: 'RELOAD_APP', + OPEN_URL: 'OPEN_URL', + OPEN_FILE: 'OPEN_FILE', + HIDE_DOCK: 'HIDE_DOCK', + SET_CURRENT_LANGUAGE: 'SET_CURRENT_LANGUAGE', + OPEN_WINDOW: 'OPEN_WINDOW', + OPEN_MINI_WINDOW: 'OPEN_MINI_WINDOW', + CLOSE_WINDOW: 'CLOSE_WINDOW', + MINIMIZE_WINDOW: 'MINIMIZE_WINDOW', + SHOW_MINI_PAGE_MENU: 'SHOW_MINI_PAGE_MENU', + SHOW_MAIN_PAGE_MENU: 'SHOW_MAIN_PAGE_MENU', + SHOW_UPLOAD_PAGE_MENU: 'SHOW_UPLOAD_PAGE_MENU', + SHOW_SECOND_UPLOADER_MENU: 'SHOW_SECOND_UPLOADER_MENU', + SHOW_PLUGIN_PAGE_MENU: 'SHOW_PLUGIN_PAGE_MENU', + SET_MINI_WINDOW_POS: 'SET_MINI_WINDOW_POS', + MINI_WINDOW_ON_TOP: 'MINI_WINDOW_ON_TOP', + MAIN_WINDOW_ON_TOP: 'MAIN_WINDOW_ON_TOP', + UPDATE_MINI_WINDOW_ICON: 'UPDATE_MINI_WINDOW_ICON', + REFRESH_SETTING_WINDOW: 'REFRESH_SETTING_WINDOW', + // picbed RPC + PICBED_GET_PICBED_CONFIG: 'PICBED_GET_PICBED_CONFIG', + PICBED_GET_CONFIG_LIST: 'PICBED_GET_CONFIG_LIST', + PICBED_DELETE_CONFIG: 'PICBED_DELETE_CONFIG', + UPLOADER_CHANGE_CURRENT: 'UPLOADER_CHANGE_CURRENT', + UPLOADER_SELECT: 'UPLOADER_SELECT', + UPLOADER_UPDATE_CONFIG: 'UPLOADER_UPDATE_CONFIG', + UPLOADER_RESET_CONFIG: 'UPLOADER_RESET_CONFIG', + DELETE_ALL_API: 'DELETE_ALL_API', + + // toolbox rpc + TOOLBOX_CHECK: 'TOOLBOX_CHECK', + TOOLBOX_CHECK_RES: 'TOOLBOX_CHECK_RES', + TOOLBOX_CHECK_FIX: 'TOOLBOX_CHECK_FIX', + + // main app setting rpc + PICLIST_GET_CONFIG: 'PICLIST_GET_CONFIG', + PICLIST_GET_CONFIG_SYNC: 'PICLIST_GET_CONFIG_SYNC', + PICLIST_SAVE_CONFIG: 'PICLIST_SAVE_CONFIG', + PICLIST_OPEN_FILE: 'PICLIST_OPEN_FILE', + PICLIST_OPEN_DIRECTORY: 'PICLIST_OPEN_DIRECTORY', + PICLIST_AUTO_START: 'PICLIST_AUTO_START', + + // shortkey setting rpc + SHORTKEY_UPDATE: 'SHORTKEY_UPDATE', + SHORTKEY_BIND_OR_UNBIND: 'SHORTKEY_BIND_OR_UNBIND', + SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE: 'SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE', + + // configuration setting rpc + CONFIGURE_MIGRATE_FROM_PICGO: 'CONFIGURE_MIGRATE_FROM_PICGO', + CONFIGURE_UPLOAD_COMMON_CONFIG: 'CONFIGURE_UPLOAD_COMMON_CONFIG', + CONFIGURE_UPLOAD_MANAGE_CONFIG: 'CONFIGURE_UPLOAD_MANAGE_CONFIG', + CONFIGURE_UPLOAD_ALL_CONFIG: 'CONFIGURE_UPLOAD_ALL_CONFIG', + CONFIGURE_DOWNLOAD_COMMON_CONFIG: 'CONFIGURE_DOWNLOAD_COMMON_CONFIG', + CONFIGURE_DOWNLOAD_MANAGE_CONFIG: 'CONFIGURE_DOWNLOAD_MANAGE_CONFIG', + CONFIGURE_DOWNLOAD_ALL_CONFIG: 'CONFIGURE_DOWNLOAD_ALL_CONFIG', + + // advanced setting rpc + ADVANCED_UPDATE_SERVER: 'ADVANCED_UPDATE_SERVER', + ADVANCED_STOP_WEB_SERVER: 'ADVANCED_STOP_WEB_SERVER', + ADVANCED_RESTART_WEB_SERVER: 'ADVANCED_RESTART_WEB_SERVER', + + // upload and main page rpc + MAIN_GET_PICBED: 'MAIN_GET_PICBED', + UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE: 'UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE', + UPLOAD_CHOOSED_FILES: 'UPLOAD_CHOOSED_FILES', + + // gallery rpc + GALLERY_PASTE_TEXT: 'GALLERY_PASTE_TEXT', + GALLERY_REMOVE_FILES: 'GALLERY_REMOVE_FILES', + GALLERY_GET_DB: 'GALLERY_GET_DB', + GALLERY_GET_BY_ID_DB: 'GALLERY_GET_BY_ID_DB', + GALLERY_UPDATE_BY_ID_DB: 'GALLERY_UPDATE_BY_ID_DB', + GALLERY_REMOVE_BY_ID_DB: 'GALLERY_REMOVE_BY_ID_DB', + GALLERY_INSERT_DB: 'GALLERY_INSERT_DB', + GALLERY_INSERT_DB_BATCH: 'GALLERY_INSERT_DB_BATCH', + // plugin rpc + PLUGIN_GET_LIST: 'PLUGIN_GET_LIST', + PLUGIN_INSTALL: 'PLUGIN_INSTALL', + PLUGIN_IMPORT_LOCAL: 'PLUGIN_IMPORT_LOCAL', + PLUGIN_UPDATE_ALL: 'PLUGIN_UPDATE_ALL', + + // tray rpc + TRAY_SET_TOOL_TIP: 'TRAY_SET_TOOL_TIP', + TRAY_GET_SHORT_URL: 'TRAY_GET_SHORT_URL', + TRAY_UPLOAD_CLIPBOARD_FILES: 'TRAY_UPLOAD_CLIPBOARD_FILES', + + // manage rpc + MANAGE_GET_CONFIG: 'MANAGE_GET_CONFIG', + MANAGE_SAVE_CONFIG: 'MANAGE_SAVE_CONFIG', + MANAGE_REMOVE_CONFIG: 'MANAGE_REMOVE_CONFIG', + MANAGE_GET_BUCKET_LIST: 'MANAGE_GET_BUCKET_LIST', + MANAGE_GET_BUCKET_LIST_BACKSTAGE: 'MANAGE_GET_BUCKET_LIST_BACKSTAGE', + MANAGE_GET_BUCKET_LIST_RECURSIVELY: 'MANAGE_GET_BUCKET_LIST_RECURSIVELY', + MANAGE_CREATE_BUCKET: 'MANAGE_CREATE_BUCKET', + MANAGE_GET_BUCKET_FILE_LIST: 'MANAGE_GET_BUCKET_FILE_LIST', + MANAGE_GET_BUCKET_DOMAIN: 'MANAGE_GET_BUCKET_DOMAIN', + MANAGE_SET_BUCKET_ACL_POLICY: 'MANAGE_SET_BUCKET_ACL_POLICY', + MANAGE_RENAME_BUCKET_FILE: 'MANAGE_RENAME_BUCKET_FILE', + MANAGE_DELETE_BUCKET_FILE: 'MANAGE_DELETE_BUCKET_FILE', + MANAGE_DELETE_BUCKET_FOLDER: 'MANAGE_DELETE_BUCKET_FOLDER', + MANAGE_GET_PRE_SIGNED_URL: 'MANAGE_GET_PRE_SIGNED_URL', + MANAGE_UPLOAD_BUCKET_FILE: 'MANAGE_UPLOAD_BUCKET_FILE', + MANAGE_DOWNLOAD_BUCKET_FILE: 'MANAGE_DOWNLOAD_BUCKET_FILE', + MANAGE_CREATE_BUCKET_FOLDER: 'MANAGE_CREATE_BUCKET_FOLDER', + MANAGE_OPEN_FILE_SELECT_DIALOG: 'MANAGE_OPEN_FILE_SELECT_DIALOG', + MANAGE_GET_UPLOAD_TASK_LIST: 'MANAGE_GET_UPLOAD_TASK_LIST', + MANAGE_GET_DOWNLOAD_TASK_LIST: 'MANAGE_GET_DOWNLOAD_TASK_LIST', + MANAGE_DELETE_UPLOADED_TASK: 'MANAGE_DELETE_UPLOADED_TASK', + MANAGE_DELETE_ALL_UPLOADED_TASK: 'MANAGE_DELETE_ALL_UPLOADED_TASK', + MANAGE_DELETE_DOWNLOADED_TASK: 'MANAGE_DELETE_DOWNLOADED_TASK', + MANAGE_DELETE_ALL_DOWNLOADED_TASK: 'MANAGE_DELETE_ALL_DOWNLOADED_TASK', + MANAGE_SELECT_DOWNLOAD_FOLDER: 'MANAGE_SELECT_DOWNLOAD_FOLDER', + MANAGE_GET_DEFAULT_DOWNLOAD_FOLDER: 'MANAGE_GET_DEFAULT_DOWNLOAD_FOLDER', + MANAGE_OPEN_DOWNLOADED_FOLDER: 'MANAGE_OPEN_DOWNLOADED_FOLDER', + MANAGE_OPEN_LOCAL_FILE: 'MANAGE_OPEN_LOCAL_FILE', + MANAGE_DOWNLOAD_FILE_FROM_URL: 'MANAGE_DOWNLOAD_FILE_FROM_URL', + MANAGE_CONVERT_PATH_TO_BASE64: 'MANAGE_CONVERT_PATH_TO_BASE64' +} + +export const IToolboxItemType = { + IS_CONFIG_FILE_BROKEN: 'IS_CONFIG_FILE_BROKEN', + IS_GALLERY_FILE_BROKEN: 'IS_GALLERY_FILE_BROKEN', + HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: 'HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD', + HAS_PROBLEM_WITH_PROXY: 'HAS_PROBLEM_WITH_PROXY' +} + +export const IToolboxItemCheckStatus = { + INIT: 'init', + LOADING: 'loading', + SUCCESS: 'success', + ERROR: 'error' +} + +export const ISartMode = { + QUIET: 'quiet', + MINI: 'mini', + MAIN: 'main', + NO_TRAY: 'no-tray' +} + +export const II18nLanguage = { + ZH_CN: 'zh-CN', + ZH_TW: 'zh-TW', + EN: 'en' +} + +export const IShortUrlServer = { + C1N: 'c1n', + YOURLS: 'yourls', + CFWORKER: 'cf_worker', + SINK: 'sink' +} + +export const commonTaskStatus = { + queuing: 'queuing', + failed: 'failed', + canceled: 'canceled', + paused: 'paused' +} + +// manage task status + +export const uploadTaskSpecialStatus = { + uploading: 'uploading', + uploaded: 'uploaded' +} + +export const downloadTaskSpecialStatus = { + downloading: 'downloading', + downloaded: 'downloaded' +} diff --git a/src/main/utils/getMacOSVersion.ts b/src/main/utils/getMacOSVersion.ts index e3f3f8bb..ef8cc43d 100644 --- a/src/main/utils/getMacOSVersion.ts +++ b/src/main/utils/getMacOSVersion.ts @@ -22,7 +22,7 @@ const parseVersion = (plist: string) => { return matches[1].replace('10.16', '11') } -export function macOSVersion (): string { +export function macOSVersion(): string { if (!isMacOS) return '' if (!version) { @@ -43,7 +43,7 @@ if (process.env.NODE_ENV === 'test') { macOSVersion._parseVersion = parseVersion } -export function isMacOSVersion (semverRange: string) { +export function isMacOSVersion(semverRange: string) { if (!isMacOS) { return false } @@ -53,7 +53,7 @@ export function isMacOSVersion (semverRange: string) { return semver.satisfies(macOSVersion(), clean(semverRange)) } -export function isMacOSVersionGreaterThanOrEqualTo (version: string) { +export function isMacOSVersionGreaterThanOrEqualTo(version: string) { if (!isMacOS) { return false } @@ -63,7 +63,7 @@ export function isMacOSVersionGreaterThanOrEqualTo (version: string) { return semver.gte(macOSVersion(), clean(version)) } -export function assertMacOSVersion (semverRange: string) { +export function assertMacOSVersion(semverRange: string) { semverRange = semverRange.replace('10.16', '11') if (!isMacOSVersion(semverRange)) { @@ -71,7 +71,7 @@ export function assertMacOSVersion (semverRange: string) { } } -export function assertMacOSVersionGreaterThanOrEqualTo (version: string) { +export function assertMacOSVersionGreaterThanOrEqualTo(version: string) { version = version.replace('10.16', '11') if (!isMacOSVersionGreaterThanOrEqualTo(version)) { @@ -79,7 +79,7 @@ export function assertMacOSVersionGreaterThanOrEqualTo (version: string) { } } -export function assertMacOS () { +export function assertMacOS() { if (!isMacOS) { throw new Error('Requires macOS') } diff --git a/src/main/utils/handleUploaderConfig.ts b/src/main/utils/handleUploaderConfig.ts index c3c91c96..61a615d1 100644 --- a/src/main/utils/handleUploaderConfig.ts +++ b/src/main/utils/handleUploaderConfig.ts @@ -1,7 +1,13 @@ import picgo from '@core/picgo' import { v4 as uuid } from 'uuid' -import type { IPicGoPluginConfig, IPicGoPluginOriginConfig, IStringKeyMap, IUploaderConfigItem, IUploaderConfigListItem } from '#/types/types' +import type { + IPicGoPluginConfig, + IPicGoPluginOriginConfig, + IStringKeyMap, + IUploaderConfigItem, + IUploaderConfigListItem +} from '#/types/types' import { setTrayToolTip, trimValues } from '~/utils/common' import { configPaths } from '~/utils/configPaths' diff --git a/src/main/utils/notification.ts b/src/main/utils/notification.ts index 2ff3c7aa..85e95a1d 100644 --- a/src/main/utils/notification.ts +++ b/src/main/utils/notification.ts @@ -1,3 +1,3 @@ -import type { IAppNotification } from '#/types/types' - -export const notificationList: IAppNotification[] = [] +import type { IAppNotification } from '#/types/types' + +export const notificationList: IAppNotification[] = [] diff --git a/src/main/utils/performanceOptimizer.ts b/src/main/utils/performanceOptimizer.ts index 24c66d4c..8c751750 100644 --- a/src/main/utils/performanceOptimizer.ts +++ b/src/main/utils/performanceOptimizer.ts @@ -1,31 +1,33 @@ -export class MemoryMonitor { - // eslint-disable-next-line no-undef - private static interval: NodeJS.Timeout | null = null - - static start (intervalMs: number = 30000) { - if (this.interval) return - - this.interval = setInterval(() => { - const memUsage = process.memoryUsage() - const mbUsage = { - rss: Math.round(memUsage.rss / 1024 / 1024), - heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024), - heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024), - external: Math.round(memUsage.external / 1024 / 1024) - } - console.log(`[Memory] RSS: ${mbUsage.rss}MB, Heap: ${mbUsage.heapUsed}/${mbUsage.heapTotal}MB, External: ${mbUsage.external}MB`) - - if (mbUsage.heapUsed / mbUsage.heapTotal > 0.8 && global.gc) { - console.log('[Memory] Triggering garbage collection') - global.gc() - } - }, intervalMs) - } - - static stop () { - if (this.interval) { - clearInterval(this.interval) - this.interval = null - } - } -} +export class MemoryMonitor { + // eslint-disable-next-line no-undef + private static interval: NodeJS.Timeout | null = null + + static start(intervalMs: number = 30000) { + if (this.interval) return + + this.interval = setInterval(() => { + const memUsage = process.memoryUsage() + const mbUsage = { + rss: Math.round(memUsage.rss / 1024 / 1024), + heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024), + heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024), + external: Math.round(memUsage.external / 1024 / 1024) + } + console.log( + `[Memory] RSS: ${mbUsage.rss}MB, Heap: ${mbUsage.heapUsed}/${mbUsage.heapTotal}MB, External: ${mbUsage.external}MB` + ) + + if (mbUsage.heapUsed / mbUsage.heapTotal > 0.8 && global.gc) { + console.log('[Memory] Triggering garbage collection') + global.gc() + } + }, intervalMs) + } + + static stop() { + if (this.interval) { + clearInterval(this.interval) + this.interval = null + } + } +} diff --git a/src/main/utils/sshClient.ts b/src/main/utils/sshClient.ts index f5d4c09d..ab84118e 100644 --- a/src/main/utils/sshClient.ts +++ b/src/main/utils/sshClient.ts @@ -1,194 +1,194 @@ -import path from 'node:path' - -import logger from '@core/picgo/logger' -import fs from 'fs-extra' -import { Config, NodeSSH, SSHExecCommandResponse } from 'node-ssh-no-cpu-features' -import { ISftpPlistConfig } from 'piclist/dist/types' -import { Client } from 'ssh2-no-cpu-features' - -class SSHClient { - private static _instance: SSHClient - private static _client: NodeSSH - private _isConnected = false - - static get instance (): SSHClient { - return this._instance || (this._instance = new this()) - } - - static get client (): NodeSSH { - return this._client || (this._client = new NodeSSH()) - } - - private changeWinStylePathToUnix (path: string): string { - return path.replace(/\\/g, '/') - } - - async connect (config: ISftpPlistConfig): Promise { - const { username, password, privateKey, passphrase } = config - const loginInfo: Config = privateKey - ? { - username, - privateKeyPath: privateKey, - passphrase: passphrase || undefined - } - : { username, password } - try { - await SSHClient.client.connect({ - host: config.host, - port: Number(config.port) || 22, - ...loginInfo - }) - this._isConnected = true - return true - } catch (err: any) { - throw new Error(err) - } - } - - async deleteFileSFTP (config: ISftpPlistConfig, remote: string): Promise { - try { - const client = new Client() - const { username, password, privateKey, passphrase } = config - const loginInfo: Config = privateKey - ? { - username, - privateKey: fs.readFileSync(privateKey), - passphrase: passphrase || undefined - } - : { username, password } - remote = this.changeWinStylePathToUnix(remote) - if (remote === '/' || remote.includes('*')) return false - const promise = new Promise((resolve, reject) => { - client - .on('ready', () => { - client.sftp( - ( - err: any, - sftp: { - unlink: (arg0: string, arg1: (err: any) => void) => void - } - ) => { - // eslint-disable-next-line prefer-promise-reject-errors - if (err) reject(false) - sftp.unlink(remote, (err: any) => { - // eslint-disable-next-line prefer-promise-reject-errors - if (err) reject(false) - client.end() - resolve(true) - }) - } - ) - }) - .connect({ - host: config.host, - port: Number(config.port) || 22, - ...loginInfo - }) - }) - return (await promise) as boolean - } catch (err: any) { - logger.error(err) - return false - } - } - - private async exec (script: string): Promise { - const execResult = await SSHClient.client.execCommand(script) - return execResult.code === 0 - } - - async execCommand (script: string): Promise { - const execResult = await SSHClient.client.execCommand(script) - return execResult || { code: 1, stdout: '', stderr: '' } - } - - async getFile (local: string, remote: string): Promise { - if (!this._isConnected) { - throw new Error('SSH 未连接') - } - try { - remote = this.changeWinStylePathToUnix(remote) - local = this.changeWinStylePathToUnix(local) - await SSHClient.client.getFile(local, remote, undefined, { - concurrency: 1 - }) - return true - } catch (err: any) { - logger.error(err) - return false - } - } - - async putFile ( - local: string, - remote: string, - config: { - fileMode?: string - dirMode?: string - } = {} - ): Promise { - if (!this._isConnected) { - throw new Error('SSH 未连接') - } - try { - remote = this.changeWinStylePathToUnix(remote) - await this.mkdir(path.dirname(remote).replace(/^\/+|\/+$/g, ''), config) - await SSHClient.client.putFile(local, remote) - const fileMode = config.fileMode || '0644' - if (fileMode !== '0644') { - const script = `chmod ${fileMode} "${remote}"` - return await this.exec(script) - } - return true - } catch (err: any) { - logger.error(err) - return false - } - } - - async mkdir ( - dirPath: string, - config: { - dirMode?: string - } = {} - ): Promise { - if (!this._isConnected) { - throw new Error('SSH 未连接') - } - try { - const directoryMode = config.dirMode || '0755' - if (directoryMode === '0755') { - const script = `mkdir -p "${dirPath}"` - return await this.exec(script) - } else { - const dirs = dirPath.split('/') - let currentPath = '' - for (const dir of dirs) { - if (dir) { - currentPath += `/${dir}` - const script = `mkdir "${currentPath}" && chmod ${directoryMode} "${currentPath}"` - const result = await this.exec(script) - if (!result) { - return false - } - } - } - return true - } - } catch (err: any) { - logger.error(err) - return false - } - } - - get isConnected (): boolean { - return SSHClient.client.isConnected() - } - - close (): void { - SSHClient.client.dispose() - this._isConnected = false - } -} - -export default SSHClient +import path from 'node:path' + +import logger from '@core/picgo/logger' +import fs from 'fs-extra' +import { Config, NodeSSH, SSHExecCommandResponse } from 'node-ssh-no-cpu-features' +import { ISftpPlistConfig } from 'piclist/dist/types' +import { Client } from 'ssh2-no-cpu-features' + +class SSHClient { + private static _instance: SSHClient + private static _client: NodeSSH + private _isConnected = false + + static get instance(): SSHClient { + return this._instance || (this._instance = new this()) + } + + static get client(): NodeSSH { + return this._client || (this._client = new NodeSSH()) + } + + private changeWinStylePathToUnix(path: string): string { + return path.replace(/\\/g, '/') + } + + async connect(config: ISftpPlistConfig): Promise { + const { username, password, privateKey, passphrase } = config + const loginInfo: Config = privateKey + ? { + username, + privateKeyPath: privateKey, + passphrase: passphrase || undefined + } + : { username, password } + try { + await SSHClient.client.connect({ + host: config.host, + port: Number(config.port) || 22, + ...loginInfo + }) + this._isConnected = true + return true + } catch (err: any) { + throw new Error(err) + } + } + + async deleteFileSFTP(config: ISftpPlistConfig, remote: string): Promise { + try { + const client = new Client() + const { username, password, privateKey, passphrase } = config + const loginInfo: Config = privateKey + ? { + username, + privateKey: fs.readFileSync(privateKey), + passphrase: passphrase || undefined + } + : { username, password } + remote = this.changeWinStylePathToUnix(remote) + if (remote === '/' || remote.includes('*')) return false + const promise = new Promise((resolve, reject) => { + client + .on('ready', () => { + client.sftp( + ( + err: any, + sftp: { + unlink: (arg0: string, arg1: (err: any) => void) => void + } + ) => { + // eslint-disable-next-line prefer-promise-reject-errors + if (err) reject(false) + sftp.unlink(remote, (err: any) => { + // eslint-disable-next-line prefer-promise-reject-errors + if (err) reject(false) + client.end() + resolve(true) + }) + } + ) + }) + .connect({ + host: config.host, + port: Number(config.port) || 22, + ...loginInfo + }) + }) + return (await promise) as boolean + } catch (err: any) { + logger.error(err) + return false + } + } + + private async exec(script: string): Promise { + const execResult = await SSHClient.client.execCommand(script) + return execResult.code === 0 + } + + async execCommand(script: string): Promise { + const execResult = await SSHClient.client.execCommand(script) + return execResult || { code: 1, stdout: '', stderr: '' } + } + + async getFile(local: string, remote: string): Promise { + if (!this._isConnected) { + throw new Error('SSH 未连接') + } + try { + remote = this.changeWinStylePathToUnix(remote) + local = this.changeWinStylePathToUnix(local) + await SSHClient.client.getFile(local, remote, undefined, { + concurrency: 1 + }) + return true + } catch (err: any) { + logger.error(err) + return false + } + } + + async putFile( + local: string, + remote: string, + config: { + fileMode?: string + dirMode?: string + } = {} + ): Promise { + if (!this._isConnected) { + throw new Error('SSH 未连接') + } + try { + remote = this.changeWinStylePathToUnix(remote) + await this.mkdir(path.dirname(remote).replace(/^\/+|\/+$/g, ''), config) + await SSHClient.client.putFile(local, remote) + const fileMode = config.fileMode || '0644' + if (fileMode !== '0644') { + const script = `chmod ${fileMode} "${remote}"` + return await this.exec(script) + } + return true + } catch (err: any) { + logger.error(err) + return false + } + } + + async mkdir( + dirPath: string, + config: { + dirMode?: string + } = {} + ): Promise { + if (!this._isConnected) { + throw new Error('SSH 未连接') + } + try { + const directoryMode = config.dirMode || '0755' + if (directoryMode === '0755') { + const script = `mkdir -p "${dirPath}"` + return await this.exec(script) + } else { + const dirs = dirPath.split('/') + let currentPath = '' + for (const dir of dirs) { + if (dir) { + currentPath += `/${dir}` + const script = `mkdir "${currentPath}" && chmod ${directoryMode} "${currentPath}"` + const result = await this.exec(script) + if (!result) { + return false + } + } + } + return true + } + } catch (err: any) { + logger.error(err) + return false + } + } + + get isConnected(): boolean { + return SSHClient.client.isConnected() + } + + close(): void { + SSHClient.client.dispose() + this._isConnected = false + } +} + +export default SSHClient diff --git a/src/main/utils/static.ts b/src/main/utils/static.ts index d591a80a..cb9481d2 100644 --- a/src/main/utils/static.ts +++ b/src/main/utils/static.ts @@ -1,25 +1,25 @@ -export const CLIPBOARD_IMAGE_FOLDER = 'piclist-clipboard-images' - -export const cancelDownloadLoadingFileList = 'cancelDownloadLoadingFileList' -export const refreshDownloadFileTransferList = 'refreshDownloadFileTransferList' - -export const picBedsCanbeDeleted = [ - 'aliyun', - 'alist', - 'alistplist', - 'aws-s3', - 'aws-s3-plist', - 'dogecloud', - 'github', - 'huaweicloud-uploader', - 'imgur', - 'local', - 'lskyplist', - 'piclist', - 'qiniu', - 'sftpplist', - 'smms', - 'tcyun', - 'upyun', - 'webdavplist' -] +export const CLIPBOARD_IMAGE_FOLDER = 'piclist-clipboard-images' + +export const cancelDownloadLoadingFileList = 'cancelDownloadLoadingFileList' +export const refreshDownloadFileTransferList = 'refreshDownloadFileTransferList' + +export const picBedsCanbeDeleted = [ + 'aliyun', + 'alist', + 'alistplist', + 'aws-s3', + 'aws-s3-plist', + 'dogecloud', + 'github', + 'huaweicloud-uploader', + 'imgur', + 'local', + 'lskyplist', + 'piclist', + 'qiniu', + 'sftpplist', + 'smms', + 'tcyun', + 'upyun', + 'webdavplist' +] diff --git a/src/main/utils/syncSettings.ts b/src/main/utils/syncSettings.ts index 7e67c2be..9b5b4469 100644 --- a/src/main/utils/syncSettings.ts +++ b/src/main/utils/syncSettings.ts @@ -37,16 +37,16 @@ const getSyncConfig = () => { const getProxyagent = (proxy: string | undefined) => { return proxy ? new HttpsProxyAgent({ - keepAlive: true, - keepAliveMsecs: 1000, - rejectUnauthorized: false, - proxy: proxy.replace('127.0.0.1', 'localhost'), - scheduling: 'lifo' - }) + keepAlive: true, + keepAliveMsecs: 1000, + rejectUnauthorized: false, + proxy: proxy.replace('127.0.0.1', 'localhost'), + scheduling: 'lifo' + }) : undefined } -function getOctokit (syncConfig: ISyncConfig) { +function getOctokit(syncConfig: ISyncConfig) { const { token, proxy } = syncConfig return new Octokit({ auth: token, @@ -83,7 +83,7 @@ const isSyncConfigValidate = ({ return type && username && repo && branch && token } -async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) { +async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const localFilePath = path.join(STORE_PATH, fileName) if (!fs.existsSync(localFilePath)) { return false @@ -161,7 +161,7 @@ async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) { } } -async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) { +async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const localFilePath = path.join(STORE_PATH, fileName) if (!fs.existsSync(localFilePath)) { return false @@ -277,7 +277,7 @@ async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) { } } -async function uploadFile (fileName: string[]): Promise { +async function uploadFile(fileName: string[]): Promise { const syncConfig = getSyncConfig() if (!isSyncConfigValidate(syncConfig)) { logger.error('sync config is invalid') @@ -302,7 +302,7 @@ async function uploadFile (fileName: string[]): Promise { return count } -async function downloadAndWriteFile (url: string, localFilePath: string, config: any, isWriteJson = false) { +async function downloadAndWriteFile(url: string, localFilePath: string, config: any, isWriteJson = false) { const res = await axios.get(url, config) if (isHttpResSuccess(res)) { await fs.writeFile( @@ -314,7 +314,7 @@ async function downloadAndWriteFile (url: string, localFilePath: string, config: return false } -async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) { +async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) { const localFilePath = path.join(STORE_PATH, fileName) const { username, repo, branch, token, proxy, type } = syncConfig try { @@ -394,7 +394,7 @@ async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) } } -async function downloadFile (fileName: string[]): Promise { +async function downloadFile(fileName: string[]): Promise { const syncConfig = getSyncConfig() if (!isSyncConfigValidate(syncConfig)) { logger.error('sync config is invalid') diff --git a/src/main/utils/windowHelper.ts b/src/main/utils/windowHelper.ts index ffc29e4b..9d366023 100644 --- a/src/main/utils/windowHelper.ts +++ b/src/main/utils/windowHelper.ts @@ -1,66 +1,72 @@ -import db from '@core/datastore' -import windowManager from 'apis/app/window/windowManager' -import { screen } from 'electron' - -import { configPaths } from '~/utils/configPaths' -import { IWindowList } from '~/utils/enum' - -export function openMiniWindow (hideSettingWindow: boolean = true) { - const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! - - miniWindow.removeAllListeners('close') - miniWindow.removeAllListeners('move') - - if (db.get(configPaths.settings.miniWindowOntop)) { - miniWindow.setAlwaysOnTop(true) - } - const { width, height } = screen.getPrimaryDisplay().workAreaSize - const lastPosition = db.get(configPaths.settings.miniWindowPosition) - const setPositionFunc = () => { - const position = miniWindow.getPosition() - db.set(configPaths.settings.miniWindowPosition, position) - } - if (lastPosition) { - if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) { - miniWindow.setPosition(width - 100, height - 100) - db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100]) - } else if (lastPosition[0] + miniWindow.getSize()[0] > width || lastPosition[1] + miniWindow.getSize()[1] > height) { - miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]) - db.set(configPaths.settings.miniWindowPosition, [width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]]) - } else { - miniWindow.setPosition(lastPosition[0], lastPosition[1]) - } - } else { - miniWindow.setPosition(width - 100, height - 100) - } - - 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() - } -} +import db from '@core/datastore' +import windowManager from 'apis/app/window/windowManager' +import { screen } from 'electron' + +import { configPaths } from '~/utils/configPaths' +import { IWindowList } from '~/utils/enum' + +export function openMiniWindow(hideSettingWindow: boolean = true) { + const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! + + miniWindow.removeAllListeners('close') + miniWindow.removeAllListeners('move') + + if (db.get(configPaths.settings.miniWindowOntop)) { + miniWindow.setAlwaysOnTop(true) + } + const { width, height } = screen.getPrimaryDisplay().workAreaSize + const lastPosition = db.get(configPaths.settings.miniWindowPosition) + const setPositionFunc = () => { + const position = miniWindow.getPosition() + db.set(configPaths.settings.miniWindowPosition, position) + } + if (lastPosition) { + if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) { + miniWindow.setPosition(width - 100, height - 100) + db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100]) + } else if ( + lastPosition[0] + miniWindow.getSize()[0] > width || + lastPosition[1] + miniWindow.getSize()[1] > height + ) { + miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]) + db.set(configPaths.settings.miniWindowPosition, [ + width - miniWindow.getSize()[0], + height - miniWindow.getSize()[1] + ]) + } else { + miniWindow.setPosition(lastPosition[0], lastPosition[1]) + } + } else { + miniWindow.setPosition(width - 100, height - 100) + } + + 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/preload/index.ts b/src/preload/index.ts index 3c704a53..5ff1d16c 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -1,101 +1,101 @@ -import crypto from 'node:crypto' -import path from 'node:path' - -import { clipboard, contextBridge, ipcRenderer, IpcRendererEvent, webFrame, webUtils } from 'electron' -import fs from 'fs-extra' -import yaml from 'js-yaml' -import mime from 'mime-types' -import { isReactive, isRef, toRaw, unref } from 'vue' - -export const getRawData = (args: any): any => { - if (isRef(args)) return unref(args) - if (isReactive(args)) return toRaw(args) - if (Array.isArray(args)) return args.map(getRawData) - if (typeof args === 'object' && args !== null) { - const data = {} as Record - for (const key in args) { - data[key] = getRawData(args[key]) - } - return data - } - return args -} - -function sendToMain (channel: string, ...args: any[]) { - ipcRenderer.send(channel, ...getRawData(args)) -} - -function sendRPC (action: string, ...args: any[]): void { - ipcRenderer.send('RPC_ACTIONS', action, getRawData(args)) -} - -async function triggerRPC (action: string, ...args: any[]): Promise { - return await ipcRenderer.invoke('RPC_ACTIONS_INVOKE', action, getRawData(args)) -} - -function sendRpcSync (action: string, ...args: any[]): any { - return ipcRenderer.sendSync('RPC_ACTIONS', action, getRawData(args)) -} - -try { - contextBridge.exposeInMainWorld('electron', { - setVisualZoomLevelLimits: (min: number, max: number) => { - webFrame.setVisualZoomLevelLimits(min, max) - }, - clipboard: { - writeText: clipboard.writeText - }, - platform: process.platform, - sendRpcSync, - triggerRPC, - sendToMain, - sendRPC, - ipcRendererOn: (channel: string, listener: (...args: any[]) => void) => { - const subscription = (_: IpcRendererEvent, ...args: any[]) => listener(...args) - ipcRenderer.on(channel, subscription) - return () => { - ipcRenderer.removeListener(channel, subscription) - } - }, - ipcRendererCountListeners: (channel: string): number => { - return ipcRenderer.listenerCount(channel) - }, - ipcRendererRemoveAllListeners: (channel: string) => { - ipcRenderer.removeAllListeners(channel) - }, - showFilePath (file: File) { - return webUtils.getPathForFile(file) - } - }) - - contextBridge.exposeInMainWorld('node', { - path: { - join: path.join, - dirname: path.dirname, - basename: path.basename, - normalize: path.normalize, - extname: path.extname, - sep: path.sep, - posix: { - sep: path.posix.sep - } - }, - fs: { - remove: fs.remove, - readFile: fs.readFile, - statSync: fs.statSync - }, - crypto: { - randomBytes: crypto.randomBytes, - createHash: crypto.createHash - }, - yaml: { - load: yaml.load - }, - mime: { - lookup: mime.lookup - } - }) -} catch (error) { - console.error(error) -} +import crypto from 'node:crypto' +import path from 'node:path' + +import { clipboard, contextBridge, ipcRenderer, IpcRendererEvent, webFrame, webUtils } from 'electron' +import fs from 'fs-extra' +import yaml from 'js-yaml' +import mime from 'mime-types' +import { isReactive, isRef, toRaw, unref } from 'vue' + +export const getRawData = (args: any): any => { + if (isRef(args)) return unref(args) + if (isReactive(args)) return toRaw(args) + if (Array.isArray(args)) return args.map(getRawData) + if (typeof args === 'object' && args !== null) { + const data = {} as Record + for (const key in args) { + data[key] = getRawData(args[key]) + } + return data + } + return args +} + +function sendToMain(channel: string, ...args: any[]) { + ipcRenderer.send(channel, ...getRawData(args)) +} + +function sendRPC(action: string, ...args: any[]): void { + ipcRenderer.send('RPC_ACTIONS', action, getRawData(args)) +} + +async function triggerRPC(action: string, ...args: any[]): Promise { + return await ipcRenderer.invoke('RPC_ACTIONS_INVOKE', action, getRawData(args)) +} + +function sendRpcSync(action: string, ...args: any[]): any { + return ipcRenderer.sendSync('RPC_ACTIONS', action, getRawData(args)) +} + +try { + contextBridge.exposeInMainWorld('electron', { + setVisualZoomLevelLimits: (min: number, max: number) => { + webFrame.setVisualZoomLevelLimits(min, max) + }, + clipboard: { + writeText: clipboard.writeText + }, + platform: process.platform, + sendRpcSync, + triggerRPC, + sendToMain, + sendRPC, + ipcRendererOn: (channel: string, listener: (...args: any[]) => void) => { + const subscription = (_: IpcRendererEvent, ...args: any[]) => listener(...args) + ipcRenderer.on(channel, subscription) + return () => { + ipcRenderer.removeListener(channel, subscription) + } + }, + ipcRendererCountListeners: (channel: string): number => { + return ipcRenderer.listenerCount(channel) + }, + ipcRendererRemoveAllListeners: (channel: string) => { + ipcRenderer.removeAllListeners(channel) + }, + showFilePath(file: File) { + return webUtils.getPathForFile(file) + } + }) + + contextBridge.exposeInMainWorld('node', { + path: { + join: path.join, + dirname: path.dirname, + basename: path.basename, + normalize: path.normalize, + extname: path.extname, + sep: path.sep, + posix: { + sep: path.posix.sep + } + }, + fs: { + remove: fs.remove, + readFile: fs.readFile, + statSync: fs.statSync + }, + crypto: { + randomBytes: crypto.randomBytes, + createHash: crypto.createHash + }, + yaml: { + load: yaml.load + }, + mime: { + lookup: mime.lookup + } + }) +} catch (error) { + console.error(error) +} diff --git a/src/renderer/App.vue b/src/renderer/App.vue index addb0f68..58fb704c 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -1,60 +1,56 @@ - - - - - - - + + + + + + + diff --git a/src/renderer/apis/allApi.ts b/src/renderer/apis/allApi.ts index 8edd4b46..b3a21907 100644 --- a/src/renderer/apis/allApi.ts +++ b/src/renderer/apis/allApi.ts @@ -3,7 +3,7 @@ import { IRPCActionType } from '@/utils/enum' import type { IStringKeyMap } from '#/types/types' export default class ALLApi { - static async delete (configMap: IStringKeyMap): Promise { + static async delete(configMap: IStringKeyMap): Promise { return (await window.electron.triggerRPC(IRPCActionType.DELETE_ALL_API, getRawData(configMap))) || false } } diff --git a/src/renderer/components/ImageLocal.vue b/src/renderer/components/ImageLocal.vue index e48f0353..9132694c 100644 --- a/src/renderer/components/ImageLocal.vue +++ b/src/renderer/components/ImageLocal.vue @@ -1,115 +1,107 @@ - - - - - + + + + + diff --git a/src/renderer/components/ImagePreSign.vue b/src/renderer/components/ImagePreSign.vue index 6caeeb49..85c6f6a4 100644 --- a/src/renderer/components/ImagePreSign.vue +++ b/src/renderer/components/ImagePreSign.vue @@ -1,123 +1,123 @@ - - - - - + + + + + diff --git a/src/renderer/components/ImageProcessSetting.vue b/src/renderer/components/ImageProcessSetting.vue index 0a71b8ac..0785e72e 100644 --- a/src/renderer/components/ImageProcessSetting.vue +++ b/src/renderer/components/ImageProcessSetting.vue @@ -1,1291 +1,1150 @@ -