diff --git a/.prettierrc b/.prettierrc index feac0f72..e61a93a0 100644 --- a/.prettierrc +++ b/.prettierrc @@ -12,7 +12,7 @@ "semi": false, "singleQuote": true, "tabWidth": 2, - "trailingComma": "none", + "trailingComma": "all", "useTabs": false, "endOfLine": "lf" } diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 00000000..13c4ce4b --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,5 @@ +node_modules +public +dist +lib +*.d.ts \ No newline at end of file diff --git a/.stylelintrc.cjs b/.stylelintrc.cjs new file mode 100644 index 00000000..954bd9ff --- /dev/null +++ b/.stylelintrc.cjs @@ -0,0 +1,118 @@ +module.exports = { + extends: ['stylelint-config-standard', 'stylelint-config-html/vue', 'stylelint-config-standard-vue'], + plugins: ['stylelint-order'], + rules: { + // 这里是允许了空的style标签 + 'no-empty-source': null, + 'selector-class-pattern': null, + // 禁止空块 + 'block-no-empty': true, + // 颜色6位长度 + 'color-hex-length': 'long', + // 兼容自定义标签名 + 'selector-type-no-unknown': [ + true, + { + ignoreTypes: [], + }, + ], + // 忽略伪类选择器 ::v-deep + 'selector-pseudo-element-no-unknown': [ + true, + { + ignorePseudoElements: ['v-deep'], + }, + ], + // 禁止低优先级的选择器出现在高优先级的选择器之后。 + 'no-descending-specificity': null, + // 不验证@未知的名字,为了兼容scss的函数 + 'at-rule-no-unknown': null, + // 禁止空注释 + 'comment-no-empty': true, + // 禁止简写属性的冗余值 + 'shorthand-property-no-redundant-values': true, + // 禁止值的浏览器引擎前缀 + 'value-no-vendor-prefix': true, + // property-no-vendor-prefix + 'property-no-vendor-prefix': true, + // 属性的排序 + 'order/properties-order': [ + 'position', + 'top', + 'right', + 'bottom', + 'left', + 'z-index', + 'display', + 'justify-content', + 'align-items', + 'float', + 'clear', + 'overflow', + 'overflow-x', + 'overflow-y', + 'margin', + 'margin-top', + 'margin-right', + 'margin-bottom', + 'margin-left', + 'border', + 'border-style', + 'border-width', + 'border-color', + 'border-top', + 'border-top-style', + 'border-top-width', + 'border-top-color', + 'border-right', + 'border-right-style', + 'border-right-width', + 'border-right-color', + 'border-bottom', + 'border-bottom-style', + 'border-bottom-width', + 'border-bottom-color', + 'border-left', + 'border-left-style', + 'border-left-width', + 'border-left-color', + 'border-radius', + 'padding', + 'padding-top', + 'padding-right', + 'padding-bottom', + 'padding-left', + 'width', + 'min-width', + 'max-width', + 'height', + 'min-height', + 'max-height', + 'font-size', + 'font-family', + 'font-weight', + 'text-align', + 'text-justify', + 'text-indent', + 'text-overflow', + 'text-decoration', + 'white-space', + 'color', + 'background', + 'background-position', + 'background-repeat', + 'background-size', + 'background-color', + 'background-clip', + 'opacity', + 'filter', + 'list-style', + 'outline', + 'visibility', + 'box-shadow', + 'text-shadow', + 'resize', + 'transition', + ], + }, +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..7b0fd1d7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["dbaeumer.vscode-eslint", "stylelint.vscode-stylelint"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index ffabf983..0b6b9a64 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -36,4 +36,4 @@ } } ] -} \ No newline at end of file +} diff --git a/.vscode/mcp.json b/.vscode/mcp.json deleted file mode 100644 index 613b462b..00000000 --- a/.vscode/mcp.json +++ /dev/null @@ -1,15 +0,0 @@ -{ -"inputs": [ - // The "inputs" section defines the inputs required for the MCP server configuration. - { - "type": "promptString" - } -], -"servers": { - // The "servers" section defines the MCP servers you want to use. - "fetch": { - "command": "uvx", - "args": ["mcp-server-fetch"] - } - } -} diff --git a/.vscode/settings.json b/.vscode/settings.json index f11e2556..249ef0ec 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,26 +1,55 @@ { - "[stylus]": { - "editor.formatOnSave": true + "eslint.run": "onSave", + "eslint.codeActionsOnSave.mode": "all", + "eslint.format.enable": true, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always" + }, + "editor.formatOnSave": false + }, + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always" + }, + "editor.formatOnSave": false + }, + "[vue]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always" + }, + "editor.formatOnSave": false + }, + "[typescriptreact]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always" + }, + "editor.formatOnSave": false + }, + "[javascriptreact]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always" + }, + "editor.formatOnSave": false }, "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, - "githubPullRequests.ignoredPullRequestBranches": [ - "dev" - ], - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[html]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, "[css]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true + "editor.defaultFormatter": "stylelint.vscode-stylelint", + "editor.codeActionsOnSave": { + "source.fixAll.stylelint": "always" + }, + "editor.formatOnSave": false }, - "i18n-ally.localesPaths": ["src\\renderer\\i18n\\locales", "resources\\i18n"], + "eslint.validate": ["javascript", "javascriptreact", "vue", "typescript", "typescriptreact", "json", "jsonc"], + "githubPullRequests.ignoredPullRequestBranches": ["dev"], + "i18n-ally.localesPaths": ["src\\renderer\\i18n\\locales", "resources\\i18n"], "i18n-ally.keystyle": "nested", "i18n-ally.sortKeys": true, "i18n-ally.namespace": true, @@ -29,5 +58,8 @@ "i18n-ally.displayLanguage": "zh-CN", "i18n-ally.enabledFrameworks": ["vue"], "i18n-ally.editor.preferEditor": true, - "typescript.tsdk": "node_modules\\typescript\\lib" -} \ No newline at end of file + "typescript.tsdk": "node_modules\\typescript\\lib", + "css.validate": false, + "scss.validate": false, + "less.validate": false +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 206ff823..e110aa3d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -24,4 +24,4 @@ } } ] -} \ No newline at end of file +} diff --git a/electron.vite.config.js b/electron.vite.config.js index f1a2fbf9..b83d064f 100644 --- a/electron.vite.config.js +++ b/electron.vite.config.js @@ -15,9 +15,9 @@ export default defineConfig({ root: resolve('./'), '#': resolve('src/universal'), apis: resolve('src/main/apis'), - '@core': resolve('src/main/apis/core') - } - } + '@core': resolve('src/main/apis/core'), + }, + }, }, preload: { plugins: [ @@ -25,17 +25,17 @@ export default defineConfig({ VueI18nPlugin({ /* options */ // locale messages resource pre-compile option - include: resolve(dirname(fileURLToPath(import.meta.url)), './src/renderer/i18n/locales/**') - }) + include: resolve(dirname(fileURLToPath(import.meta.url)), './src/renderer/i18n/locales/**'), + }), ], resolve: { alias: { '@': resolve('src/renderer'), '~': resolve('src/main'), root: resolve('./'), - '#': resolve('src/universal') - } - } + '#': resolve('src/universal'), + }, + }, }, renderer: { root: resolve('src/renderer'), @@ -45,12 +45,12 @@ export default defineConfig({ '@': resolve('src/renderer'), '~': resolve('src/main'), root: resolve('./'), - '#': resolve('src/universal') - } + '#': resolve('src/universal'), + }, }, plugins: [vue()], server: { - port: 3000 - } - } + port: 3000, + }, + }, }) diff --git a/eslint.config.js b/eslint.config.js index 6e588d59..ce6fd1ac 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,49 +1,65 @@ -import eslint from '@eslint/js' -import standard from '@vue/eslint-config-standard' +import js from '@eslint/js' import { defineConfig } from 'eslint/config' -import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' +import configPrettier from 'eslint-config-prettier' +import jsonc from 'eslint-plugin-jsonc' +import pluginPrettier from 'eslint-plugin-prettier/recommended' import simpleImportSort from 'eslint-plugin-simple-import-sort' -import eslintPluginUnicorn from 'eslint-plugin-unicorn' +import pluginUnicorn from 'eslint-plugin-unicorn' import pluginVue from 'eslint-plugin-vue' import globals from 'globals' +import jsoncParser from 'jsonc-eslint-parser' import tseslint from 'typescript-eslint' +import vueParser from 'vue-eslint-parser' export default defineConfig( { - files: ['./src/*.{ts,tsx,cts,mts,js,cjs,mjs}', './scripts/*.{ts,js,mjs}', './test/*.{ts,js,mjs}'] + ignores: ['**/node_modules/**', '**/out/**', '**/webpack.config.js', 'vitest.workspace.mjs', '**/dist/**'], }, - { - ignores: ['**/node_modules/**', '**/out/**', '**/webpack.config.js', 'vitest.workspace.mjs', '**/dist/**'] - }, - eslint.configs.recommended, + js.configs.recommended, + ...pluginVue.configs['flat/recommended'], ...tseslint.configs.recommended, ...tseslint.configs.stylistic, - ...pluginVue.configs['flat/recommended'], - ...standard, - eslintPluginPrettierRecommended, { - plugins: { - 'simple-import-sort': simpleImportSort, - unicorn: eslintPluginUnicorn + files: ['**/*.ts', '**/*.d.ts'], + languageOptions: { + parser: tseslint.parser, + sourceType: 'module', + ecmaVersion: 'latest', + globals: { + ...globals.browser, + ...globals.node, + Office: 'readonly', + }, }, - rules: { - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error' - } }, { + files: ['**/*.vue'], languageOptions: { + parser: vueParser, parserOptions: { - warnOnUnsupportedTypeScriptVersion: false + parser: tseslint.parser, + extraFileExtensions: ['.vue'], + sourceType: 'module', + ecmaVersion: 'latest', }, globals: { + ...globals.browser, ...globals.node, - ...globals.browser - } - } + Office: 'readonly', + }, + }, }, { + files: ['**/*.ts', '**/*.d.ts', '**/*.vue', 'eslint.config.js', 'vite.config.js', 'electron.vite.config.js'], + plugins: { + 'simple-import-sort': simpleImportSort, + unicorn: pluginUnicorn, + }, rules: { + 'unicorn/prefer-node-protocol': 'error', + 'unicorn/prefer-module': 'error', + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', eqeqeq: 'error', 'no-caller': 'error', 'no-constant-condition': ['error', { checkLoops: false }], @@ -58,22 +74,18 @@ export default defineConfig( 'prefer-const': 'error', 'prefer-object-spread': 'error', 'unicode-bom': ['error', 'never'], - // Enabled in eslint:recommended, but not applicable here + 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-unused-vars': 'off', 'no-extra-boolean-cast': 'off', 'no-case-declarations': 'off', 'no-cond-assign': 'off', 'no-control-regex': 'off', 'no-inner-declarations': 'off', 'no-empty': 'off', - // @typescript-eslint/eslint-plugin - 'no-unused-expressions': 'off', '@typescript-eslint/no-unused-expressions': 'off', '@typescript-eslint/ban-ts-comment': 'off', - '@typescript-eslint/class-literal-property-style': 'off', - '@typescript-eslint/consistent-indexed-object-style': 'off', - '@typescript-eslint/consistent-generic-constructors': 'off', - '@typescript-eslint/no-duplicate-enum-values': 'off', '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-namespace': 'off', '@typescript-eslint/no-non-null-asserted-optional-chain': 'off', @@ -82,12 +94,51 @@ export default defineConfig( '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-empty-object-type': 'off', // {} is a totally useful and valid type. '@typescript-eslint/no-require-imports': 'off', - '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/no-this-alias': 'off', // Pending https://github.com/typescript-eslint/typescript-eslint/issues/4820 '@typescript-eslint/prefer-optional-chain': 'off', - 'unicorn/prefer-node-protocol': 'error' - } + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + }, + ], + 'vue/no-v-html': 'off', + 'vue/multi-word-component-names': 'off', + 'no-undef': 'off', // TypeScript handles this + 'no-async-promise-executor': 'off', + }, + }, + ...jsonc.configs['flat/recommended-with-jsonc'], + { + files: ['**/*.json', '**/*.jsonc', '**/*.json5'], + languageOptions: { + parser: jsoncParser, + }, + rules: { + 'jsonc/array-bracket-spacing': ['error', 'never'], + 'jsonc/comma-dangle': ['error', 'never'], + 'jsonc/indent': ['error', 2], + 'jsonc/no-comments': 'off', + 'jsonc/quotes': ['error', 'double'], + }, + }, + { + files: ['src/renderer/i18n/**/*.json'], + rules: { + 'jsonc/sort-keys': [ + 'error', + 'asc', // 升序排列 + { + caseSensitive: false, + natural: true, + }, + ], + }, }, { files: ['**/*.mjs', '**/*.mts'], @@ -99,19 +150,24 @@ export default defineConfig( { name: '__dirname' }, { name: 'require' }, { name: 'module' }, - { name: 'exports' } - ] - } + { name: 'exports' }, + ], + }, }, { - files: ['*.vue', '**/*.vue'], + files: ['*.config.js', '.stylelintrc.cjs', 'scripts/*.{js,mjs,cjs}'], languageOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - globals: globals.browser, - parserOptions: { - parser: tseslint.parser - } - } - } + globals: { + ...globals.node, + }, + }, + rules: { + // 在脚本文件中,通常允许使用 console 和 require + 'no-console': 'off', + '@typescript-eslint/no-require-imports': 'off', + '@typescript-eslint/no-var-requires': 'off', + }, + }, + configPrettier, + pluginPrettier, ) diff --git a/package.json b/package.json index 8e605bdc..3e9fd93d 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "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/ scripts/ .", + "lint:style": "stylelint \"src/**/*.(vue|less|scss|css)\" --fix", "postinstall": "electron-builder install-app-deps", "postuninstall": "electron-builder install-app-deps", "prebuild": "electron-vite build", @@ -76,28 +77,17 @@ "tunnel": "^0.0.6", "upyun": "^3.4.6", "uuid": "^11.1.0", + "vue": "^3.5.22", "webdav": "^5.8.0", - "write-file-atomic": "^6.0.0", - "vue": "^3.5.22" + "write-file-atomic": "^6.0.0" }, "devDependencies": { + "@electron/notarize": "^3.1.1", + "@eslint/js": "^9.39.2", "@headlessui/vue": "^1.7.23", "@highlightjs/vue-plugin": "^2.1.2", - "@videojs-player/vue": "^1.0.0", - "dexie": "^3.2.4", - "highlight.js": "^11.11.1", - "lucide-vue-next": "^0.553.0", - "pinia": "^3.0.4", - "pinia-plugin-persistedstate": "^4.7.1", - "qrcode.vue": "^3.6.0", - "video.js": "^8.23.4", - "vue-i18n": "^11.1.12", - "vue-router": "^4.6.3", - "vue3-lazyload": "^0.3.8", - "@electron/notarize": "^3.1.1", - "@eslint/js": "^9.39.1", - "@intlify/unplugin-vue-i18n": "^11.0.1", - "@types/ali-oss": "^6.16.11", + "@intlify/unplugin-vue-i18n": "^11.0.3", + "@types/ali-oss": "^6.16.13", "@types/fs-extra": "^11.0.4", "@types/js-yaml": "^4.0.9", "@types/lodash-es": "^4.17.12", @@ -108,30 +98,52 @@ "@types/upyun": "^3.4.3", "@types/video.js": "^7.3.58", "@types/write-file-atomic": "^4.0.3", - "@vitejs/plugin-vue": "^6.0.1", - "@vue/eslint-config-standard": "^9.0.1", + "@videojs-player/vue": "^1.0.0", + "@vitejs/plugin-vue": "^6.0.3", + "baseline-browser-mapping": "^2.9.11", + "dexie": "^3.2.4", "dotenv": "^17.2.3", "dpdm": "^3.14.0", "electron": "^38.4.0", "electron-builder": "^26.0.12", "electron-vite": "^4.0.1", - "eslint": "^9.39.1", + "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", + "eslint-plugin-jsonc": "^2.21.0", "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unicorn": "^62.0.0", - "eslint-plugin-vue": "^10.5.1", + "eslint-plugin-vue": "^10.6.2", "globals": "^16.5.0", + "highlight.js": "^11.11.1", "husky": "^9.1.7", + "lucide-vue-next": "^0.562.0", "node-bump-version": "^2.0.0", - "prettier": "^3.6.2", + "pinia": "^3.0.4", + "pinia-plugin-persistedstate": "^4.7.1", + "postcss": "^8.5.6", + "postcss-html": "^1.8.0", + "prettier": "^3.7.4", + "qrcode.vue": "^3.6.0", + "stylelint": "^16.26.1", + "stylelint-config-html": "^1.1.0", + "stylelint-config-standard": "^39.0.1", + "stylelint-config-standard-vue": "^1.0.0", + "stylelint-order": "^7.0.1", "stylus": "^0.64.0", "typescript": "5.8.2", - "typescript-eslint": "^8.46.4", - "vite": "^7.2.2", - "vitest": "^4.0.8", + "typescript-eslint": "^8.51.0", + "video.js": "^8.23.4", + "vite": "^7.3.0", + "vitest": "^4.0.16", "vue-eslint-parser": "^10.2.0", - "vue-tsc": "^3.1.3" + "vue-i18n": "^11.2.7", + "vue-router": "^4.6.4", + "vue-tsc": "^3.2.1", + "vue3-lazyload": "^0.3.8" + }, + "resolutions": { + "baseline-browser-mapping": "^2.9.11" }, "config": { "commitizen": { diff --git a/scripts/config.js b/scripts/config.js index 282c7755..ed7c50ab 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -6,14 +6,14 @@ const darwin = [ appNameWithPrefix: 'PicList-', ext: '.dmg', arch: '-arm64', - 'version-file': 'latest-mac.yml' + 'version-file': 'latest-mac.yml', }, { appNameWithPrefix: 'PicList-', ext: '.dmg', arch: '-x64', - 'version-file': 'latest-mac.yml' - } + 'version-file': 'latest-mac.yml', + }, ] const linux = [ @@ -21,14 +21,14 @@ const linux = [ appNameWithPrefix: 'PicList-', ext: '.AppImage', arch: '', - 'version-file': 'latest-linux.yml' + 'version-file': 'latest-linux.yml', }, { appNameWithPrefix: 'piclist_', ext: '.snap', arch: '_amd64', - 'version-file': 'latest-linux.yml' - } + 'version-file': 'latest-linux.yml', + }, ] // windows @@ -37,30 +37,30 @@ const win32 = [ appNameWithPrefix: 'PicList-Setup-', ext: '.exe', arch: '-ia32', - 'version-file': 'latest.yml' + 'version-file': 'latest.yml', }, { appNameWithPrefix: 'PicList-Setup-', ext: '.exe', arch: '-x64', - 'version-file': 'latest.yml' + 'version-file': 'latest.yml', }, { appNameWithPrefix: 'PicList-Setup-', ext: '.exe', arch: '', // 32 & 64 - 'version-file': 'latest.yml' + 'version-file': 'latest.yml', }, { appNameWithPrefix: 'PicList-Setup-', ext: '.exe', arch: '-arm64', - 'version-file': 'latest.yml' - } + 'version-file': 'latest.yml', + }, ] export default { darwin, linux, - win32 + win32, } diff --git a/scripts/gen-sha256.js b/scripts/gen-sha256.js index 35478a93..05fd1a34 100644 --- a/scripts/gen-sha256.js +++ b/scripts/gen-sha256.js @@ -15,12 +15,12 @@ const DOWNLOAD_DIR = process.argv[3] || path.join(os.homedir(), 'Downloads') const files = [ { name: 'PicList-x64.dmg', - url: `${BASE_URL}/PicList-${version}-x64.dmg` + url: `${BASE_URL}/PicList-${version}-x64.dmg`, }, { name: 'PicList-arm64.dmg', - url: `${BASE_URL}/PicList-${version}-arm64.dmg` - } + url: `${BASE_URL}/PicList-${version}-arm64.dmg`, + }, ] /** @@ -57,7 +57,7 @@ async function downloadAndHash(fileInfo) { const response = await axios({ method: 'get', url, - responseType: 'stream' + responseType: 'stream', }) const writer = fs.createWriteStream(filePath) diff --git a/scripts/notarize.cjs b/scripts/notarize.cjs index 3435af2a..1788d17a 100644 --- a/scripts/notarize.cjs +++ b/scripts/notarize.cjs @@ -27,7 +27,7 @@ async function main(context) { appleId: XCODE_APP_LOADER_EMAIL, appleIdPassword: XCODE_APP_LOADER_PASSWORD, tool: 'notarytool', - teamId: XCODE_TEAM_ID + teamId: XCODE_TEAM_ID, }) console.log('Finished Apple notarization.') } diff --git a/scripts/upload-beta.cjs b/scripts/upload-beta.cjs index 2185eef3..dc1418b1 100644 --- a/scripts/upload-beta.cjs +++ b/scripts/upload-beta.cjs @@ -26,11 +26,11 @@ const uploadFile = async () => { const options = { credentials: { accessKeyId: SECRET_ID, - secretAccessKey: SECRET_KEY + secretAccessKey: SECRET_KEY, }, endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`, tls: true, - region: 'auto' + region: 'auto', } const client = new S3Client.S3Client(options) const parallelUploads3 = new Upload.Upload({ @@ -41,9 +41,9 @@ const uploadFile = async () => { Body: fileStream, ContentType: 'application/octet-stream', Metadata: { - description: 'uploaded by PicList' - } - } + description: 'uploaded by PicList', + }, + }, }) parallelUploads3.on('httpUploadProgress', progress => { const progressBar = Math.round((progress.loaded / progress.total) * 100) diff --git a/scripts/upload-dist-to-r2.cjs b/scripts/upload-dist-to-r2.cjs index 62515e49..5981f62e 100644 --- a/scripts/upload-dist-to-r2.cjs +++ b/scripts/upload-dist-to-r2.cjs @@ -20,11 +20,11 @@ const SECRET_KEY = process.env.R2_SECRET_KEY const options = { credentials: { accessKeyId: SECRET_ID, - secretAccessKey: SECRET_KEY + secretAccessKey: SECRET_KEY, }, endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`, tls: true, - region: 'auto' + region: 'auto', } const removeDupField = path => { @@ -65,9 +65,9 @@ const uploadFile = async () => { Body: fileStream, ContentType: 'application/octet-stream', Metadata: { - description: 'uploaded by PicList' - } - } + description: 'uploaded by PicList', + }, + }, }) parallelUploads3.on('httpUploadProgress', progress => { const progressBar = Math.round((progress.loaded / progress.total) * 100) @@ -97,9 +97,9 @@ const uploadFile = async () => { Body: versionFileStream, ContentType: mime.getType(versionFileName), Metadata: { - description: 'uploaded by PicList' - } - } + description: 'uploaded by PicList', + }, + }, }) console.log('\nUploading version file to root...') await uploadVersionFileToRoot.done() @@ -114,9 +114,9 @@ const uploadFile = async () => { Body: versionFileStream2, ContentType: mime.getType(versionFileName), Metadata: { - description: 'uploaded by PicList' - } - } + description: 'uploaded by PicList', + }, + }, }) console.log('\nUploading version file to latest...') await uploadVersionFileToLatest.done() diff --git a/src/main/apis/app/remoteNotice/index.ts b/src/main/apis/app/remoteNotice/index.ts index 9ef9840d..303d86a9 100644 --- a/src/main/apis/app/remoteNotice/index.ts +++ b/src/main/apis/app/remoteNotice/index.ts @@ -36,10 +36,10 @@ class RemoteNoticeHandler { try { const localCountStorage: IRemoteNoticeLocalCountStorage = fs.readJSONSync( REMOTE_NOTICE_LOCAL_STORAGE_PATH, - 'utf8' + 'utf8', ) this.remoteNoticeLocalCountStorage = localCountStorage - } catch (e) { + } catch (_e) { this.remoteNoticeLocalCountStorage = localCountStorage } } @@ -56,7 +56,7 @@ class RemoteNoticeHandler { const noticeInfo = (await axios({ method: 'get', url: REMOTE_NOTICE_URL, - responseType: 'json' + responseType: 'json', }).then(res => res.data)) as IRemoteNotice return noticeInfo } catch { @@ -121,7 +121,7 @@ class RemoteNoticeHandler { if (action.data?.url) { shell.openExternal(action.data.url) } - } + }, }) break case IRemoteNoticeActionType.OPEN_URL: @@ -144,7 +144,7 @@ class RemoteNoticeHandler { title: action.data?.title || '', message: action.data?.content || '', type: 'info', - buttons: action.data?.buttons?.map(item => item.label) || ['Yes'] + buttons: action.data?.buttons?.map(item => item.label) || ['Yes'], }) .then(res => { const button = action.data?.buttons?.[res.response] diff --git a/src/main/apis/app/shortKey/shortKeyHandler.ts b/src/main/apis/app/shortKey/shortKeyHandler.ts index e559dc9b..c59bf851 100644 --- a/src/main/apis/app/shortKey/shortKeyHandler.ts +++ b/src/main/apis/app/shortKey/shortKeyHandler.ts @@ -11,7 +11,7 @@ import type { IPluginShortKeyConfig, IShortKeyConfig, IShortKeyConfigs, - IShortKeyHandler + IShortKeyHandler, } from '#/types/types' import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant' import { configPaths } from '~/utils/configPaths' @@ -78,7 +78,7 @@ class ShortKeyHandler { config: IShortKeyConfig | IPluginShortKeyConfig, command: string, handler: IShortKeyHandler, - writeFlag: boolean + writeFlag: boolean, ) { shortKeyService.registerCommand(command, handler) if (config.key) { @@ -96,8 +96,8 @@ class ShortKeyHandler { enable: true, name: config.name, label: config.label, - key: config.key - } + key: config.key, + }, }) } } @@ -108,7 +108,7 @@ class ShortKeyHandler { if (item.enable === false) { globalShortcut.unregister(item.key) picgo.saveConfig({ - [`settings.shortKey.${command}.enable`]: false + [`settings.shortKey.${command}.enable`]: false, }) return true } else { @@ -116,7 +116,7 @@ class ShortKeyHandler { return false } else { picgo.saveConfig({ - [`settings.shortKey.${command}.enable`]: true + [`settings.shortKey.${command}.enable`]: true, }) globalShortcut.register(item.key, () => { this.handler(command) @@ -132,7 +132,7 @@ class ShortKeyHandler { if (globalShortcut.isRegistered(item.key)) return false globalShortcut.unregister(oldKey) picgo.saveConfig({ - [`settings.shortKey.${command}.key`]: item.key + [`settings.shortKey.${command}.key`]: item.key, }) globalShortcut.register(item.key, () => { this.handler(`${from}:${item.name}`) @@ -183,7 +183,7 @@ class ShortKeyHandler { .map(command => { return { command, - key: commands[command].key + key: commands[command].key, } }) as IKeyCommandType[] keyList.forEach(item => { diff --git a/src/main/apis/app/shortKey/shortKeyService.ts b/src/main/apis/app/shortKey/shortKeyService.ts index 8ac97329..ab950d90 100644 --- a/src/main/apis/app/shortKey/shortKeyService.ts +++ b/src/main/apis/app/shortKey/shortKeyService.ts @@ -3,7 +3,7 @@ import logger from '@core/picgo/logger' import type { IShortKeyHandler } from '#/types/types' class ShortKeyService { - private commandList: Map = new Map() + private commandList = new Map() registerCommand(command: string, handler: IShortKeyHandler) { this.commandList.set(command, handler) } diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts index 19390018..c2eacc70 100644 --- a/src/main/apis/app/system/index.ts +++ b/src/main/apis/app/system/index.ts @@ -12,7 +12,7 @@ import { MenuItemConstructorOptions, nativeTheme, Notification, - Tray + Tray, } from 'electron' import fs from 'fs-extra' import { cloneDeep } from 'lodash-es' @@ -41,7 +41,7 @@ export function setDockMenu() { const dockMenu = Menu.buildFromTemplate([ { label: $t('OPEN_MAIN_WINDOW'), - click: openMainWindow + click: openMainWindow, }, { label: $t('START_WATCH_CLIPBOARD'), @@ -54,7 +54,7 @@ export function setDockMenu() { }) setDockMenu() }, - visible: !isListeningClipboard + visible: !isListeningClipboard, }, { label: $t('STOP_WATCH_CLIPBOARD'), @@ -64,8 +64,8 @@ export function setDockMenu() { clipboardPoll.removeAllListeners() setDockMenu() }, - visible: isListeningClipboard - } + visible: isListeningClipboard, + }, ]) app.dock?.setMenu(dockMenu) } @@ -82,9 +82,9 @@ export function createMenu() { click() { app.relaunch() app.exit(0) - } - } - ] + }, + }, + ], }, { label: $t('CHOOSE_DEFAULT_PICBED'), type: 'submenu', submenu }, { @@ -96,13 +96,13 @@ export function createMenu() { { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' }, { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' }, { label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' }, - { label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' } - ] + { label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' }, + ], }, { label: $t('QUIT'), - submenu: [{ label: $t('QUIT'), role: 'quit' }] - } + submenu: [{ label: $t('QUIT'), role: 'quit' }], + }, ]) Menu.setApplicationMenu(appMenu) } @@ -138,21 +138,21 @@ export function createContextMenu() { { label: $t('START_WATCH_CLIPBOARD'), click: startWatchClipboard, - visible: !isListeningClipboard + visible: !isListeningClipboard, }, { label: $t('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, - visible: isListeningClipboard + visible: isListeningClipboard, }, { label: $t('RELOAD_APP'), click() { app.relaunch() app.exit(0) - } + }, }, - { label: $t('QUIT'), role: 'quit' } + { label: $t('QUIT'), role: 'quit' }, ] if (process.platform === 'win32') { template.splice( @@ -163,13 +163,13 @@ export function createContextMenu() { click() { openMiniWindow(false) }, - visible: !isMiniWindowVisible + visible: !isMiniWindowVisible, }, { label: $t('HIDE_MINI_WINDOW'), click: hideMiniWindow, - visible: isMiniWindowVisible - } + visible: isMiniWindowVisible, + }, ) } contextMenu = Menu.buildFromTemplate(template) @@ -188,22 +188,22 @@ export function createContextMenu() { click() { openMiniWindow(false) }, - visible: !isMiniWindowVisible + visible: !isMiniWindowVisible, }, { label: $t('HIDE_MINI_WINDOW'), click: hideMiniWindow, - visible: isMiniWindowVisible + visible: isMiniWindowVisible, }, { label: $t('START_WATCH_CLIPBOARD'), click: startWatchClipboard, - visible: !isListeningClipboard + visible: !isListeningClipboard, }, { label: $t('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, - visible: isListeningClipboard + visible: isListeningClipboard, }, { label: $t('ABOUT'), @@ -212,11 +212,11 @@ export function createContextMenu() { title: 'PicList', message: 'PicList', buttons: ['Ok'], - detail: `Version: ${pkg.version}\nAuthor: Kuingsmile\nGithub: https://github.com/Kuingsmile/PicList` + detail: `Version: ${pkg.version}\nAuthor: Kuingsmile\nGithub: https://github.com/Kuingsmile/PicList`, }) - } + }, }, - { label: $t('QUIT'), role: 'quit' } + { label: $t('QUIT'), role: 'quit' }, ]) } } @@ -258,14 +258,14 @@ export function createTray(tooltip: string) { const decodePath = ensureFilePath(imgPath) if (decodePath === imgPath) { obj.push({ - imgUrl: imgPath + imgUrl: imgPath, }) } else { if (decodePath !== '') { // 带有中文的路径,无法直接被img.src所使用,会被转义 const base64 = await fs.readFile(decodePath.replace('file://', ''), { encoding: 'base64' }) obj.push({ - imgUrl: `data:image/png;base64,${base64}` + imgUrl: `data:image/png;base64,${base64}`, }) } } @@ -274,7 +274,7 @@ export function createTray(tooltip: string) { obj.push({ width: img.getSize().width, height: img.getSize().height, - imgUrl + imgUrl, }) } } @@ -333,7 +333,7 @@ export function createTray(tooltip: string) { const [pasteTextItem, shortUrl] = await pasteTemplate( pasteStyle, imgs[i], - db.get(configPaths.settings.customLink) + db.get(configPaths.settings.customLink), ) imgs[i].shortUrl = shortUrl pasteText.push(pasteTextItem) @@ -344,7 +344,7 @@ export function createTray(tooltip: string) { if (isShowResultNotification) { const notification = new Notification({ title: $t('UPLOAD_SUCCEED'), - body: shortUrl || imgs[i].imgUrl! + body: shortUrl || imgs[i].imgUrl!, // icon: files[i] }) setTimeout(() => { diff --git a/src/main/apis/app/uploader/apis.ts b/src/main/apis/app/uploader/apis.ts index 34cd74a2..36fe7295 100644 --- a/src/main/apis/app/uploader/apis.ts +++ b/src/main/apis/app/uploader/apis.ts @@ -62,7 +62,7 @@ export const uploadClipboardFiles = async (): Promise => { if (isShowResultNotification) { const notification = new Notification({ title: $t('UPLOAD_SUCCEED'), - body: shortUrl || img[0].imgUrl! + body: shortUrl || img[0].imgUrl!, // icon: img[0].imgUrl }) setTimeout(() => { @@ -78,30 +78,30 @@ export const uploadClipboardFiles = async (): Promise => { } return { url: handleUrlEncodeWithSetting(inserted.imgUrl as string), - fullResult: inserted + fullResult: inserted, } } else { const notification = new Notification({ title: $t('UPLOAD_FAILED'), - body: $t('TIPS_UPLOAD_NOT_PICTURES') + body: $t('TIPS_UPLOAD_NOT_PICTURES'), }) notification.show() return { url: '', - fullResult: {} + fullResult: {}, } } } else { return { url: '', - fullResult: {} + fullResult: {}, } } } export const uploadChoosedFiles = async ( webContents: WebContents, - files: IFileWithPath[] + files: IFileWithPath[], ): Promise => { const input = files.map(item => item.path) const rawInput = cloneDeep(input) @@ -132,7 +132,7 @@ export const uploadChoosedFiles = async ( const [pasteTextItem, shortUrl] = await pasteTemplate( pasteStyle, imgs[i], - db.get(configPaths.settings.customLink) + db.get(configPaths.settings.customLink), ) imgs[i].shortUrl = shortUrl pasteText.push(pasteTextItem) @@ -144,7 +144,7 @@ export const uploadChoosedFiles = async ( if (imgLength <= 3) { const notification = new Notification({ title: $t('UPLOAD_SUCCEED'), - body: shortUrl || imgs[i].imgUrl! + body: shortUrl || imgs[i].imgUrl!, // icon: files[i].path }) setTimeout(() => { @@ -153,7 +153,7 @@ export const uploadChoosedFiles = async ( } else if (i === imgLength - 1) { const notification = new Notification({ title: $t('MULTI_UPLOAD_SUCCEED', { n: imgLength }), - body: '' + body: '', }) setTimeout(() => { notification.show() @@ -163,7 +163,7 @@ export const uploadChoosedFiles = async ( const inserted = await GalleryDB.getInstance().insert(imgs[i]) result.push({ url: handleUrlEncodeWithSetting(inserted.imgUrl!), - fullResult: inserted + fullResult: inserted, }) } handleCopyUrl(pasteText.join('\n')) @@ -181,7 +181,7 @@ export const uploadChoosedFiles = async ( export const handleSecondaryUpload = async ( webContents?: WebContents, input?: string[], - uploadType: 'clipboard' | 'file' | 'tray' = 'file' + uploadType: 'clipboard' | 'file' | 'tray' = 'file', ): Promise<{ needRestore: boolean; ctx: IPicGo | false }> => { const enableSecondUploader = db.get(configPaths.settings.enableSecondUploader) || false let currentPicBedType = '' @@ -242,6 +242,6 @@ export const handleSecondaryUpload = async ( } return { needRestore, - ctx + ctx, } } diff --git a/src/main/apis/app/uploader/index.ts b/src/main/apis/app/uploader/index.ts index d75d147a..50d87972 100644 --- a/src/main/apis/app/uploader/index.ts +++ b/src/main/apis/app/uploader/index.ts @@ -53,7 +53,7 @@ class Uploader { if (db.get(configPaths.settings.uploadNotification)) { const notification = new Notification({ title: $t('UPLOAD_PROGRESS'), - body: $t('UPLOADING') + body: $t('UPLOADING'), }) notification.show() } @@ -85,10 +85,10 @@ class Uploader { name = await waitForRename(window, window.webContents.id) } item.fileName = name || fileName - }) + }), ) } - } + }, }) } @@ -163,7 +163,7 @@ class Uploader { showNotification({ title: $t('UPLOAD_FAILED'), body: util.format(e.stack), - clickToCopy: true + clickToCopy: true, }) }, 500) return false @@ -186,7 +186,7 @@ class Uploader { showNotification({ title: $t('UPLOAD_FAILED'), body: util.format(e.stack), - clickToCopy: true + clickToCopy: true, }) }, 500) return false diff --git a/src/main/apis/app/window/windowList.ts b/src/main/apis/app/window/windowList.ts index bb8ad7fb..e2c7c55f 100644 --- a/src/main/apis/app/window/windowList.ts +++ b/src/main/apis/app/window/windowList.ts @@ -20,11 +20,11 @@ const windowList = new Map() const getDefaultWindowSizes = (): { width: number; height: number } => { const [mainWindowWidth, mainWindowHeight] = db.get([ configPaths.settings.mainWindowWidth, - configPaths.settings.mainWindowHeight + configPaths.settings.mainWindowHeight, ]) return { width: mainWindowWidth || 1200, - height: mainWindowHeight || 800 + height: mainWindowHeight || 800, } } @@ -64,8 +64,8 @@ const trayWindowOptions = { contextIsolation: true, nodeIntegrationInWorker: false, backgroundThrottling: true, - webSecurity: false - } + webSecurity: false, + }, } const settingWindowOptions = { @@ -88,8 +88,8 @@ const settingWindowOptions = { nodeIntegration: false, contextIsolation: true, nodeIntegrationInWorker: false, - webSecurity: false - } + webSecurity: false, + }, } as IBrowserWindowOptions if (process.platform !== 'darwin') { @@ -113,8 +113,8 @@ const miniWindowOptions = { nodeIntegration: false, contextIsolation: true, backgroundThrottling: true, - nodeIntegrationInWorker: false - } + nodeIntegrationInWorker: false, + }, } as IBrowserWindowOptions if (db.get(configPaths.settings.miniWindowOntop)) { @@ -134,8 +134,8 @@ const renameWindowOptions = { nodeIntegration: false, contextIsolation: true, nodeIntegrationInWorker: false, - backgroundThrottling: false - } + backgroundThrottling: false, + }, } as IBrowserWindowOptions if (process.platform !== 'darwin') { @@ -163,8 +163,8 @@ const toolboxWindowOptions = { nodeIntegration: false, contextIsolation: true, nodeIntegrationInWorker: false, - webSecurity: false - } + webSecurity: false, + }, } as IBrowserWindowOptions if (process.platform !== 'darwin') { @@ -186,7 +186,7 @@ windowList.set(IWindowList.TRAY_WINDOW, { window.on('blur', () => { window.hide() }) - } + }, }) windowList.set(IWindowList.SETTING_WINDOW, { @@ -198,7 +198,7 @@ windowList.set(IWindowList.SETTING_WINDOW, { window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`) } else { window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'main-page/upload' + hash: 'main-page/upload', }) } window.on('closed', () => { @@ -211,7 +211,7 @@ windowList.set(IWindowList.SETTING_WINDOW, { }) bus.emit(CREATE_APP_MENU) windowManager.create(IWindowList.MINI_WINDOW) - } + }, }) windowList.set(IWindowList.MINI_WINDOW, { @@ -223,10 +223,10 @@ windowList.set(IWindowList.MINI_WINDOW, { window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`) } else { window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'mini-page' + hash: 'mini-page', }) } - } + }, }) windowList.set(IWindowList.RENAME_WINDOW, { @@ -238,7 +238,7 @@ windowList.set(IWindowList.RENAME_WINDOW, { window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`) } else { window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'rename-page' + hash: 'rename-page', }) } const currentWindow = windowManager.getAvailableWindow(true) @@ -248,7 +248,7 @@ windowList.set(IWindowList.RENAME_WINDOW, { const positionY = Math.floor(y + height / 2 - (height > 400 ? 88 : 0)) window.setPosition(positionX, positionY, false) } - } + }, }) windowList.set(IWindowList.TOOLBOX_WINDOW, { @@ -260,7 +260,7 @@ windowList.set(IWindowList.TOOLBOX_WINDOW, { window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`) } else { window.loadFile(path.join(__dirname, '../renderer/index.html'), { - hash: 'toolbox-page' + hash: 'toolbox-page', }) } const currentWindow = windowManager.getAvailableWindow(true) @@ -270,7 +270,7 @@ windowList.set(IWindowList.TOOLBOX_WINDOW, { 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 b43d9331..2e2d437b 100644 --- a/src/main/apis/app/window/windowManager.ts +++ b/src/main/apis/app/window/windowManager.ts @@ -5,8 +5,8 @@ import type { IWindowListItem, IWindowManager } from '#/types/electron' import { IWindowList } from '~/utils/enum' class WindowManager implements IWindowManager { - #windowMap: Map = new Map() - #windowIdMap: Map = new Map() + #windowMap = new Map() + #windowIdMap = new Map() create(name: string) { const windowConfig: IWindowListItem = windowList.get(name)! diff --git a/src/main/apis/core/bus/apis.ts b/src/main/apis/core/bus/apis.ts index 8a308913..33bf3996 100644 --- a/src/main/apis/core/bus/apis.ts +++ b/src/main/apis/core/bus/apis.ts @@ -6,7 +6,7 @@ import { UPLOAD_WITH_CLIPBOARD_FILES, UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, UPLOAD_WITH_FILES, - UPLOAD_WITH_FILES_RESPONSE + UPLOAD_WITH_FILES_RESPONSE, } from '@core/bus/constants' import bus from '@core/bus/index' @@ -21,11 +21,11 @@ export const uploadWithClipboardFiles = (): Promise<{ if (result) { return resolve({ success: true, - result: [result] + result: [result], }) } else { return resolve({ - success: false + success: false, }) } }) @@ -34,7 +34,7 @@ export const uploadWithClipboardFiles = (): Promise<{ } export const uploadWithFiles = ( - pathList: IFileWithPath[] + pathList: IFileWithPath[], ): Promise<{ success: boolean result?: string[] @@ -44,11 +44,11 @@ export const uploadWithFiles = ( if (result.length) { return resolve({ success: true, - result + result, }) } else { return resolve({ - success: false + success: false, }) } }) diff --git a/src/main/apis/core/datastore/dbChecker.ts b/src/main/apis/core/datastore/dbChecker.ts index 8e60a850..c65d46fc 100644 --- a/src/main/apis/core/datastore/dbChecker.ts +++ b/src/main/apis/core/datastore/dbChecker.ts @@ -20,7 +20,7 @@ let hasCheckPath = false const errorMsg = { broken: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT'), - brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP') + brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP'), } function dbChecker() { @@ -42,28 +42,28 @@ function dbChecker() { let configFile: string = '{}' const optionsTpl = { title: $t('TIPS_NOTICE'), - body: '' + body: '', } // config save bak try { configFile = fs.readFileSync(configFilePath, { encoding: 'utf-8' }) JSON.parse(configFile) - } catch (e) { + } catch (_e) { fs.unlinkSync(configFilePath) if (fs.existsSync(configFileBackupPath)) { try { configFile = fs.readFileSync(configFileBackupPath, { - encoding: 'utf-8' + encoding: 'utf-8', }) JSON.parse(configFile) writeFile.sync(configFilePath, configFile, { encoding: 'utf-8' }) const stats = fs.statSync(configFileBackupPath) optionsTpl.body = `${errorMsg.brokenButBackup}\n${$t('TIPS_PICGO_BACKUP_FILE_VERSION', { - v: dayjs(stats.mtime).format('YYYY-MM-DD HH:mm:ss') + v: dayjs(stats.mtime).format('YYYY-MM-DD HH:mm:ss'), })}` notificationList.push(optionsTpl) return - } catch (e) { + } catch (_e) { optionsTpl.body = errorMsg.broken notificationList.push(optionsTpl) return @@ -92,7 +92,7 @@ function dbPathChecker(): string { } try { const configString = fs.readFileSync(defaultConfigPath, { - encoding: 'utf-8' + encoding: 'utf-8', }) const config = JSON.parse(configString) const userConfigPath: string = config.configPath || '' @@ -109,7 +109,7 @@ function dbPathChecker(): string { if (!hasCheckPath) { const optionsTpl = { title: $t('TIPS_NOTICE'), - body: $t('TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR') + body: $t('TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR'), } notificationList.push(optionsTpl) hasCheckPath = true @@ -133,7 +133,7 @@ function getGalleryDBPath(): { const dbBackupPath = path.join(path.dirname(dbPath), 'piclist.bak.db') return { dbPath, - dbBackupPath + dbBackupPath, } } diff --git a/src/main/apis/core/datastore/index.ts b/src/main/apis/core/datastore/index.ts index 283a7635..1638c23e 100644 --- a/src/main/apis/core/datastore/index.ts +++ b/src/main/apis/core/datastore/index.ts @@ -27,8 +27,8 @@ class ConfigStore { current: 'smms', // deprecated uploader: 'smms', smms: { - token: '' - } + token: '', + }, }) } @@ -37,7 +37,7 @@ class ConfigStore { enable: true, key: 'CommandOrControl+Alt+P', name: 'upload', - label: $t('QUICK_UPLOAD') + label: $t('QUICK_UPLOAD'), }) } this.read() diff --git a/src/main/apis/core/picgo/index.ts b/src/main/apis/core/picgo/index.ts index 0e0e0e52..98c1e1c4 100644 --- a/src/main/apis/core/picgo/index.ts +++ b/src/main/apis/core/picgo/index.ts @@ -14,7 +14,7 @@ const picgo = await PicGo.create(CONFIG_PATH) picgo.saveConfig({ debug: true, - PICGO_ENV: 'GUI' + PICGO_ENV: 'GUI', }) picgo.GUI_VERSION = pkg.version diff --git a/src/main/apis/core/utils/localLogger.ts b/src/main/apis/core/utils/localLogger.ts index fbea8133..28b8b0bc 100644 --- a/src/main/apis/core/utils/localLogger.ts +++ b/src/main/apis/core/utils/localLogger.ts @@ -21,7 +21,7 @@ const checkLogFileIsLarge = (logPath: string): CheckLogFileResult => { return { isLarge: logFileSize > DEFAULT_LOG_FILE_SIZE_LIMIT, logFileSize, - logFileSizeLimit: DEFAULT_LOG_FILE_SIZE_LIMIT + logFileSizeLimit: DEFAULT_LOG_FILE_SIZE_LIMIT, } } return { isLarge: false } diff --git a/src/main/apis/delete/alist.ts b/src/main/apis/delete/alist.ts index 05ca4c6e..2596760c 100644 --- a/src/main/apis/delete/alist.ts +++ b/src/main/apis/delete/alist.ts @@ -26,12 +26,12 @@ export default class AlistApi { url: `${url}/api/fs/remove`, headers: { 'Content-Type': 'application/json', - Authorization: token + Authorization: token, }, data: { dir: path.join('/', uploadPath, path.dirname(fileName)), - names: [path.basename(fileName)] - } + names: [path.basename(fileName)], + }, }) const ok = result.data.code === 200 deleteLog(fileName, 'Alist', ok) diff --git a/src/main/apis/delete/alistplist.ts b/src/main/apis/delete/alistplist.ts index 605deacd..11406fba 100644 --- a/src/main/apis/delete/alistplist.ts +++ b/src/main/apis/delete/alistplist.ts @@ -18,7 +18,7 @@ interface IConfigMap { const getAListToken = async (url: string, username: string, password: string) => { const res = await axios.post(`${url}/api/auth/login`, { username, - password + password, }) if (res.data.code === 200 && res.data.message === 'success') { return res.data.data.token @@ -43,12 +43,12 @@ export default class AListplistApi { url: `${url}/api/fs/remove`, headers: { 'Content-Type': 'application/json', - Authorization: token + Authorization: token, }, data: { dir: path.join('/', uploadPath, path.dirname(fileName)), - names: [path.basename(fileName)] - } + names: [path.basename(fileName)], + }, }) const ok = result.data.code === 200 deleteLog(fileName, 'Alist', ok) diff --git a/src/main/apis/delete/allApi.ts b/src/main/apis/delete/allApi.ts index 238c72f6..af5ddb77 100644 --- a/src/main/apis/delete/allApi.ts +++ b/src/main/apis/delete/allApi.ts @@ -35,7 +35,7 @@ const apiMap: IStringKeyMap = { smms: SmmsApi, tcyun: TcyunApi, upyun: UpyunApi, - webdavplist: WebdavApi + webdavplist: WebdavApi, } export default class ALLApi { diff --git a/src/main/apis/delete/github.ts b/src/main/apis/delete/github.ts index 12f46d81..39aabe1a 100644 --- a/src/main/apis/delete/github.ts +++ b/src/main/apis/delete/github.ts @@ -12,7 +12,7 @@ interface IConfigMap { export default class GithubApi { static #createOctokit(token: string) { return new Octokit({ - auth: token + auth: token, }) } @@ -25,7 +25,7 @@ export default class GithubApi { const { fileName, hash, - config: { repo, token, branch, path } + config: { repo, token, branch, path }, } = configMap const [owner, repoName] = repo.split('/') const octokit = GithubApi.#createOctokit(token) @@ -37,7 +37,7 @@ export default class GithubApi { path: key, message: `delete ${fileName} by PicList`, sha: hash, - branch + branch, }) const ok = status === 200 deleteLog(fileName, 'GitHub', ok) diff --git a/src/main/apis/delete/imgur.ts b/src/main/apis/delete/imgur.ts index 22012ece..2b4f0cbd 100644 --- a/src/main/apis/delete/imgur.ts +++ b/src/main/apis/delete/imgur.ts @@ -28,7 +28,7 @@ export default class ImgurApi { try { const response: AxiosResponse = await axios.delete(apiUrl, { headers: { Authorization }, - timeout: 30000 + timeout: 30000, }) const ok = response.status === 200 deleteLog(hash, 'Imgur', ok) diff --git a/src/main/apis/delete/lskyplist.ts b/src/main/apis/delete/lskyplist.ts index d22a9f67..885de2b0 100644 --- a/src/main/apis/delete/lskyplist.ts +++ b/src/main/apis/delete/lskyplist.ts @@ -21,17 +21,17 @@ export default class LskyplistApi { const v2Headers = { Accept: 'application/json', - Authorization: token || undefined + Authorization: token || undefined, } const requestAgent = new https.Agent({ - rejectUnauthorized: false + rejectUnauthorized: false, }) try { const response: AxiosResponse = await axios.delete(`${host}/api/v1/images/${hash}`, { headers: v2Headers, timeout: 30000, - httpsAgent: requestAgent + httpsAgent: requestAgent, }) const ok = response.status === 200 && response.data.status === true deleteLog(hash, 'Lskyplist', ok) diff --git a/src/main/apis/delete/piclist.ts b/src/main/apis/delete/piclist.ts index 589e5da6..af5d17f4 100644 --- a/src/main/apis/delete/piclist.ts +++ b/src/main/apis/delete/piclist.ts @@ -18,7 +18,7 @@ export default class PiclistApi { try { const response: AxiosResponse = await axios.post(url, { - list: [fullResult] + list: [fullResult], }) const ok = response.status === 200 && response.data?.success deleteLog(fullResult, 'Piclist', ok) diff --git a/src/main/apis/delete/qiniu.ts b/src/main/apis/delete/qiniu.ts index 99c57324..ff86acbe 100644 --- a/src/main/apis/delete/qiniu.ts +++ b/src/main/apis/delete/qiniu.ts @@ -11,7 +11,7 @@ export default class QiniuApi { static async delete(configMap: IConfigMap): Promise { const { fileName, - config: { accessKey, secretKey, bucket, path } + config: { accessKey, secretKey, bucket, path }, } = configMap const mac = new qiniu.auth.digest.Mac(accessKey, secretKey) const qiniuConfig = new qiniu.conf.Config() @@ -26,7 +26,7 @@ export default class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } }) diff --git a/src/main/apis/delete/smms.ts b/src/main/apis/delete/smms.ts index 66025de0..98349c67 100644 --- a/src/main/apis/delete/smms.ts +++ b/src/main/apis/delete/smms.ts @@ -23,13 +23,13 @@ export default class SmmsApi { try { const response: AxiosResponse = await axios.get(`${SmmsApi.#baseUrl}/delete/${hash}`, { headers: { - Authorization: token + Authorization: token, }, params: { hash, - format: 'json' + format: 'json', }, - timeout: 30000 + timeout: 30000, }) const ok = response.status === 200 deleteLog(hash, 'Smms', ok) diff --git a/src/main/apis/delete/tcyun.ts b/src/main/apis/delete/tcyun.ts index 27a3c09c..5e87e3d0 100644 --- a/src/main/apis/delete/tcyun.ts +++ b/src/main/apis/delete/tcyun.ts @@ -10,14 +10,14 @@ export default class TcyunApi { static #createCOS(SecretId: string, SecretKey: string): COS { return new COS({ SecretId, - SecretKey + SecretKey, }) } static async delete(configMap: IConfigMap): Promise { const { fileName, - config: { secretId, secretKey, bucket, area, path } + config: { secretId, secretKey, bucket, area, path }, } = configMap try { const cos = TcyunApi.#createCOS(secretId, secretKey) @@ -30,7 +30,7 @@ export default class TcyunApi { const result = await cos.deleteObject({ Bucket: bucket, Region: area, - Key: key + Key: key, }) const ok = result.statusCode === 204 deleteLog(fileName, 'Tcyun', ok) diff --git a/src/main/apis/delete/upyun.ts b/src/main/apis/delete/upyun.ts index 6f567a85..9519b676 100644 --- a/src/main/apis/delete/upyun.ts +++ b/src/main/apis/delete/upyun.ts @@ -12,7 +12,7 @@ export default class UpyunApi { static async delete(configMap: IConfigMap): Promise { const { fileName, - config: { bucket, operator, password, path } + config: { bucket, operator, password, path }, } = configMap try { const service = new Upyun.Service(bucket, operator, password) diff --git a/src/main/apis/delete/webdav.ts b/src/main/apis/delete/webdav.ts index fcb7fbb6..e9632984 100644 --- a/src/main/apis/delete/webdav.ts +++ b/src/main/apis/delete/webdav.ts @@ -13,12 +13,12 @@ export default class WebdavApi { static async delete(configMap: IConfigMap): Promise { const { fileName, - config: { host, username, password, path, sslEnabled, authType } + config: { host, username, password, path, sslEnabled, authType }, } = configMap const endpoint = formatEndpoint(host, sslEnabled) const options: WebDAVClientOptions = { username, - password + password, } if (authType === 'digest') { options.authType = AuthType.Digest diff --git a/src/main/apis/gui/index.ts b/src/main/apis/gui/index.ts index 340605e0..874d9155 100644 --- a/src/main/apis/gui/index.ts +++ b/src/main/apis/gui/index.ts @@ -16,7 +16,7 @@ import type { IShowMessageBoxOption, IShowMessageBoxResult, IShowNotificationOption, - IUploadOption + IUploadOption, } from '#/types/types' import { SHOW_INPUT_BOX } from '~/events/constant' import { T as $t } from '~/i18n' @@ -62,8 +62,8 @@ class GuiApi implements IGuiApi { async showInputBox( options: IShowInputBoxOption = { title: '', - placeholder: '' - } + placeholder: '', + }, ) { await this.showSettingWindow() this.getWebcontentsByWindowId(this.settingWindowId)?.send(SHOW_INPUT_BOX, options) @@ -103,7 +103,7 @@ class GuiApi implements IGuiApi { const [pasteTextItem, shortUrl] = await pasteTemplate( pasteStyle, imgs[i], - db.get(configPaths.settings.customLink) + db.get(configPaths.settings.customLink), ) imgs[i].shortUrl = shortUrl pasteText.push(pasteTextItem) @@ -114,7 +114,7 @@ class GuiApi implements IGuiApi { if (isShowResultNotification) { const notification = new Notification({ title: $t('UPLOAD_SUCCEED'), - body: shortUrl || (imgs[i].imgUrl! as string) + body: shortUrl || (imgs[i].imgUrl! as string), // icon: imgs[i].imgUrl }) setTimeout(() => { @@ -134,12 +134,12 @@ class GuiApi implements IGuiApi { showNotification( options: IShowNotificationOption = { title: '', - body: '' - } + body: '', + }, ) { const notification = new Notification({ title: options.title, - body: options.body + body: options.body, }) notification.show() } @@ -149,8 +149,8 @@ class GuiApi implements IGuiApi { title: '', message: '', type: 'info', - buttons: ['Yes', 'No'] - } + buttons: ['Yes', 'No'], + }, ) { return new Promise(resolve => { getWindowId().then(id => { @@ -158,7 +158,7 @@ class GuiApi implements IGuiApi { dialog.showMessageBox(BrowserWindow.fromId(id)!, options as MessageBoxOptions).then(res => { resolve({ result: res.response, - checkboxChecked: res.checkboxChecked + checkboxChecked: res.checkboxChecked, }) }) }) @@ -174,7 +174,7 @@ class GuiApi implements IGuiApi { return { defaultConfigPath, currentConfigPath, - galleryDBPath + galleryDBPath, } } @@ -191,7 +191,7 @@ class GuiApi implements IGuiApi { title: $t('TIPS_WARNING'), message: $t('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'), type: 'info', - buttons: ['Yes', 'No'] + buttons: ['Yes', 'No'], }) .then(res => { if (res.result === 0) { @@ -201,7 +201,7 @@ class GuiApi implements IGuiApi { } }) }) - } + }, }) } if (prop === 'removeById') { @@ -214,7 +214,7 @@ class GuiApi implements IGuiApi { title: $t('TIPS_WARNING'), message: $t('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'), type: 'info', - buttons: ['Yes', 'No'] + buttons: ['Yes', 'No'], }) .then(res => { if (res.result === 0) { @@ -224,11 +224,11 @@ class GuiApi implements IGuiApi { } }) }) - } + }, }) } return Reflect.get(target, prop) - } + }, }) } } diff --git a/src/main/events/busEventList.ts b/src/main/events/busEventList.ts index da0136b6..7a145c3f 100644 --- a/src/main/events/busEventList.ts +++ b/src/main/events/busEventList.ts @@ -8,7 +8,7 @@ import { UPLOAD_WITH_CLIPBOARD_FILES, UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, UPLOAD_WITH_FILES, - UPLOAD_WITH_FILES_RESPONSE + UPLOAD_WITH_FILES_RESPONSE, } from '@core/bus/constants' import { createMenu } from 'apis/app/system' import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis' @@ -24,7 +24,7 @@ function initEventCenter() { [UPLOAD_WITH_FILES]: busCallUploadFiles, [GET_WINDOW_ID]: busCallGetWindowId, [GET_SETTING_WINDOW_ID]: busCallGetSettingWindowId, - [CREATE_APP_MENU]: createMenu + [CREATE_APP_MENU]: createMenu, } for (const i in eventList) { bus.on(i, eventList[i]) @@ -57,5 +57,5 @@ function busCallGetSettingWindowId() { export default { listen() { initEventCenter() - } + }, } diff --git a/src/main/events/remotes/menu.ts b/src/main/events/remotes/menu.ts index 1e7a83e4..5b40fd67 100644 --- a/src/main/events/remotes/menu.ts +++ b/src/main/events/remotes/menu.ts @@ -13,7 +13,7 @@ import { PICGO_HANDLE_PLUGIN_DONE, PICGO_HANDLE_PLUGIN_ING, PICGO_TOGGLE_PLUGIN, - SHOW_MAIN_PAGE_QRCODE + SHOW_MAIN_PAGE_QRCODE, } from '~/events/constant' import { handlePluginUninstall, handlePluginUpdate } from '~/events/rpc/routes/plugin/utils' import { T as $t } from '~/i18n' @@ -37,24 +37,24 @@ const buildMiniPageMenu = () => { const template: (MenuItemConstructorOptions | MenuItem)[] = [ { label: $t('OPEN_MAIN_WINDOW'), - click: openMainWindow + click: openMainWindow, }, { label: $t('CHOOSE_DEFAULT_PICBED'), type: 'submenu', - submenu + submenu, }, { label: $t('UPLOAD_BY_CLIPBOARD'), click() { uploadClipboardFiles() - } + }, }, { label: $t('HIDE_MINI_WINDOW'), click() { BrowserWindow.getFocusedWindow()!.hide() - } + }, }, { label: $t('START_WATCH_CLIPBOARD'), @@ -67,7 +67,7 @@ const buildMiniPageMenu = () => { }) buildMiniPageMenu() }, - visible: !isListeningClipboard + visible: !isListeningClipboard, }, { label: $t('STOP_WATCH_CLIPBOARD'), @@ -77,19 +77,19 @@ const buildMiniPageMenu = () => { ClipboardWatcher.removeAllListeners() buildMiniPageMenu() }, - visible: isListeningClipboard + visible: isListeningClipboard, }, { label: $t('RELOAD_APP'), click() { app.relaunch() app.exit(0) - } + }, }, { role: 'quit', - label: $t('QUIT') - } + label: $t('QUIT'), + }, ] return Menu.buildFromTemplate(template) } @@ -102,36 +102,36 @@ const buildMainPageMenu = (win: BrowserWindow) => { dialog.showMessageBox({ title: 'PicList', message: 'PicList', - detail: `Version: ${pkg.version}\nAuthor: Kuingsmile\nGithub: https://github.com/Kuingsmile/PicList` + detail: `Version: ${pkg.version}\nAuthor: Kuingsmile\nGithub: https://github.com/Kuingsmile/PicList`, }) - } + }, }, { label: $t('SHOW_PICBED_QRCODE'), click() { win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE) - } + }, }, { label: $t('OPEN_TOOLBOX'), click() { const window = windowManager.create(IWindowList.TOOLBOX_WINDOW) window?.show() - } + }, }, { label: $t('SHOW_DEVTOOLS'), click() { win?.webContents?.openDevTools({ mode: 'detach' }) - } + }, }, { label: $t('FEEDBACK'), click() { const url = 'https://github.com/Kuingsmile/PicList/issues' shell.openExternal(url) - } - } + }, + }, ] as (MenuItemConstructorOptions | MenuItem)[] return Menu.buildFromTemplate(template) } @@ -145,11 +145,11 @@ const buildSecondPicBedMenu = () => { const currentPicBedMenuItem = [ { label: `${$t('CURRENT_SECOND_PICBED')} - ${currentPicBedName || 'None'}`, - enabled: false + enabled: false, }, { - type: 'separator' - } + type: 'separator', + }, ] let submenu = picBeds .filter(item => item.visible) @@ -168,19 +168,19 @@ const buildSecondPicBedMenu = () => { // see: https://github.com/electron/electron/issues/21292 type: 'checkbox', checked: config._id === defaultSecondUploaderId && item.type === secondUploader, - click: function () { + click() { changeSecondUploader(item.type, config, config._id) - } + }, } }) : undefined, click: !hasSubmenu ? function () { picgo.saveConfig({ - [configPaths.picBed.secondUploader]: item.type + [configPaths.picBed.secondUploader]: item.type, }) } - : undefined + : undefined, } }) // @ts-expect-error submenu type @@ -197,11 +197,11 @@ const buildPicBedListMenu = () => { const currentPicBedMenuItem = [ { label: `${$t('CURRENT_PICBED')} - ${currentPicBedName}`, - enabled: false + enabled: false, }, { - type: 'separator' - } + type: 'separator', + }, ] let submenu = picBeds .filter(item => item.visible) @@ -221,13 +221,13 @@ const buildPicBedListMenu = () => { // see: https://github.com/electron/electron/issues/21292 type: 'checkbox', checked: config._id === defaultId && item.type === currentPicBed, - click: function () { + click() { changeCurrentUploader(item.type, config, config._id) if (windowManager.has(IWindowList.SETTING_WINDOW)) { windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') } setTrayToolTip(`${item.type} ${config._configName || 'Default'}`) - } + }, } }) : undefined, @@ -235,14 +235,14 @@ const buildPicBedListMenu = () => { ? function () { picgo.saveConfig({ [configPaths.picBed.current]: item.type, - [configPaths.picBed.uploader]: item.type + [configPaths.picBed.uploader]: item.type, }) if (windowManager.has(IWindowList.SETTING_WINDOW)) { windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') } setTrayToolTip(item.type) } - : undefined + : undefined, } }) // @ts-expect-error submenu type @@ -259,7 +259,7 @@ const handleRestoreState = (item: string, name: string): void => { if (current === name) { picgo.saveConfig({ [configPaths.picBed.current]: 'smms', - [configPaths.picBed.uploader]: 'smms' + [configPaths.picBed.uploader]: 'smms', }) } } @@ -267,7 +267,7 @@ const handleRestoreState = (item: string, name: string): void => { const current = picgo.getConfig(configPaths.picBed.transformer) if (current === name) { picgo.saveConfig({ - [configPaths.picBed.transformer]: 'path' + [configPaths.picBed.transformer]: 'path', }) } } @@ -280,18 +280,18 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { enabled: !plugin.enabled, click() { picgo.saveConfig({ - [`picgoPlugins.${plugin.fullName}`]: true + [`picgoPlugins.${plugin.fullName}`]: true, }) const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send(PICGO_TOGGLE_PLUGIN, plugin.fullName, true) - } + }, }, { label: $t('DISABLE_PLUGIN'), enabled: plugin.enabled, click() { picgo.saveConfig({ - [`picgoPlugins.${plugin.fullName}`]: false + [`picgoPlugins.${plugin.fullName}`]: false, }) const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) @@ -303,7 +303,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { if (plugin.config.uploader.name) { handleRestoreState('uploader', plugin.config.uploader.name) } - } + }, }, { label: $t('UNINSTALL_PLUGIN'), @@ -311,7 +311,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) handlePluginUninstall(plugin.fullName) - } + }, }, { label: $t('UPDATE_PLUGIN'), @@ -319,14 +319,14 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName) handlePluginUpdate(plugin.fullName) - } - } + }, + }, ] as (MenuItemConstructorOptions | MenuItem)[] for (const i in plugin.config) { if (plugin.config[i].config.length > 0) { const obj = { label: $t('CONFIG_THING', { - c: `${i} - ${plugin.config[i].fullName || plugin.config[i].name}` + c: `${i} - ${plugin.config[i].fullName || plugin.config[i].name}`, }), click() { const window = windowManager.get(IWindowList.SETTING_WINDOW)! @@ -334,7 +334,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { const configName = plugin.config[i].fullName || plugin.config[i].name const config = plugin.config[i].config window.webContents.send(PICGO_CONFIG_PLUGIN, currentType, configName, config) - } + }, } menu.push(obj) } @@ -351,14 +351,14 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { const currentTransformer = picgo.getConfig(configPaths.picBed.transformer) || 'path' if (currentTransformer === transformer) { picgo.saveConfig({ - [configPaths.picBed.transformer]: 'path' + [configPaths.picBed.transformer]: 'path', }) } else { picgo.saveConfig({ - [configPaths.picBed.transformer]: transformer + [configPaths.picBed.transformer]: transformer, }) } - } + }, } menu.push(obj) } @@ -366,7 +366,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { // plugin custom menus if (plugin.guiMenu) { menu.push({ - type: 'separator' + type: 'separator', }) for (const i of plugin.guiMenu) { menu.push({ @@ -381,7 +381,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { } }) } - } + }, }) } } diff --git a/src/main/events/rpc/index.ts b/src/main/events/rpc/index.ts index 485b1e70..731edf2e 100644 --- a/src/main/events/rpc/index.ts +++ b/src/main/events/rpc/index.ts @@ -68,7 +68,7 @@ const routes = [ toolboxRouter.routes(), trayRouter.routes(), uploadRouter.routes(), - manageRouter.routes() + manageRouter.routes(), ] for (const route of routes) { diff --git a/src/main/events/rpc/routes/gallery/index.ts b/src/main/events/rpc/routes/gallery/index.ts index 34aee5cf..aa15f99a 100644 --- a/src/main/events/rpc/routes/gallery/index.ts +++ b/src/main/events/rpc/routes/gallery/index.ts @@ -34,7 +34,7 @@ const galleryRoutes = [ } return [txt, shortUrl] }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.GALLERY_REMOVE_FILES, @@ -42,7 +42,7 @@ const galleryRoutes = [ setTimeout(() => { picgo.emit(ICOREBuildInEvent.REMOVE, args[0], GuiApi.getInstance()) }, 500) - } + }, }, { action: IRPCActionType.GALLERY_GET_DB, @@ -50,7 +50,7 @@ const galleryRoutes = [ const dbStore = GalleryDB.getInstance() return await dbStore.get(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.GALLERY_GET_BY_ID_DB, @@ -58,7 +58,7 @@ const galleryRoutes = [ const dbStore = GalleryDB.getInstance() return await dbStore.getById(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.GALLERY_UPDATE_BY_ID_DB, @@ -66,7 +66,7 @@ const galleryRoutes = [ const dbStore = GalleryDB.getInstance() return await dbStore.updateById(args[0], args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.GALLERY_REMOVE_BY_ID_DB, @@ -74,7 +74,7 @@ const galleryRoutes = [ const dbStore = GalleryDB.getInstance() return await dbStore.removeById(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.GALLERY_INSERT_DB, @@ -82,7 +82,7 @@ const galleryRoutes = [ const dbStore = GalleryDB.getInstance() return await dbStore.insert(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.GALLERY_INSERT_DB_BATCH, @@ -90,8 +90,8 @@ const galleryRoutes = [ const dbStore = GalleryDB.getInstance() return await dbStore.insertMany(args[0]) }, - type: IRPCType.INVOKE - } + type: IRPCType.INVOKE, + }, ] galleryRouter.addBatch(galleryRoutes) diff --git a/src/main/events/rpc/routes/manage/bucket.ts b/src/main/events/rpc/routes/manage/bucket.ts index 59abe81b..2cdace74 100644 --- a/src/main/events/rpc/routes/manage/bucket.ts +++ b/src/main/events/rpc/routes/manage/bucket.ts @@ -9,93 +9,93 @@ export default [ handler: async (_: IIPCEvent, args: [currentPicBed: string]) => { return new ManageApi(args[0]).getBucketList() }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_GET_BUCKET_LIST_BACKSTAGE, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).getBucketListBackstage(args[1]) - } + }, }, { action: IRPCActionType.MANAGE_GET_BUCKET_LIST_RECURSIVELY, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).getBucketListRecursively(args[1]) - } + }, }, { action: IRPCActionType.MANAGE_CREATE_BUCKET, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).createBucket(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_GET_BUCKET_FILE_LIST, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).getBucketFileList(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_GET_BUCKET_DOMAIN, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).getBucketDomain(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_SET_BUCKET_ACL_POLICY, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).setBucketAclPolicy(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_RENAME_BUCKET_FILE, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).renameBucketFile(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_DELETE_BUCKET_FILE, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).deleteBucketFile(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_DELETE_BUCKET_FOLDER, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).deleteBucketFolder(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).getPreSignedUrl(args[1]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_UPLOAD_BUCKET_FILE, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).uploadBucketFile(args[1]) - } + }, }, { action: IRPCActionType.MANAGE_DOWNLOAD_BUCKET_FILE, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).downloadBucketFile(args[1]) - } + }, }, { action: IRPCActionType.MANAGE_CREATE_BUCKET_FOLDER, handler: async (_: IIPCEvent, args: [currentPicBed: string, param: IStringKeyMap]) => { return new ManageApi(args[0]).createBucketFolder(args[1]) }, - type: IRPCType.INVOKE - } + type: IRPCType.INVOKE, + }, ] diff --git a/src/main/events/rpc/routes/manage/config.ts b/src/main/events/rpc/routes/manage/config.ts index 03e6a5e7..78b83303 100644 --- a/src/main/events/rpc/routes/manage/config.ts +++ b/src/main/events/rpc/routes/manage/config.ts @@ -11,18 +11,18 @@ export default [ handler: async (_: IIPCEvent, args: [key?: string]) => { return manageApi.getConfig(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_SAVE_CONFIG, handler: async (_: IIPCEvent, args: [data: IObj]) => { manageApi.saveConfig(args[0]) - } + }, }, { action: IRPCActionType.MANAGE_REMOVE_CONFIG, handler: async (_: IIPCEvent, args: [key: string, propName: string]) => { manageApi.removeConfig(args[0], args[1]) - } - } + }, + }, ] diff --git a/src/main/events/rpc/routes/manage/upDownload.ts b/src/main/events/rpc/routes/manage/upDownload.ts index 1a8f1226..00817f63 100644 --- a/src/main/events/rpc/routes/manage/upDownload.ts +++ b/src/main/events/rpc/routes/manage/upDownload.ts @@ -13,66 +13,66 @@ export default [ action: IRPCActionType.MANAGE_OPEN_FILE_SELECT_DIALOG, handler: async () => { const res = await dialog.showOpenDialog({ - properties: ['openFile', 'multiSelections'] + properties: ['openFile', 'multiSelections'], }) return res.canceled ? [] : res.filePaths }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_GET_UPLOAD_TASK_LIST, handler: async () => { return UpDownTaskQueue.getInstance().getAllUploadTask() }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_GET_DOWNLOAD_TASK_LIST, handler: async () => { return UpDownTaskQueue.getInstance().getAllDownloadTask() }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_DELETE_UPLOADED_TASK, handler: async () => { UpDownTaskQueue.getInstance().removeUploadedTask() - } + }, }, { action: IRPCActionType.MANAGE_DELETE_ALL_UPLOADED_TASK, handler: async () => { UpDownTaskQueue.getInstance().clearUploadTaskQueue() - } + }, }, { action: IRPCActionType.MANAGE_DELETE_DOWNLOADED_TASK, handler: async () => { UpDownTaskQueue.getInstance().removeDownloadedTask() - } + }, }, { action: IRPCActionType.MANAGE_DELETE_ALL_DOWNLOADED_TASK, handler: async () => { UpDownTaskQueue.getInstance().clearDownloadTaskQueue() - } + }, }, { action: IRPCActionType.MANAGE_SELECT_DOWNLOAD_FOLDER, handler: async () => { const res = await dialog.showOpenDialog({ - properties: ['openDirectory'] + properties: ['openDirectory'], }) return res.filePaths[0] }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_GET_DEFAULT_DOWNLOAD_FOLDER, handler: async () => { return app.getPath('downloads') }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_OPEN_DOWNLOADED_FOLDER, @@ -83,27 +83,27 @@ export default [ } else { shell.openPath(app.getPath('downloads')) } - } + }, }, { action: IRPCActionType.MANAGE_OPEN_LOCAL_FILE, handler: async (_: IIPCEvent, args: [fullPath: string]) => { const fullPath = args[0] fs.existsSync(fullPath) ? shell.showItemInFolder(fullPath) : shell.openPath(path.dirname(fullPath)) - } + }, }, { action: IRPCActionType.MANAGE_DOWNLOAD_FILE_FROM_URL, handler: async (_: IIPCEvent, args: [urls: string[]]) => { return await downloadFileFromUrl(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.MANAGE_CONVERT_PATH_TO_BASE64, handler: async (_: IIPCEvent, args: [filePath: string]) => { return fs.readFileSync(args[0], 'base64') }, - type: IRPCType.INVOKE - } + type: IRPCType.INVOKE, + }, ] diff --git a/src/main/events/rpc/routes/picbed/delete.ts b/src/main/events/rpc/routes/picbed/delete.ts index 4df31abd..6fd74241 100644 --- a/src/main/events/rpc/routes/picbed/delete.ts +++ b/src/main/events/rpc/routes/picbed/delete.ts @@ -10,6 +10,6 @@ export default [ handler: async (_: IIPCEvent, args: [item: ImgInfo]) => { return await ALLApi.delete(args[0]) }, - type: IRPCType.INVOKE - } + type: IRPCType.INVOKE, + }, ] diff --git a/src/main/events/rpc/routes/picbed/index.ts b/src/main/events/rpc/routes/picbed/index.ts index 014932ee..8250ebf3 100644 --- a/src/main/events/rpc/routes/picbed/index.ts +++ b/src/main/events/rpc/routes/picbed/index.ts @@ -10,7 +10,7 @@ import { getUploaderConfigList, resetUploaderConfig, selectUploaderConfig, - updateUploaderConfig + updateUploaderConfig, } from '~/utils/handleUploaderConfig' const picbedRouter = new RPCRouter() @@ -34,7 +34,7 @@ const picbedRoutes = [ const config = getUploaderConfigList(args[0]) return config }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.PICBED_DELETE_CONFIG, @@ -43,7 +43,7 @@ const picbedRoutes = [ const config = deleteUploaderConfig(type, id) return config }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.UPLOADER_SELECT, @@ -52,7 +52,7 @@ const picbedRoutes = [ selectUploaderConfig(type, id) return true }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.UPLOADER_UPDATE_CONFIG, @@ -61,7 +61,7 @@ const picbedRoutes = [ updateUploaderConfig(type, id, config) return true }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.UPLOADER_RESET_CONFIG, @@ -70,7 +70,7 @@ const picbedRoutes = [ resetUploaderConfig(type, id) return true }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.PICBED_GET_PICBED_CONFIG, @@ -82,17 +82,17 @@ const picbedRoutes = [ const config = handleConfigWithFunction(_config) return { config, - name + name, } } else { return { config: [], - name + name, } } }, - type: IRPCType.INVOKE - } + type: IRPCType.INVOKE, + }, ] const picBedsRoutes = [...picbedRoutes, ...deleteRoutes] diff --git a/src/main/events/rpc/routes/plugin/index.ts b/src/main/events/rpc/routes/plugin/index.ts index 48cc9efa..b91516e8 100644 --- a/src/main/events/rpc/routes/plugin/index.ts +++ b/src/main/events/rpc/routes/plugin/index.ts @@ -3,7 +3,7 @@ import { pluginGetListFunc, pluginImportLocalFunc, pluginInstallFunc, - pluginUpdateAllFunc + pluginUpdateAllFunc, } from '~/events/rpc/routes/plugin/utils' import { IRPCActionType } from '~/utils/enum' @@ -12,20 +12,20 @@ const pluginRouter = new RPCRouter() const pluginRoutes = [ { action: IRPCActionType.PLUGIN_GET_LIST, - handler: pluginGetListFunc + handler: pluginGetListFunc, }, { action: IRPCActionType.PLUGIN_INSTALL, - handler: pluginInstallFunc + handler: pluginInstallFunc, }, { action: IRPCActionType.PLUGIN_IMPORT_LOCAL, - handler: pluginImportLocalFunc + handler: pluginImportLocalFunc, }, { action: IRPCActionType.PLUGIN_UPDATE_ALL, - handler: pluginUpdateAllFunc - } + handler: pluginUpdateAllFunc, + }, ] pluginRouter.addBatch(pluginRoutes) diff --git a/src/main/events/rpc/routes/plugin/utils.ts b/src/main/events/rpc/routes/plugin/utils.ts index 24687abe..dbc7333e 100644 --- a/src/main/events/rpc/routes/plugin/utils.ts +++ b/src/main/events/rpc/routes/plugin/utils.ts @@ -60,7 +60,7 @@ const getPluginList = async (): Promise => { let menu: Omit[] = [] if (plugin.guiMenu) { menu = plugin.guiMenu(picgo).map(item => ({ - label: item.label + label: item.label, })) } let gui = false @@ -81,25 +81,25 @@ const getPluginList = async (): Promise => { plugin: { fullName: pluginList[i], name: handleStreamlinePluginName(pluginList[i]), - config: plugin.config ? handleConfigWithFunction(plugin.config(picgo)) : [] + config: plugin.config ? handleConfigWithFunction(plugin.config(picgo)) : [], }, uploader: { name: uploaderName, config: handleConfigWithFunction( - getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo) - ) + getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo), + ), }, transformer: { name: transformerName, config: handleConfigWithFunction( - getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo) - ) - } + getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo), + ), + }, }, enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`), homepage: pluginPKG.homepage ? pluginPKG.homepage : '', guiMenu: menu, - ing: false + ing: false, } list.push(obj) } @@ -113,7 +113,7 @@ const handleNPMError = (): IDispose => { .showMessageBox({ title: $t('TIPS_ERROR'), message: $t('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'), - buttons: ['Yes'] + buttons: ['Yes'], }) .then(res => { if (res.response === 0) { @@ -135,7 +135,7 @@ export const handlePluginUpdate = async (fullName: string | string[]) => { } else { showNotification({ title: $t('PLUGIN_UPDATE_FAILED'), - body: res.body as string + body: res.body as string, }) } window.webContents.send('hideLoading') @@ -152,7 +152,7 @@ export const handlePluginUninstall = async (fullName: string) => { } else { showNotification({ title: $t('PLUGIN_UNINSTALL_FAILED'), - body: res.body as string + body: res.body as string, }) } window.webContents.send('hideLoading') @@ -169,7 +169,7 @@ export const pluginGetListFunc = async (event: IIPCEvent) => { event.sender.send('pluginList', []) showNotification({ title: $t('TIPS_GET_PLUGIN_LIST_FAILED'), - body: e.message + body: e.message, }) picgo.log.error(e) } @@ -182,14 +182,14 @@ export const pluginInstallFunc = async (event: IIPCEvent, args: [fullName: strin event.sender.send('installPlugin', { success: res.success, body: fullName, - errMsg: res.success ? '' : res.body + errMsg: res.success ? '' : res.body, }) if (res.success) { await shortKeyHandler.registerPluginShortKey(res.body[0]) } else { showNotification({ title: $t('PLUGIN_INSTALL_FAILED'), - body: res.body as string + body: res.body as string, }) } event.sender.send('hideLoading') @@ -199,7 +199,7 @@ export const pluginInstallFunc = async (event: IIPCEvent, args: [fullName: strin export const pluginImportLocalFunc = async (event: IIPCEvent) => { const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! const res = await dialog.showOpenDialog(settingWindow, { - properties: ['openDirectory'] + properties: ['openDirectory'], }) const filePaths = res.filePaths if (filePaths.length > 0) { @@ -212,17 +212,17 @@ export const pluginImportLocalFunc = async (event: IIPCEvent) => { event.sender.send('pluginList', []) showNotification({ title: $t('TIPS_GET_PLUGIN_LIST_FAILED'), - body: e.message + body: e.message, }) } showNotification({ title: $t('PLUGIN_IMPORT_SUCCEED'), - body: '' + body: '', }) } else { showNotification({ title: $t('PLUGIN_IMPORT_FAILED'), - body: res.body as string + body: res.body as string, }) } } diff --git a/src/main/events/rpc/routes/setting/advanced.ts b/src/main/events/rpc/routes/setting/advanced.ts index fe6a69dc..ba3c8074 100644 --- a/src/main/events/rpc/routes/setting/advanced.ts +++ b/src/main/events/rpc/routes/setting/advanced.ts @@ -7,18 +7,18 @@ export default [ action: IRPCActionType.ADVANCED_UPDATE_SERVER, handler: async () => { server.restart() - } + }, }, { action: IRPCActionType.ADVANCED_STOP_WEB_SERVER, handler: async () => { webServer.stop() - } + }, }, { action: IRPCActionType.ADVANCED_RESTART_WEB_SERVER, handler: async () => { webServer.restart() - } - } + }, + }, ] diff --git a/src/main/events/rpc/routes/setting/configure.ts b/src/main/events/rpc/routes/setting/configure.ts index 012b221c..1e826626 100644 --- a/src/main/events/rpc/routes/setting/configure.ts +++ b/src/main/events/rpc/routes/setting/configure.ts @@ -24,7 +24,7 @@ export default [ const sourcePath = path.join(picGoConfigPath, file) const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist')) await fs.copy(sourcePath, targetPath, { overwrite: true }) - }) + }), ) return true } catch (err: any) { @@ -32,48 +32,48 @@ export default [ throw new Error('Migrate failed') } }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.CONFIGURE_UPLOAD_COMMON_CONFIG, handler: async () => { return await uploadFile(commonConfigList) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.CONFIGURE_UPLOAD_MANAGE_CONFIG, handler: async () => { return await uploadFile(manageConfigList) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.CONFIGURE_UPLOAD_ALL_CONFIG, handler: async () => { return await uploadFile([...commonConfigList, ...manageConfigList]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.CONFIGURE_DOWNLOAD_COMMON_CONFIG, handler: async () => { return await downloadFile(commonConfigList) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.CONFIGURE_DOWNLOAD_MANAGE_CONFIG, handler: async () => { return await downloadFile(manageConfigList) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.CONFIGURE_DOWNLOAD_ALL_CONFIG, handler: async () => { return await downloadFile([...commonConfigList, ...manageConfigList]) }, - type: IRPCType.INVOKE - } + type: IRPCType.INVOKE, + }, ] diff --git a/src/main/events/rpc/routes/setting/mainApp.ts b/src/main/events/rpc/routes/setting/mainApp.ts index 35e983e2..dbe4fac3 100644 --- a/src/main/events/rpc/routes/setting/mainApp.ts +++ b/src/main/events/rpc/routes/setting/mainApp.ts @@ -18,7 +18,7 @@ export default [ handler: async (_: IIPCEvent, args: [key?: string]) => { return picgo.getConfig(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.PICLIST_GET_CONFIG_SYNC, @@ -26,13 +26,13 @@ export default [ const result = picgo.getConfig(args[0]) const eventInstance = event as IpcMainEvent eventInstance.returnValue = result - } + }, }, { action: IRPCActionType.PICLIST_SAVE_CONFIG, handler: async (_: IIPCEvent, args: [data: IObj]) => { picgo.saveConfig(args[0]) - } + }, }, { action: IRPCActionType.PICLIST_OPEN_FILE, @@ -42,12 +42,13 @@ export default [ fs.writeFileSync(abFilePath, '') } shell.openPath(abFilePath) - } + }, }, { action: IRPCActionType.PICLIST_OPEN_DIRECTORY, handler: async (_: IIPCEvent, args: [dirPath?: string, inStorePath?: boolean]) => { - let [dirPath, inStorePath = true] = args + let [dirPath] = args + const [inStorePath = true] = args if (inStorePath) { dirPath = path.join(STORE_PATH, dirPath || '') } @@ -55,19 +56,19 @@ export default [ return } shell.openPath(dirPath) - } + }, }, { action: IRPCActionType.PICLIST_AUTO_START, handler: async (_: IIPCEvent, args: [val: boolean]) => { await setAutoStart(args[0]) - } + }, }, { action: IRPCActionType.PICLIST_AUTO_START_STATUS, handler: async (_: IIPCEvent) => { return await isAutoStartEnabled() }, - type: IRPCType.INVOKE - } + type: IRPCType.INVOKE, + }, ] diff --git a/src/main/events/rpc/routes/setting/shortKey.ts b/src/main/events/rpc/routes/setting/shortKey.ts index fbab28a0..8601d8ce 100644 --- a/src/main/events/rpc/routes/setting/shortKey.ts +++ b/src/main/events/rpc/routes/setting/shortKey.ts @@ -11,7 +11,7 @@ import { IRPCActionType, IRPCType } from '~/utils/enum' const notificationFunc = (result: boolean) => { const notification = new Notification({ title: $t(`OPERATION_${result ? 'SUCCEED' : 'FAILED'}`), - body: $t(`TIPS_SHORTCUT_MODIFIED_${result ? 'SUCCEED' : 'CONFLICT'}`) + body: $t(`TIPS_SHORTCUT_MODIFIED_${result ? 'SUCCEED' : 'CONFLICT'}`), }) notification.show() } @@ -25,7 +25,7 @@ export default [ notificationFunc(result) return result }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.SHORTKEY_BIND_OR_UNBIND, @@ -33,13 +33,13 @@ export default [ const [item, from] = args const result = shortKeyHandler.bindOrUnbindShortKey(item, from) notificationFunc(result) - } + }, }, { action: IRPCActionType.SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE, handler: async (_: IIPCEvent, args: [status: boolean]) => { const [status] = args bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, status) - } - } + }, + }, ] diff --git a/src/main/events/rpc/routes/system/app.ts b/src/main/events/rpc/routes/system/app.ts index 61ecf38d..7f49d92c 100644 --- a/src/main/events/rpc/routes/system/app.ts +++ b/src/main/events/rpc/routes/system/app.ts @@ -11,19 +11,19 @@ export default [ handler: async () => { app.relaunch() app.exit(0) - } + }, }, { action: IRPCActionType.OPEN_FILE, handler: async (_: IIPCEvent, args: [filePath: string]) => { shell.openPath(args[0]) - } + }, }, { action: IRPCActionType.OPEN_URL, handler: async (_: IIPCEvent, args: [url: string]) => { shell.openExternal(args[0]) - } + }, }, { action: IRPCActionType.SET_CURRENT_LANGUAGE, @@ -31,6 +31,6 @@ export default [ i18nManager.setCurrentLanguage(args[0]) const { lang } = i18nManager.getCurrentLocales() picgo.i18n.setLanguage(lang) - } - } + }, + }, ] diff --git a/src/main/events/rpc/routes/system/window.ts b/src/main/events/rpc/routes/system/window.ts index a4909393..1fc1f3d6 100644 --- a/src/main/events/rpc/routes/system/window.ts +++ b/src/main/events/rpc/routes/system/window.ts @@ -8,7 +8,7 @@ import { buildMiniPageMenu, buildPicBedListMenu, buildPluginPageMenu, - buildSecondPicBedMenu + buildSecondPicBedMenu, } from '~/events/remotes/menu' import { IRPCActionType, IWindowList } from '~/utils/enum' import { openMiniWindow } from '~/utils/windowHelper' @@ -18,7 +18,7 @@ export default [ action: IRPCActionType.HIDE_DOCK, handler: async (_: IIPCEvent, args: [value: boolean]) => { args[0] ? app.dock?.hide() : app.dock?.show() - } + }, }, { action: IRPCActionType.OPEN_WINDOW, @@ -27,13 +27,13 @@ export default [ if (window) { window.show() } - } + }, }, { action: IRPCActionType.OPEN_MINI_WINDOW, handler: async () => { openMiniWindow() - } + }, }, { action: IRPCActionType.CLOSE_WINDOW, @@ -44,14 +44,14 @@ export default [ } else { window?.close() } - } + }, }, { action: IRPCActionType.MINIMIZE_WINDOW, handler: async () => { const window = BrowserWindow.getFocusedWindow() window?.minimize() - } + }, }, { action: IRPCActionType.SHOW_MINI_PAGE_MENU, @@ -59,9 +59,9 @@ export default [ const window = windowManager.get(IWindowList.MINI_WINDOW)! const menu = buildMiniPageMenu() menu.popup({ - window + window, }) - } + }, }, { action: IRPCActionType.SHOW_MAIN_PAGE_MENU, @@ -69,9 +69,9 @@ export default [ const window = windowManager.get(IWindowList.SETTING_WINDOW)! const menu = buildMainPageMenu(window) menu.popup({ - window + window, }) - } + }, }, { action: IRPCActionType.SHOW_UPLOAD_PAGE_MENU, @@ -79,9 +79,9 @@ export default [ const window = windowManager.get(IWindowList.SETTING_WINDOW)! const menu = buildPicBedListMenu() menu.popup({ - window + window, }) - } + }, }, { action: IRPCActionType.SHOW_SECOND_UPLOADER_MENU, @@ -89,9 +89,9 @@ export default [ const window = windowManager.get(IWindowList.SETTING_WINDOW)! const menu = buildSecondPicBedMenu() menu.popup({ - window + window, }) - } + }, }, { action: IRPCActionType.SHOW_PLUGIN_PAGE_MENU, @@ -99,23 +99,23 @@ export default [ const window = windowManager.get(IWindowList.SETTING_WINDOW)! const menu = buildPluginPageMenu(args[0]) menu.popup({ - window + window, }) - } + }, }, { action: IRPCActionType.SET_MINI_WINDOW_POS, handler: async (_: IIPCEvent, args: [pos: IMiniWindowPos]) => { const window = BrowserWindow.getFocusedWindow() window?.setBounds(args[0]) - } + }, }, { action: IRPCActionType.MINI_WINDOW_ON_TOP, handler: async (_: IIPCEvent, args: [isOnTop: boolean]) => { const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! miniWindow.setAlwaysOnTop(args[0]) - } + }, }, { action: IRPCActionType.MAIN_WINDOW_ON_TOP, @@ -123,14 +123,14 @@ export default [ const mainWindow = windowManager.get(IWindowList.SETTING_WINDOW)! const isAlwaysOnTop = mainWindow.isAlwaysOnTop() mainWindow.setAlwaysOnTop(!isAlwaysOnTop) - } + }, }, { action: IRPCActionType.UPDATE_MINI_WINDOW_ICON, handler: async (_: IIPCEvent, args: [iconPath: string]) => { const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! miniWindow.webContents.send('updateMiniIcon', args[0]) - } + }, }, { action: IRPCActionType.REFRESH_SETTING_WINDOW, @@ -139,6 +139,6 @@ export default [ settingWindow.webContents.session.clearCache().then(() => { settingWindow.webContents.reloadIgnoringCache() }) - } - } + }, + }, ] diff --git a/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts b/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts index 07a8d65f..b489a1d9 100644 --- a/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts +++ b/src/main/events/rpc/routes/toolbox/checkClipboardUpload.ts @@ -16,7 +16,7 @@ const defaultClipboardImagePath = path.join(defaultConfigPath, CLIPBOARD_IMAGE_F export const checkClipboardUploadMap: IToolboxCheckerMap = { [IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD]: async event => { sendToolboxRes(event, { - status: IToolboxItemCheckStatus.LOADING + status: IToolboxItemCheckStatus.LOADING, }) const configFilePath = dbPathChecker() if (fs.existsSync(configFilePath)) { @@ -26,29 +26,29 @@ export const checkClipboardUploadMap: IToolboxCheckerMap = { sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, msg: $t('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS', { - path: clipboardImagePath + path: clipboardImagePath, }), - value: clipboardImagePath + value: clipboardImagePath, }) } else { sendToolboxRes(event, { status: IToolboxItemCheckStatus.ERROR, msg: $t('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS', { - path: clipboardImagePath + path: clipboardImagePath, }), - value: path.dirname(clipboardImagePath) + value: path.dirname(clipboardImagePath), }) } } else { sendToolboxRes(event, { status: IToolboxItemCheckStatus.ERROR, msg: $t('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS', { - path: defaultClipboardImagePath + path: defaultClipboardImagePath, }), - value: path.dirname(defaultClipboardImagePath) + value: path.dirname(defaultClipboardImagePath), }) } - } + }, } export const fixClipboardUploadMap: IToolboxFixMap = { @@ -60,17 +60,17 @@ export const fixClipboardUploadMap: IToolboxFixMap = { fs.mkdirsSync(clipboardImagePath) return { type: IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD, - status: IToolboxItemCheckStatus.SUCCESS + status: IToolboxItemCheckStatus.SUCCESS, } - } catch (e) { + } catch (_e) { return { type: IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD, status: IToolboxItemCheckStatus.ERROR, msg: $t('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS', { - path: clipboardImagePath + path: clipboardImagePath, }), - value: path.dirname(clipboardImagePath) + value: path.dirname(clipboardImagePath), } } - } + }, } diff --git a/src/main/events/rpc/routes/toolbox/checkFile.ts b/src/main/events/rpc/routes/toolbox/checkFile.ts index 5fd8ce78..d54f8b7a 100644 --- a/src/main/events/rpc/routes/toolbox/checkFile.ts +++ b/src/main/events/rpc/routes/toolbox/checkFile.ts @@ -14,7 +14,7 @@ export const checkFileMap: IToolboxCheckerMap = { [IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => { const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN) sendToolboxRes(event, { - status: IToolboxItemCheckStatus.LOADING + status: IToolboxItemCheckStatus.LOADING, }) const configFilePath = dbPathChecker() try { @@ -23,64 +23,64 @@ export const checkFileMap: IToolboxCheckerMap = { sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, msg: $t('TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS', { - path: configFilePath + path: configFilePath, }), - value: configFilePath + value: configFilePath, }) } - } catch (e) { + } catch (_e) { sendToolboxRes(event, { status: IToolboxItemCheckStatus.ERROR, msg: $t('TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS'), - value: path.dirname(configFilePath) + value: path.dirname(configFilePath), }) } }, [IToolboxItemType.IS_GALLERY_FILE_BROKEN]: async event => { const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_GALLERY_FILE_BROKEN) sendToolboxRes(event, { - status: IToolboxItemCheckStatus.LOADING + status: IToolboxItemCheckStatus.LOADING, }) const galleryDB = GalleryDB.getInstance() if (galleryDB.errorList.length === 0) { sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, msg: $t('TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS', { - path: DB_PATH + path: DB_PATH, }), - value: path.dirname(DB_PATH) + value: path.dirname(DB_PATH), }) } else { sendToolboxRes(event, { status: IToolboxItemCheckStatus.ERROR, msg: $t('TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS'), - value: path.dirname(DB_PATH) + value: path.dirname(DB_PATH), }) } - } + }, } export const fixFileMap: IToolboxFixMap = { [IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => { try { fs.unlinkSync(dbPathChecker()) - } catch (e) { + } catch (_e) { // do nothing } return { type: IToolboxItemType.IS_CONFIG_FILE_BROKEN, - status: IToolboxItemCheckStatus.SUCCESS + status: IToolboxItemCheckStatus.SUCCESS, } }, [IToolboxItemType.IS_GALLERY_FILE_BROKEN]: async () => { try { fs.unlinkSync(DB_PATH) - } catch (e) { + } catch (_e) { // do nothing } return { type: IToolboxItemType.IS_GALLERY_FILE_BROKEN, - status: IToolboxItemCheckStatus.SUCCESS + status: IToolboxItemCheckStatus.SUCCESS, } - } + }, } diff --git a/src/main/events/rpc/routes/toolbox/checkProxy.ts b/src/main/events/rpc/routes/toolbox/checkProxy.ts index ea818221..133f676f 100644 --- a/src/main/events/rpc/routes/toolbox/checkProxy.ts +++ b/src/main/events/rpc/routes/toolbox/checkProxy.ts @@ -16,9 +16,9 @@ function getProxy(proxyStr: string): AxiosRequestConfig['proxy'] | null { return { host: proxyOptions.hostname, port: parseInt(proxyOptions.port || '0', 10), - protocol: proxyOptions.protocol + protocol: proxyOptions.protocol, } - } catch (e) {} + } catch (_e) {} } return null } @@ -28,18 +28,18 @@ const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_ export const checkProxyMap: IToolboxCheckerMap = { [IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async event => { sendToolboxRes(event, { - status: IToolboxItemCheckStatus.LOADING + status: IToolboxItemCheckStatus.LOADING, }) const configFilePath = dbPathChecker() if (fs.existsSync(configFilePath)) { let config: IConfig | undefined try { config = (await fs.readJSON(configFilePath)) as IConfig - } catch (e) {} + } catch (_e) {} if (!config) { return sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') + msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS'), }) } @@ -47,34 +47,34 @@ export const checkProxyMap: IToolboxCheckerMap = { if (!proxy) { return sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') + 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') + msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT'), }) } else { const httpsAgent = tunnel.httpsOverHttp({ proxy: { host: proxyOptions.host, - port: proxyOptions.port - } + port: proxyOptions.port, + }, }) try { await axios.get('https://www.google.com', { - httpsAgent + httpsAgent, }) return sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_SUCCESS_TIPS') + msg: $t('TOOLBOX_CHECK_PROXY_SUCCESS_TIPS'), }) - } catch (e) { + } catch (_e) { return sendToolboxRes(event, { status: IToolboxItemCheckStatus.ERROR, - msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING') + msg: $t('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING'), }) } } @@ -83,7 +83,7 @@ export const checkProxyMap: IToolboxCheckerMap = { sendToolboxRes(event, { status: IToolboxItemCheckStatus.SUCCESS, - msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS') + msg: $t('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS'), }) - } + }, } diff --git a/src/main/events/rpc/routes/toolbox/index.ts b/src/main/events/rpc/routes/toolbox/index.ts index 288c4d31..abd28ca2 100644 --- a/src/main/events/rpc/routes/toolbox/index.ts +++ b/src/main/events/rpc/routes/toolbox/index.ts @@ -12,12 +12,12 @@ const toolboxRouter = new RPCRouter() const toolboxCheckMap: Partial> = { ...checkFileMap, ...checkClipboardUploadMap, - ...checkProxyMap + ...checkProxyMap, } const toolboxFixMap: Partial> = { ...fixFileMap, - ...fixClipboardUploadMap + ...fixClipboardUploadMap, } toolboxRouter @@ -40,7 +40,7 @@ toolboxRouter } } }, - IRPCType.SEND + IRPCType.SEND, ) .add( IRPCActionType.TOOLBOX_CHECK_FIX, @@ -51,7 +51,7 @@ toolboxRouter return await handler(event as IpcMainEvent) } }, - IRPCType.INVOKE + IRPCType.INVOKE, ) export { toolboxRouter } diff --git a/src/main/events/rpc/routes/toolbox/utils.ts b/src/main/events/rpc/routes/toolbox/utils.ts index 9f0dd22d..1fa539b0 100644 --- a/src/main/events/rpc/routes/toolbox/utils.ts +++ b/src/main/events/rpc/routes/toolbox/utils.ts @@ -7,7 +7,7 @@ export function sendToolboxResWithType(type: string) { return (event: IpcMainEvent, res?: Omit) => { return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, { ...res, - type + type, }) } } diff --git a/src/main/events/rpc/routes/tray/index.ts b/src/main/events/rpc/routes/tray/index.ts index 3927b5dd..a63b5fc1 100644 --- a/src/main/events/rpc/routes/tray/index.ts +++ b/src/main/events/rpc/routes/tray/index.ts @@ -18,14 +18,14 @@ const trayRoutes = [ action: IRPCActionType.TRAY_SET_TOOL_TIP, handler: async (_: IIPCEvent, args: [text: string]) => { setTrayToolTip(args[0]) - } + }, }, { action: IRPCActionType.TRAY_GET_SHORT_URL, handler: async (_: IIPCEvent, args: [url: string]) => { return await generateShortUrl(args[0]) }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.TRAY_UPLOAD_CLIPBOARD_FILES, @@ -45,7 +45,7 @@ const trayRoutes = [ if (isShowResultNotification) { const notification = new Notification({ title: $t('UPLOAD_SUCCEED'), - body: shortUrl || img[0].imgUrl! + body: shortUrl || img[0].imgUrl!, // icon: file[0] // icon: img[0].imgUrl }) @@ -58,8 +58,8 @@ const trayRoutes = [ } } trayWindow.webContents.send('uploadFiles') - } - } + }, + }, ] trayRouter.addBatch(trayRoutes) diff --git a/src/main/events/rpc/routes/upload/index.ts b/src/main/events/rpc/routes/upload/index.ts index 8fcfd0d3..0159f306 100644 --- a/src/main/events/rpc/routes/upload/index.ts +++ b/src/main/events/rpc/routes/upload/index.ts @@ -14,20 +14,20 @@ const uploadRoutes = [ handler: async () => { return getPicBeds() }, - type: IRPCType.INVOKE + type: IRPCType.INVOKE, }, { action: IRPCActionType.UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE, handler: async () => { uploadClipboardFiles() - } + }, }, { action: IRPCActionType.UPLOAD_CHOOSED_FILES, handler: async (evt: IIPCEvent, args: [files: IFileWithPath[]]) => { return uploadChoosedFiles(evt.sender, args[0]) - } - } + }, + }, ] uploadRouter.addBatch(uploadRoutes) diff --git a/src/main/i18n/index.ts b/src/main/i18n/index.ts index 43d8920f..f0284903 100644 --- a/src/main/i18n/index.ts +++ b/src/main/i18n/index.ts @@ -13,22 +13,22 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) const builtinI18nList: II18nItem[] = [ { label: '简体中文', - value: 'zh-CN' + value: 'zh-CN', }, { label: '繁體中文', - value: 'zh-TW' + value: 'zh-TW', }, { label: 'English', - value: 'en' - } + value: 'en', + }, ] class I18nManager { private i18n: I18n | null = null private builtinI18nFolder = path.join(__dirname, '../../resources', 'i18n').replace('app.asar', 'app.asar.unpacked') private outterI18nFolder = '' - private localesMap: Map = new Map() + private localesMap = new Map() private currentLanguage: string = 'zh-CN' readonly defaultLanguage: string = 'zh-CN' private i18nFileList: II18nItem[] = builtinI18nList @@ -40,7 +40,7 @@ class I18nManager { addI18nFile(file: string, label: string) { this.i18nFileList.push({ label, - value: file + value: file, }) } @@ -79,11 +79,11 @@ class I18nManager { private initI18n(lang: string = this.defaultLanguage, locales: ILocales) { const objectAdapter = new ObjectAdapter({ - [lang]: locales + [lang]: locales, }) this.i18n = new I18n({ adapter: objectAdapter, - defaultLanguage: lang + defaultLanguage: lang, }) } @@ -98,7 +98,7 @@ class I18nManager { getCurrentLocales() { return { lang: this.currentLanguage, - locales: this.getLocales(this.currentLanguage) + locales: this.getLocales(this.currentLanguage), } } } diff --git a/src/main/lifeCycle/errorHandler.ts b/src/main/lifeCycle/errorHandler.ts index 9e1d04f2..30d8c56a 100644 --- a/src/main/lifeCycle/errorHandler.ts +++ b/src/main/lifeCycle/errorHandler.ts @@ -42,8 +42,8 @@ function bootstrapEPIPESuppression() { bootstrapEPIPESuppression() function epipeBomb(stream: any, callback: any) { - if (stream == null) stream = process.stdout - if (callback == null) callback = process.exit + if (stream === null) stream = process.stdout + if (callback === null) callback = process.exit function epipeFilter(err: any) { if (err.code === 'EPIPE') return callback() diff --git a/src/main/lifeCycle/index.ts b/src/main/lifeCycle/index.ts index 2c55898d..80b60f15 100644 --- a/src/main/lifeCycle/index.ts +++ b/src/main/lifeCycle/index.ts @@ -62,7 +62,7 @@ const handleStartUpFiles = (argv: string[], cwd: string) => { updater.autoUpdater.setFeedURL({ provider: 'generic', url: 'https://release.piclist.cn/latest', - channel: 'latest' + channel: 'latest', }) updater.autoUpdater.autoDownload = false @@ -101,13 +101,13 @@ updater.autoUpdater.on('update-available', async (info: updater.UpdateInfo) => { buttons: ['Yes', 'Go to download page'], message: $t('TIPS_FIND_NEW_VERSION', { - v: info.version + v: info.version, }) + '\n\n' + displayLog + truncatedNote, checkboxLabel: $t('NO_MORE_NOTICE'), - checkboxChecked: false + checkboxChecked: false, }) .then(result => { if (result.response === 0) { @@ -124,7 +124,7 @@ updater.autoUpdater.on('update-available', async (info: updater.UpdateInfo) => { updater.autoUpdater.on('download-progress', progressObj => { const percent = { - progress: progressObj.percent + progress: progressObj.percent, } const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send('updateProgress', percent) @@ -136,7 +136,7 @@ updater.autoUpdater.on('update-downloaded', () => { type: 'info', title: $t('UPDATE_DOWNLOADED'), buttons: ['Yes', 'No'], - message: $t('TIPS_UPDATE_DOWNLOADED') + message: $t('TIPS_UPDATE_DOWNLOADED'), }) .then(result => { const window = windowManager.get(IWindowList.SETTING_WINDOW)! @@ -243,7 +243,7 @@ class LifeCycle { miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]) db.set(configPaths.settings.miniWindowPosition, [ width - miniWindow.getSize()[0], - height - miniWindow.getSize()[1] + height - miniWindow.getSize()[1], ]) } else { miniWindow.setPosition(lastPosition[0], lastPosition[1]) @@ -297,7 +297,7 @@ class LifeCycle { .then(actualAutoStartEnabled => { if (actualAutoStartEnabled !== storedAutoStartEnabled) { logger.warn( - `Auto-start state mismatch detected. Stored: ${storedAutoStartEnabled}, Actual: ${actualAutoStartEnabled}. Syncing...` + `Auto-start state mismatch detected. Stored: ${storedAutoStartEnabled}, Actual: ${actualAutoStartEnabled}. Syncing...`, ) setAutoStart(storedAutoStartEnabled).catch(err => { logger.error('Failed to sync auto-start:', err) diff --git a/src/main/manage/apis/aliyun.ts b/src/main/manage/apis/aliyun.ts index 5cd9d0bd..c3ccba5d 100644 --- a/src/main/manage/apis/aliyun.ts +++ b/src/main/manage/apis/aliyun.ts @@ -13,7 +13,7 @@ import { formatError, getFileMimeType, hmacSha1Base64, - NewDownloader + NewDownloader, } from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import { isImage } from '~/utils/common' @@ -32,7 +32,7 @@ class AliyunApi { this.ctx = new OSS({ accessKeyId, accessKeySecret, - secure: true + secure: true, }) this.accessKeyId = accessKeyId this.accessKeySecret = accessKeySecret @@ -50,7 +50,7 @@ class AliyunApi { checked: false, isImage: false, match: false, - Key: item + Key: item, } } @@ -67,7 +67,7 @@ class AliyunApi { match: false, isImage: isImage(fileName), rawUrl: item.url, - url: `${urlPrefix}/${item.name}` + url: `${urlPrefix}/${item.name}`, } } @@ -89,7 +89,7 @@ class AliyunApi { canonicalizedResource: string, headers: IStringKeyMap, contentMd5: string, - contentType: string + contentType: string, ) { const date = new Date().toUTCString() const stringToSign = `${method.toUpperCase()}\n${contentMd5}\n${contentType}\n${date}\n${this.getCanonicalizedOSSHeaders(headers)}${canonicalizedResource}` @@ -102,7 +102,7 @@ class AliyunApi { accessKeySecret: this.accessKeySecret, region, bucket, - secure: true + secure: true, }) } @@ -113,18 +113,18 @@ class AliyunApi { const getBuckets = async (marker?: string) => { const res = (await this.ctx.listBuckets({ marker, - 'max-keys': 1000 + 'max-keys': 1000, })) as IStringKeyMap if (res?.res?.statusCode !== 200 || !res?.buckets) return { result: [], isTruncated: false } const formattedBuckets = res.buckets.map((item: OSS.Bucket) => ({ Name: item.name, Location: item.region, - CreationDate: item.creationDate + CreationDate: item.creationDate, })) return { result: formattedBuckets, isTruncated: res.isTruncated, - nextMarker: res.nextMarker + nextMarker: res.nextMarker, } } const result: IStringKeyMap[] = [] @@ -145,7 +145,7 @@ class AliyunApi { */ async getBucketDomain(param: IStringKeyMap): Promise { const headers = { - Date: new Date().toUTCString() + Date: new Date().toUTCString(), } const authorization = this.authorization('GET', `/${param.bucketName}/?cname`, headers, '', '') @@ -154,8 +154,8 @@ class AliyunApi { method: 'GET', headers: { ...headers, - Authorization: authorization - } + Authorization: authorization, + }, }) if (res?.status === 200) { @@ -191,18 +191,18 @@ class AliyunApi { accessKeyId: this.accessKeyId, accessKeySecret: this.accessKeySecret, region: configMap.region, - secure: true + secure: true, }) const aclTransMap: IStringKeyMap = { private: 'private', publicRead: 'public-read', - publicReadWrite: 'public-read-write' + publicReadWrite: 'public-read-write', } const res = await client.putBucket(configMap.BucketName, { acl: aclTransMap[configMap.acl], storageClass: 'Standard', dataRedundancyType: 'LRS', - timeout: this.timeOut + timeout: this.timeOut, }) return res?.res?.status === 200 } @@ -213,7 +213,7 @@ class AliyunApi { bucketName: bucket, bucketConfig: { Location: region }, prefix, - cancelToken + cancelToken, } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` @@ -229,7 +229,7 @@ class AliyunApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } const client = this.getNewCtx(region, bucket) do { @@ -237,11 +237,11 @@ class AliyunApi { { prefix: slicedPrefix === '' ? undefined : slicedPrefix, 'max-keys': '1000', - 'continuation-token': marker + 'continuation-token': marker, }, { - timeout: this.timeOut - } + timeout: this.timeOut, + }, ) if (res?.res?.statusCode === 200) { res?.objects?.forEach((item: OSS.ObjectMeta) => { @@ -268,7 +268,7 @@ class AliyunApi { bucketName: bucket, bucketConfig: { Location: region }, prefix, - cancelToken + cancelToken, } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` @@ -284,7 +284,7 @@ class AliyunApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } const client = this.getNewCtx(region, bucket) do { @@ -293,11 +293,11 @@ class AliyunApi { prefix: slicedPrefix === '' ? undefined : slicedPrefix, delimiter: '/', 'max-keys': '1000', - 'continuation-token': marker + 'continuation-token': marker, }, { - timeout: this.timeOut - } + timeout: this.timeOut, + }, ) if (res?.res?.statusCode === 200) { res?.prefixes?.forEach((item: string) => { @@ -342,7 +342,7 @@ class AliyunApi { bucketConfig: { Location: region }, prefix, marker, - itemsPerPage + itemsPerPage, } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` @@ -353,11 +353,11 @@ class AliyunApi { prefix: slicedPrefix || undefined, delimiter: '/', 'max-keys': itemsPerPage.toString(), - 'continuation-token': marker + 'continuation-token': marker, }, { - timeout: this.timeOut - } + timeout: this.timeOut, + }, )) as any // prefixes can be null // objects will be [] when no file @@ -366,20 +366,20 @@ class AliyunApi { fullList: [], isTruncated: false, nextMarker: '', - success: false + success: false, } } const fullList = [ ...(res.prefixes?.map((item: string) => this.formatFolder(item, slicedPrefix, urlPrefix)) || []), ...(res.objects ?.filter((item: OSS.ObjectMeta) => item.size !== 0) - .map((item: OSS.ObjectMeta) => this.formatFile(item, slicedPrefix, urlPrefix)) || []) + .map((item: OSS.ObjectMeta) => this.formatFile(item, slicedPrefix, urlPrefix)) || []), ] return { fullList, isTruncated: res.isTruncated, nextMarker: res.nextContinuationToken || '', - success: true + success: true, } } @@ -431,7 +431,7 @@ class AliyunApi { let isTruncated const allFileList = { CommonPrefixes: [] as any[], - Contents: [] as any[] + Contents: [] as any[], } do { const res = (await client.listV2( @@ -439,11 +439,11 @@ class AliyunApi { prefix: key, delimiter: '/', 'max-keys': '1000', - 'continuation-token': marker + 'continuation-token': marker, }, { - timeout: this.timeOut - } + timeout: this.timeOut, + }, )) as any if (res?.res.statusCode !== 200) return false @@ -458,7 +458,7 @@ class AliyunApi { const successfully = await this.deleteBucketFolder({ bucketName, region, - key: item + key: item, }) if (!successfully) return false } @@ -467,7 +467,7 @@ class AliyunApi { const cycle = Math.ceil(allFileList.Contents.length / 1000) for (let i = 0; i < cycle; i++) { const deleteRes = (await client.deleteMulti( - allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => item.name) + allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => item.name), )) as any if (deleteRes?.res.statusCode !== 200) return false } @@ -490,7 +490,7 @@ class AliyunApi { const { bucketName, region, key, expires, customUrl } = configMap const client = this.getNewCtx(region, bucketName) const res = client.signatureUrl(key, { - expires: expires || 3600 + expires: expires || 3600, }) return customUrl ? `${customUrl.replace(/\/+$/, '')}/${key}${res.slice(res.indexOf('?'))}` : res } @@ -527,7 +527,7 @@ class AliyunApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: bucketName, - targetFileRegion: region + targetFileRegion: region, }) client .multipartUpload(key, filePath, { @@ -538,9 +538,9 @@ class AliyunApi { instance.updateUploadTask({ id, progress: Math.floor(p * 100), - status: uploadTaskSpecialStatus.uploading + status: uploadTaskSpecialStatus.uploading, }) - } + }, }) .then((res: any) => { const id = `${bucketName}-${region}-${key}-${filePath}` @@ -550,7 +550,7 @@ class AliyunApi { progress: 100, status: uploadTaskSpecialStatus.uploaded, response: JSON.stringify(res), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } else { instance.updateUploadTask({ @@ -558,7 +558,7 @@ class AliyunApi { progress: 0, status: commonTaskStatus.failed, response: JSON.stringify(res), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } }) @@ -566,8 +566,8 @@ class AliyunApi { this.logger.error( formatError(err, { class: 'AliyunApi', - method: 'uploadBucketFile' - }) + method: 'uploadBucketFile', + }), ) const id = `${bucketName}-${region}-${key}-${filePath}` instance.updateUploadTask({ @@ -575,7 +575,7 @@ class AliyunApi { progress: 0, status: commonTaskStatus.failed, response: JSON.stringify(err), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) }) } @@ -614,10 +614,10 @@ class AliyunApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) const preSignedUrl = client.signatureUrl(key, { - expires: 60 * 60 * 48 + expires: 60 * 60 * 48, }) promises.push( () => @@ -629,7 +629,7 @@ class AliyunApi { reject(res) } }) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) @@ -637,8 +637,8 @@ class AliyunApi { this.logger.error( formatError(error, { class: 'AliyunApi', - method: 'downloadBucketFile' - }) + method: 'downloadBucketFile', + }), ) }) return true diff --git a/src/main/manage/apis/api.ts b/src/main/manage/apis/api.ts index 10b4efeb..85b551db 100644 --- a/src/main/manage/apis/api.ts +++ b/src/main/manage/apis/api.ts @@ -21,5 +21,5 @@ export default { SmmsApi, TcyunApi, UpyunApi, - WebdavplistApi + WebdavplistApi, } diff --git a/src/main/manage/apis/github.ts b/src/main/manage/apis/github.ts index 63154d0f..0988e4b4 100644 --- a/src/main/manage/apis/github.ts +++ b/src/main/manage/apis/github.ts @@ -13,7 +13,7 @@ import { getAgent, getOptions, gotUpload, - NewDownloader + NewDownloader, } from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import { formatHttpProxy, isImage, trimPath } from '~/utils/common' @@ -37,7 +37,7 @@ class GithubApi { this.proxyStr = formatHttpProxy(proxy, 'string') as string | undefined this.commonHeaders = { Authorization: this.token, - Accept: 'application/vnd.github+json' + Accept: 'application/vnd.github+json', } } @@ -74,7 +74,7 @@ class GithubApi { isDir: true, checked: false, isImage: false, - match: false + match: false, } } @@ -112,7 +112,7 @@ class GithubApi { match: false, isImage: isImage(item.path), rawUrl: item.url, - url: rawUrl + url: rawUrl, } } @@ -133,8 +133,8 @@ class GithubApi { 'json', undefined, undefined, - this.proxy - ) + this.proxy, + ), )) as any if (res.statusCode === 200) { res.body.forEach((item: any) => { @@ -142,7 +142,7 @@ class GithubApi { ...item, Name: item.name, Location: item.id, - CreationDate: item.created_at + CreationDate: item.created_at, }) }) } else { @@ -171,8 +171,8 @@ class GithubApi { 'json', undefined, undefined, - this.proxy - ) + this.proxy, + ), )) as any if (res.statusCode === 200) { res.body.forEach((item: any) => result.push(item.name)) @@ -199,7 +199,7 @@ class GithubApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } const treeQueue = [slicedPrefix] while (treeQueue.length) { @@ -210,7 +210,7 @@ class GithubApi { const currentPrefix = treeQueue[0] res = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/git/trees/${branch}:${treeQueue.shift()}`, - getOptions('GET', this.commonHeaders, {}, 'json', undefined, undefined, this.proxy) + getOptions('GET', this.commonHeaders, {}, 'json', undefined, undefined, this.proxy), )) as any if (res && res.statusCode === 200) { const { tree } = res.body @@ -250,11 +250,11 @@ class GithubApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } res = await got( `${this.baseUrl}/repos/${this.username}/${repo}/git/trees/${branch}:${slicedPrefix}`, - getOptions('GET', this.commonHeaders, undefined, 'json', undefined, undefined, this.proxy) + getOptions('GET', this.commonHeaders, undefined, 'json', undefined, undefined, this.proxy), ) if (res && res.statusCode === 200) { res.body.tree.forEach((item: any) => { @@ -290,11 +290,11 @@ class GithubApi { const body = { message: 'deleted by PicList', sha, - branch + branch, } const res = await got( `${this.baseUrl}/repos/${this.username}/${repo}/contents/${key}`, - getOptions('DELETE', this.commonHeaders, undefined, 'json', JSON.stringify(body), undefined, this.proxy) + getOptions('DELETE', this.commonHeaders, undefined, 'json', JSON.stringify(body), undefined, this.proxy), ) return res.statusCode === 200 } @@ -308,14 +308,14 @@ class GithubApi { // get sha of the branch const refRes = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/git/refs/heads/${branch}`, - getOptions('GET', this.commonHeaders, undefined, 'json', undefined, undefined, this.proxy) + getOptions('GET', this.commonHeaders, undefined, 'json', undefined, undefined, this.proxy), )) as any if (refRes.statusCode !== 200) return false const refSha = refRes.body.object.sha // get sha of the root tree const rootRes = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/branches/${branch}`, - getOptions('GET', undefined, undefined, 'json', undefined, undefined, this.proxy) + getOptions('GET', undefined, undefined, 'json', undefined, undefined, this.proxy), )) as any if (rootRes.statusCode !== 200) return false const rootSha = rootRes.body.commit.commit.tree.sha @@ -328,13 +328,13 @@ class GithubApi { 'GET', this.commonHeaders, { - recursive: true + recursive: true, }, 'json', undefined, undefined, - this.proxy - ) + this.proxy, + ), )) as any if (treeRes.statusCode !== 200) return false const oldTree = treeRes.body.tree @@ -345,7 +345,7 @@ class GithubApi { path: `${key.replace(/(^\/+|\/+$)/g, '')}/${item.path}`, mode: item.mode, type: item.type, - sha: null + sha: null, })) const newTreeShaRes = (await got( `${this.baseUrl}/repos/${this.username}/${repo}/git/trees`, @@ -356,11 +356,11 @@ class GithubApi { 'json', JSON.stringify({ base_tree: rootSha, - tree: newTree + tree: newTree, }), undefined, - this.proxy - ) + this.proxy, + ), )) as any if (newTreeShaRes.statusCode !== 201) return false const newTreeSha = newTreeShaRes.body.sha @@ -375,11 +375,11 @@ class GithubApi { JSON.stringify({ message: 'deleted by PicList', tree: newTreeSha, - parents: [refSha] + parents: [refSha], }), undefined, - this.proxy - ) + this.proxy, + ), )) as any if (commitRes.statusCode !== 201) return false const commitSha = commitRes.body.sha @@ -392,11 +392,11 @@ class GithubApi { undefined, 'json', JSON.stringify({ - sha: commitSha + sha: commitSha, }), undefined, - this.proxy - ) + this.proxy, + ), )) as any return updateRefRes.statusCode === 200 } @@ -421,13 +421,13 @@ class GithubApi { 'GET', this.commonHeaders, { - ref: branch + ref: branch, }, 'json', undefined, undefined, - this.proxy - ) + this.proxy, + ), )) as any return res.statusCode === 200 ? res.body.download_url : '' } @@ -443,11 +443,11 @@ class GithubApi { const body = { message: `created a new folder named ${key} by PicList`, content: base64Content, - branch + branch, } const res = await got( `${this.baseUrl}/repos/${this.username}/${repo}/contents/${newFileKey}`, - getOptions('PUT', this.commonHeaders, undefined, 'json', JSON.stringify(body), undefined, this.proxy) + getOptions('PUT', this.commonHeaders, undefined, 'json', JSON.stringify(body), undefined, this.proxy), ) return res.statusCode === 201 } @@ -479,7 +479,7 @@ class GithubApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: repo, - targetFileRegion: region + targetFileRegion: region, }) gotUpload( instance, @@ -488,14 +488,14 @@ class GithubApi { JSON.stringify({ message: 'uploaded by PicList', branch, - content: base64Content + content: base64Content, }), this.commonHeaders, id, this.logger, 30000, false, - getAgent(this.proxy) + getAgent(this.proxy), ) } return true @@ -521,7 +521,7 @@ class GithubApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) let downloadUrl: string if (githubPrivate) { @@ -530,7 +530,7 @@ class GithubApi { customUrl: branch, key, rawUrl: githubUrl, - githubPrivate + githubPrivate, }) downloadUrl = preSignedUrl } else { @@ -546,7 +546,7 @@ class GithubApi { reject(res) } }) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) @@ -554,8 +554,8 @@ class GithubApi { this.logger.error( formatError(error, { class: 'GithubApi', - method: 'downloadBucketFile' - }) + method: 'downloadBucketFile', + }), ) }) return true diff --git a/src/main/manage/apis/imgur.ts b/src/main/manage/apis/imgur.ts index 36c995a4..7a320b47 100644 --- a/src/main/manage/apis/imgur.ts +++ b/src/main/manage/apis/imgur.ts @@ -15,7 +15,7 @@ import { getFileMimeType, getOptions, gotUpload, - NewDownloader + NewDownloader, } from '~/manage/utils/common' import ManageLogger from '~/manage/utils/logger' import { formatHttpProxy, isImage } from '~/utils/common' @@ -38,7 +38,7 @@ class ImgurApi { this.proxyStr = formatHttpProxy(proxy, 'string') as string | undefined this.logger = logger this.tokenHeaders = { - Authorization: this.accessToken + Authorization: this.accessToken, } } @@ -57,7 +57,7 @@ class ImgurApi { match: false, isImage: isImg, url: item.link, - sha: item.deletehash + sha: item.deletehash, } } @@ -71,7 +71,7 @@ class ImgurApi { do { res = (await got( `${this.baseUrl}/account/${this.userName}/albums/${initPage}`, - getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) + getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy), )) as any if (!(res.statusCode === 200 && res.body.success)) { return [] @@ -83,12 +83,12 @@ class ImgurApi { ...item, Name: item.title, Location: item.id, - CreationDate: item.datetime + CreationDate: item.datetime, })) as any[] finalResult.push({ Name: '全部', Location: 'unclassified', - CreationDate: new Date().getTime() + CreationDate: new Date().getTime(), }) return finalResult } @@ -97,7 +97,7 @@ class ImgurApi { const window = windowManager.get(IWindowList.SETTING_WINDOW)! const { bucketConfig: { Location: albumHash }, - cancelToken + cancelToken, } = configMap const cancelTask = [false] ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => { @@ -110,12 +110,12 @@ class ImgurApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } if (albumHash !== 'unclassified') { res = (await got( `${this.baseUrl}/account/${this.userName}/album/${albumHash}`, - getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) + getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy), )) as any if (res.statusCode === 200 && res.body.success) { res.body.data.images.forEach((item: any) => { @@ -132,7 +132,7 @@ class ImgurApi { do { res = (await got( `${this.baseUrl}/account/${this.userName}/images/${initPage}`, - getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) + getOptions('GET', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy), )) as any if (res.statusCode === 200 && res.body.success) { res.body.data.forEach((item: any) => { @@ -157,7 +157,7 @@ class ImgurApi { const { DeleteHash: deleteHash } = configMap const res = (await got( `${this.baseUrl}/account/${this.userName}/image/${deleteHash}`, - getOptions('DELETE', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy) + getOptions('DELETE', this.tokenHeaders, undefined, 'json', undefined, undefined, this.proxy), )) as any return res.statusCode === 200 && res.body.success } @@ -186,7 +186,7 @@ class ImgurApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: bucketName, - targetFileRegion: albumHash + targetFileRegion: albumHash, }) const form = new FormData() form.append('type', 'file') @@ -195,12 +195,12 @@ class ImgurApi { if (fileSize > 1024 * 1024 * 10) { form.append('video', fs.createReadStream(filePath), { filename: path.basename(key), - contentType: getFileMimeType(fileName) + contentType: getFileMimeType(fileName), }) } else { form.append('image', fs.createReadStream(filePath), { filename: path.basename(key), - contentType: getFileMimeType(fileName) + contentType: getFileMimeType(fileName), }) } albumHash !== 'unclassified' && form.append('album', albumHash) @@ -216,7 +216,7 @@ class ImgurApi { this.logger, 30000, false, - getAgent(this.proxy) + getAgent(this.proxy), ) } return true @@ -242,7 +242,7 @@ class ImgurApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) promises.push( () => @@ -254,7 +254,7 @@ class ImgurApi { reject(res) } }) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) diff --git a/src/main/manage/apis/local.ts b/src/main/manage/apis/local.ts index b9985f97..bafa6e90 100644 --- a/src/main/manage/apis/local.ts +++ b/src/main/manage/apis/local.ts @@ -53,7 +53,7 @@ class LocalApi { checked: false, isImage: false, match: false, - url: urlPrefix + url: urlPrefix, } } @@ -70,7 +70,7 @@ class LocalApi { checked: false, match: false, isImage: isImage(fileName), - url: urlPrefix + url: urlPrefix, } } @@ -89,20 +89,20 @@ class LocalApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { res = fsWalk.walkSync(this.transBack(prefix), { followSymbolicLinks: true, fs, stats: true, - throwErrorOnBrokenSymbolicLink: false + throwErrorOnBrokenSymbolicLink: false, }) if (res.length) { result.fullList.push( ...res .filter((item: fsWalk.Entry) => item.stats?.isFile()) - .map((item: any) => this.formatFile(item, urlPrefix, item.name, item.path, true)) + .map((item: any) => this.formatFile(item, urlPrefix, item.name, item.path, true)), ) result.success = true } @@ -135,11 +135,11 @@ class LocalApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { const res = await fs.readdir(prefix, { - withFileTypes: true + withFileTypes: true, }) if (res.length) { let urlPrefixF @@ -199,7 +199,7 @@ class LocalApi { let result = false try { await fs.rm(this.transBack(key), { - recursive: true + recursive: true, }) result = true } catch (error) { @@ -226,7 +226,7 @@ class LocalApi { targetFilePath: key, targetFileBucket: bucketName, targetFileRegion: '', - noProgress: true + noProgress: true, }) try { fs.ensureFileSync(this.transBack(key)) @@ -235,7 +235,7 @@ class LocalApi { id, progress: 100, status: uploadTaskSpecialStatus.uploaded, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } catch (error) { this.logParam(error, 'uploadBucketFile') @@ -243,7 +243,7 @@ class LocalApi { id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } } @@ -255,7 +255,7 @@ class LocalApi { let result = false try { await fs.mkdir(this.transBack(key), { - recursive: true + recursive: true, }) result = true } catch (error) { @@ -279,7 +279,7 @@ class LocalApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) try { fs.ensureFileSync(savedFilePath) @@ -288,7 +288,7 @@ class LocalApi { id, progress: 100, status: downloadTaskSpecialStatus.downloaded, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } catch (error) { this.logParam(error, 'downloadBucketFile') @@ -296,7 +296,7 @@ class LocalApi { id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } } diff --git a/src/main/manage/apis/qiniu.ts b/src/main/manage/apis/qiniu.ts index 933695ad..c9ec5200 100644 --- a/src/main/manage/apis/qiniu.ts +++ b/src/main/manage/apis/qiniu.ts @@ -12,7 +12,7 @@ import { formatError, getFileMimeType, hmacSha1Base64, - NewDownloader + NewDownloader, } from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import { isImage } from '~/utils/common' @@ -30,7 +30,7 @@ class QiniuApi { hostList = { getBucketList: 'https://uc.qiniuapi.com/buckets', - getBucketDomain: 'https://uc.qiniuapi.com/v2/domains' + getBucketDomain: 'https://uc.qiniuapi.com/v2/domains', } constructor(accessKey: string, secretKey: string, logger: ManageLogger) { @@ -50,7 +50,7 @@ class QiniuApi { isDir: true, checked: false, isImage: false, - match: false + match: false, } } @@ -65,7 +65,7 @@ class QiniuApi { isDir: false, checked: false, match: false, - isImage: isImage(fileName) + isImage: isImage(fileName), } } @@ -76,7 +76,7 @@ class QiniuApi { body: string, query: string, contentType: string, - xQiniuHeaders?: IStringKeyMap + xQiniuHeaders?: IStringKeyMap, ) { let signStr = `${method.toUpperCase()} ${urlPath}${query ? `?${query}` : ''}\nHost: ${host}` @@ -104,9 +104,9 @@ class QiniuApi { const res = await axios.get(host, { headers: { Authorization: authorization, - 'Content-Type': this.commonType + 'Content-Type': this.commonType, }, - timeout: this.timeout + timeout: this.timeout, }) if (res?.status === 200 && res?.data?.length) { const result = [] as any[] @@ -117,7 +117,7 @@ class QiniuApi { Name: dataItem, Location: info.zone, CreationDate: new Date().toISOString(), - Private: info.private + Private: info.private, }) } return result @@ -137,23 +137,23 @@ class QiniuApi { url: `https://${this.host}/v2/bucketInfo`, params: { bucket: bucketName, - fs: true + fs: true, }, headers: { Authorization: authorization, 'Content-Type': 'application/json', - Host: this.host + Host: this.host, }, - timeout: this.timeout + timeout: this.timeout, }) return res?.status === 200 ? { success: true, private: res.data.private, - zone: res.data.zone + zone: res.data.zone, } : { - success: false + success: false, } } @@ -166,13 +166,13 @@ class QiniuApi { const authorization = qiniu.util.generateAccessToken(this.mac, `${host}?tbl=${bucketName}`, undefined) const res = await axios.get(host, { params: { - tbl: bucketName + tbl: bucketName, }, headers: { Authorization: authorization, - 'Content-Type': this.commonType + 'Content-Type': this.commonType, }, - timeout: this.timeout + timeout: this.timeout, }) return res?.status === 200 && res?.data?.length ? res.data : [] } @@ -192,14 +192,14 @@ class QiniuApi { url: `https://${this.host}/private`, params: { bucket: bucketName, - private: isPrivate + private: isPrivate, }, headers: { Authorization: authorization, 'Content-Type': this.commonType, - Host: this.host + Host: this.host, }, - timeout: this.timeout + timeout: this.timeout, }) return res?.status === 200 } @@ -223,14 +223,14 @@ class QiniuApi { headers: { Authorization: authorization, 'Content-Type': 'application/json', - Host: this.host + Host: this.host, }, - timeout: this.timeout + timeout: this.timeout, }) return res?.status === 200 ? await this.setBucketAclPolicy({ bucketName: BucketName, - isPrivate: !acl + isPrivate: !acl, }) : false } @@ -251,7 +251,7 @@ class QiniuApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -262,7 +262,7 @@ class QiniuApi { { prefix: slicedPrefix === '' ? undefined : slicedPrefix, marker, - limit: 1000 + limit: 1000, }, (err: any, respBody: any, respInfo: any) => { if (err) { @@ -270,10 +270,10 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } - } + }, ) }) if (res && res.respInfo.statusCode === 200) { @@ -313,7 +313,7 @@ class QiniuApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } const config = new qiniu.conf.Config() const bucketManager = new qiniu.rs.BucketManager(this.mac, config) @@ -325,7 +325,7 @@ class QiniuApi { prefix: slicedPrefix === '' ? undefined : slicedPrefix, delimiter: '/', marker, - limit: 1000 + limit: 1000, }, (err: any, respBody: any, respInfo: any) => { if (err) { @@ -333,10 +333,10 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } - } + }, ) }) if (res && res.respInfo.statusCode === 200) { @@ -390,7 +390,7 @@ class QiniuApi { fullList: [] as any, isTruncated: false, nextMarker: '', - success: false + success: false, } res = await new Promise((resolve, reject) => { bucketManager.listPrefix( @@ -399,7 +399,7 @@ class QiniuApi { limit: itemsPerPage, prefix: slicedPrefix === '' ? undefined : slicedPrefix, marker, - delimiter: '/' + delimiter: '/', }, (err, respBody, respInfo) => { if (err) { @@ -407,10 +407,10 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } - } + }, ) }) if (res?.respInfo?.statusCode === 200) { @@ -451,7 +451,7 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } }) @@ -470,7 +470,7 @@ class QiniuApi { let marker = '' let isTruncated = true const allFileList = { - Contents: [] as any[] + Contents: [] as any[], } do { const res = (await new Promise((resolve, reject) => { @@ -479,7 +479,7 @@ class QiniuApi { { prefix: key, marker, - limit: 1000 + limit: 1000, }, (err, respBody, respInfo) => { if (err) { @@ -487,10 +487,10 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } - } + }, ) })) as any if (res?.respInfo?.statusCode === 200) { @@ -515,7 +515,7 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } }) @@ -546,7 +546,7 @@ class QiniuApi { bucketName, newKey, { - force: true + force: true, }, (err, respBody, respInfo) => { if (err) { @@ -554,10 +554,10 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } - } + }, ) })) as any return res?.respInfo?.statusCode === 200 @@ -604,14 +604,14 @@ class QiniuApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: bucketName, - targetFileRegion: region + targetFileRegion: region, }) const config = new qiniu.conf.Config() const resumeUploader = new qiniu.resume_up.ResumeUploader(config) const putExtra = new qiniu.resume_up.PutExtra() const uploadToken = new qiniu.rs.PutPolicy({ scope: `${bucketName}:${key}`, - expires: 36000 + expires: 36000, }).uploadToken(this.mac) putExtra.fname = key putExtra.params = {} @@ -623,7 +623,7 @@ class QiniuApi { instance.updateUploadTask({ id: `${bucketName}-${region}-${key}-${filePath}`, progress, - status: uploadTaskSpecialStatus.uploading + status: uploadTaskSpecialStatus.uploading, }) } resumeUploader.putFile(uploadToken, key, filePath, putExtra, (respErr, respBody, respInfo) => { @@ -631,14 +631,14 @@ class QiniuApi { this.logger.error( formatError(respErr, { class: 'Qiniu', - method: 'uploadBucketFile' - }) + method: 'uploadBucketFile', + }), ) instance.updateUploadTask({ id: `${bucketName}-${region}-${key}-${filePath}`, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) return } @@ -648,14 +648,14 @@ class QiniuApi { progress: 100, status: uploadTaskSpecialStatus.uploaded, response: JSON.stringify(respBody), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } else { instance.updateUploadTask({ id: `${bucketName}-${region}-${key}-${filePath}`, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } }) @@ -670,7 +670,7 @@ class QiniuApi { async createBucketFolder(configMap: IStringKeyMap): Promise { const { bucketName, key } = configMap const putPolicy = new qiniu.rs.PutPolicy({ - scope: `${bucketName}:${key}` + scope: `${bucketName}:${key}`, }) const uploadToken = putPolicy.uploadToken(this.mac) const FormUploader = new qiniu.form_up.FormUploader() @@ -682,7 +682,7 @@ class QiniuApi { } else { resolve({ respBody, - respInfo + respInfo, }) } }) @@ -710,12 +710,12 @@ class QiniuApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) const preSignedUrl = await this.getPreSignedUrl({ key, expires: 36000, - customUrl + customUrl, }) promises.push( () => @@ -727,7 +727,7 @@ class QiniuApi { reject(res) } }) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) diff --git a/src/main/manage/apis/s3plist.ts b/src/main/manage/apis/s3plist.ts index 76e06135..87af4312 100644 --- a/src/main/manage/apis/s3plist.ts +++ b/src/main/manage/apis/s3plist.ts @@ -18,7 +18,7 @@ import { PutObjectCommand, PutPublicAccessBlockCommand, S3Client, - S3ClientConfig + S3ClientConfig, } from '@aws-sdk/client-s3' import { Progress, Upload } from '@aws-sdk/lib-storage' import { getSignedUrl } from '@aws-sdk/s3-request-presigner' @@ -55,7 +55,7 @@ class S3plistApi { proxy: string | undefined, logger: ManageLogger, dogeCloudSupport: boolean = false, - bucketName: string = '' + bucketName: string = '', ) { this.accessKeyId = accessKeyId this.secretAccessKey = secretAccessKey @@ -64,12 +64,12 @@ class S3plistApi { this.baseOptions = { credentials: { accessKeyId, - secretAccessKey + secretAccessKey, }, endpoint: endpoint ? formatEndpoint(endpoint, sslEnabled) : undefined, tls: sslEnabled, forcePathStyle: s3ForcePathStyle, - requestHandler: this.setAgent(proxy, sslEnabled) + requestHandler: this.setAgent(proxy, sslEnabled), } this.logger = logger this.proxy = formatHttpProxy(proxy, 'string') as string | undefined @@ -84,7 +84,7 @@ class S3plistApi { this.baseOptions.credentials = { accessKeyId: token.accessKeyId, secretAccessKey: token.secretAccessKey, - sessionToken: token.sessionToken + sessionToken: token.sessionToken, } } @@ -93,7 +93,7 @@ class S3plistApi { const commonOptions: AgentOptions = { keepAlive: true, keepAliveMsecs: 1000, - scheduling: 'lifo' as 'lifo' | 'fifo' | undefined + scheduling: 'lifo' as 'lifo' | 'fifo' | undefined, } const extraOptions = sslEnabled ? { rejectUnauthorized: false } : {} return sslEnabled @@ -102,16 +102,16 @@ class S3plistApi { ? agent.https : new https.Agent({ ...commonOptions, - ...extraOptions - }) + ...extraOptions, + }), }) : new NodeHttpHandler({ httpAgent: agent.http ? agent.http : new http.Agent({ ...commonOptions, - ...extraOptions - }) + ...extraOptions, + }), }) } @@ -128,7 +128,7 @@ class S3plistApi { checked: false, isImage: false, match: false, - key: item.Prefix + key: item.Prefix, } } @@ -144,7 +144,7 @@ class S3plistApi { isDir: false, checked: false, match: false, - isImage: isImage(fileName || '') + isImage: isImage(fileName || ''), } } @@ -155,8 +155,8 @@ class S3plistApi { BlockPublicAcls: false, IgnorePublicAcls: false, BlockPublicPolicy: false, - RestrictPublicBuckets: false - } + RestrictPublicBuckets: false, + }, } const command = new PutPublicAccessBlockCommand(input) const data = await client.send(command) @@ -193,7 +193,7 @@ class S3plistApi { if (endpoint === '' || endpoint.includes('amazonaws')) { const createCommand = new CreateBucketCommand({ Bucket: BucketName, - ObjectOwnership: 'BucketOwnerPreferred' + ObjectOwnership: 'BucketOwnerPreferred', }) const createData = await client.send(createCommand) if (createData.$metadata.httpStatusCode === 200) { @@ -201,7 +201,7 @@ class S3plistApi { await this.putPublicAccess(BucketName, client) const putACLCommand = new PutBucketAclCommand({ Bucket: BucketName, - ACL: acl + ACL: acl, }) const putACLData = await client.send(putACLCommand) if (putACLData.$metadata.httpStatusCode !== 200) { @@ -216,7 +216,7 @@ class S3plistApi { } else { const createCommand = new CreateBucketCommand({ Bucket: BucketName, - ACL: acl + ACL: acl, }) const createData = await client.send(createCommand) if (createData.$metadata.httpStatusCode === 200) { @@ -244,8 +244,8 @@ class S3plistApi { { Name: item.s3Bucket, CreationDate: item.ctime, - Location: item.region - } + Location: item.region, + }, ] } } @@ -274,16 +274,16 @@ class S3plistApi { ...data.Buckets.map(bucket => ({ Name: bucket.Name, CreationDate: bucket.CreationDate, - Location: 'auto' - })) + Location: 'auto', + })), ) } else { for (const bucket of data.Buckets) { const bucketName = bucket.Name const bucketConfig = await client.send( new GetBucketLocationCommand({ - Bucket: bucketName - }) + Bucket: bucketName, + }), ) result.push({ Name: bucketName, @@ -291,7 +291,7 @@ class S3plistApi { Location: bucketConfig.$metadata.httpStatusCode === 200 ? bucketConfig.LocationConstraint?.toLowerCase() || 'us-east-1' - : 'us-east-1' + : 'us-east-1', }) if (bucketConfig.$metadata.httpStatusCode !== 200) { this.logParam(bucketConfig, 'getBucketList') @@ -311,7 +311,7 @@ class S3plistApi { bucketName: bucket, bucketConfig: { Location: region }, prefix, - cancelToken + cancelToken, } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` @@ -327,7 +327,7 @@ class S3plistApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { do { @@ -338,7 +338,7 @@ class S3plistApi { Bucket: bucket, Prefix: slicedPrefix === '' ? undefined : slicedPrefix, MaxKeys: 1000, - ContinuationToken: marker + ContinuationToken: marker, }) res = await client.send(command) if (res.$metadata.httpStatusCode === 200) { @@ -375,7 +375,7 @@ class S3plistApi { bucketName: bucket, bucketConfig: { Location: region }, prefix, - cancelToken + cancelToken, } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` @@ -391,7 +391,7 @@ class S3plistApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { await this.getDogeCloudToken() @@ -404,7 +404,7 @@ class S3plistApi { Prefix: slicedPrefix === '' ? undefined : slicedPrefix, MaxKeys: 1000, ContinuationToken: marker, - Delimiter: '/' + Delimiter: '/', }) res = await client.send(command) if (res.$metadata.httpStatusCode === 200) { @@ -445,7 +445,7 @@ class S3plistApi { bucketConfig: { Location: region }, prefix, marker, - itemsPerPage + itemsPerPage, } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` @@ -453,13 +453,13 @@ class S3plistApi { fullList: [] as any, isTruncated: false, nextMarker: '', - success: false + success: false, } try { await this.getDogeCloudToken() const options = { ...this.baseOptions, - region: String(region) || 'us-east-1' + region: String(region) || 'us-east-1', } as S3ClientConfig const client = new S3Client(options) const command = new ListObjectsV2Command({ @@ -467,13 +467,13 @@ class S3plistApi { Prefix: slicedPrefix, ContinuationToken: marker === '' ? undefined : marker, Delimiter: '/', - MaxKeys: itemsPerPage + MaxKeys: itemsPerPage, }) const data = await client.send(command) if (data.$metadata.httpStatusCode === 200) { result.fullList = [ ...(data.CommonPrefixes?.map(item => this.formatFolder(item, slicedPrefix, urlPrefix)) || []), - ...(data.Contents?.map(item => this.formatFile(item, slicedPrefix, urlPrefix)) || []) + ...(data.Contents?.map(item => this.formatFile(item, slicedPrefix, urlPrefix)) || []), ] result.isTruncated = data.IsTruncated || false result.nextMarker = data.NextContinuationToken || '' @@ -502,19 +502,19 @@ class S3plistApi { await this.getDogeCloudToken() const options = { ...this.baseOptions, - region: String(region) || 'us-east-1' + region: String(region) || 'us-east-1', } as S3ClientConfig const client = new S3Client(options) const command = new CopyObjectCommand({ Bucket: bucketName, CopySource: encodeURI(`${bucketName}/${oldKey}`), - Key: newKey + Key: newKey, }) const data = await client.send(command) if (data.$metadata.httpStatusCode === 200) { const deleteCommand = new DeleteObjectCommand({ Bucket: bucketName, - Key: oldKey + Key: oldKey, }) const deleteData = await client.send(deleteCommand) if (deleteData.$metadata.httpStatusCode === 204) { @@ -550,7 +550,7 @@ class S3plistApi { const client = new S3Client(options) const command = new DeleteObjectCommand({ Bucket: bucketName, - Key: key + Key: key, }) const data = await client.send(command) if (data.$metadata.httpStatusCode === 204) { @@ -576,7 +576,7 @@ class S3plistApi { let res const allFileList = { CommonPrefixes: [] as any[], - Contents: [] as any[] + Contents: [] as any[], } try { await this.getDogeCloudToken() @@ -589,7 +589,7 @@ class S3plistApi { Prefix: key, ContinuationToken: marker === '' ? undefined : marker, Delimiter: '/', - MaxKeys: 1000 + MaxKeys: 1000, }) res = (await client.send(command)) as ListObjectsV2CommandOutput if (res.$metadata.httpStatusCode === 200) { @@ -607,7 +607,7 @@ class S3plistApi { res = await this.deleteBucketFolder({ bucketName, region, - key: item.Prefix + key: item.Prefix, }) if (!res) { return result @@ -626,10 +626,10 @@ class S3plistApi { Delete: { Objects: deleteList.map(item => { return { - Key: item.Key + Key: item.Key, } - }) - } + }), + }, }) res = await client.send(deleteCommand) if (res.$metadata.httpStatusCode !== 200) { @@ -668,11 +668,11 @@ class S3plistApi { client, new GetObjectCommand({ Bucket: bucketName, - Key: key + Key: key, }), { - expiresIn: expires || 3600 - } + expiresIn: expires || 3600, + }, ) return signedUrl } catch (error) { @@ -695,7 +695,7 @@ class S3plistApi { const client = new S3Client(options) const command = new PutObjectCommand({ Bucket: bucketName, - Key: key + Key: key, }) const data = await client.send(command) if (data.$metadata.httpStatusCode === 200) { @@ -733,7 +733,7 @@ class S3plistApi { 'aws-exec-read', 'authenticated-read', 'bucket-owner-read', - 'bucket-owner-full-control' + 'bucket-owner-full-control', ] for (const item of fileArray) { const { bucketName, region, key, filePath, fileName, aclForUpload } = item @@ -749,7 +749,7 @@ class S3plistApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: bucketName, - targetFileRegion: String(region) + targetFileRegion: String(region), }) try { await this.getDogeCloudToken() @@ -760,7 +760,7 @@ class S3plistApi { progress: 0, status: commonTaskStatus.failed, response: JSON.stringify(error), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) continue } @@ -777,15 +777,15 @@ class S3plistApi { ContentType: getFileMimeType(fileName), ACL: allowedAcl.includes(aclForUpload) ? aclForUpload : 'private', Metadata: { - description: 'uploaded by PicList' - } - } + description: 'uploaded by PicList', + }, + }, }) parallelUploads3.on('httpUploadProgress', (progress: Progress) => { instance.updateUploadTask({ id, progress: progress.loaded && progress.total ? Math.floor((progress.loaded / progress.total) * 100) : 0, - status: uploadTaskSpecialStatus.uploading + status: uploadTaskSpecialStatus.uploading, }) }) parallelUploads3 @@ -796,14 +796,14 @@ class S3plistApi { id, progress: 100, status: uploadTaskSpecialStatus.uploaded, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } else { instance.updateUploadTask({ id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } }) @@ -814,7 +814,7 @@ class S3plistApi { progress: 0, status: commonTaskStatus.failed, response: JSON.stringify(error), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) }) } @@ -841,14 +841,14 @@ class S3plistApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) const preSignedUrl = await this.getPreSignedUrl({ bucketName, region: String(region), key, expires: 36000, - customUrl + customUrl, }) promises.push( () => @@ -860,7 +860,7 @@ class S3plistApi { reject(res) } }) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) diff --git a/src/main/manage/apis/sftp.ts b/src/main/manage/apis/sftp.ts index 778250dc..a00df90d 100644 --- a/src/main/manage/apis/sftp.ts +++ b/src/main/manage/apis/sftp.ts @@ -53,7 +53,7 @@ class SftpApi { passphrase: Undefinable, fileMode: Undefinable, dirMode: Undefinable, - logger: ManageLogger + logger: ManageLogger, ) { this.host = host this.port = Number(port) || 22 @@ -71,7 +71,7 @@ class SftpApi { username: this.username, password: this.password, privateKey: this.privateKey, - passphrase: this.passphrase + passphrase: this.passphrase, } } @@ -117,7 +117,7 @@ class SftpApi { checked: false, isImage: false, match: false, - url + url, } } @@ -134,7 +134,7 @@ class SftpApi { checked: false, match: false, isImage: isImage(item.filename), - url: isWebPath ? urlPrefix : `${urlPrefix}${item.filename}` + url: isWebPath ? urlPrefix : `${urlPrefix}${item.filename}`, } } @@ -166,7 +166,7 @@ class SftpApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { await this.connectClient() @@ -211,7 +211,7 @@ class SftpApi { size: Number(size) || 0, mtime, filename, - key + key, }) }) return result @@ -237,7 +237,7 @@ class SftpApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { await this.connectClient() @@ -339,13 +339,13 @@ class SftpApi { targetFilePath: key, targetFileBucket: bucketName, targetFileRegion: region, - noProgress: false + noProgress: false, }) try { await this.connectClient() const res = await this.ctx.putFile(filePath, `/${key.replace(/^\/+/, '')}`, { fileMode: this.fileMode, - dirMode: this.dirMode + dirMode: this.dirMode, }) this.ctx.close() if (res) { @@ -353,14 +353,14 @@ class SftpApi { id, progress: 100, status: uploadTaskSpecialStatus.uploaded, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } else { instance.updateUploadTask({ id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } } catch (error) { @@ -369,7 +369,7 @@ class SftpApi { id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } } @@ -405,7 +405,7 @@ class SftpApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) try { await this.connectClient() @@ -416,14 +416,14 @@ class SftpApi { id, progress: 100, status: downloadTaskSpecialStatus.downloaded, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } else { instance.updateDownloadTask({ id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } } catch (error) { @@ -432,7 +432,7 @@ class SftpApi { id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } } diff --git a/src/main/manage/apis/smms.ts b/src/main/manage/apis/smms.ts index e6acc8c0..a882ea5c 100644 --- a/src/main/manage/apis/smms.ts +++ b/src/main/manage/apis/smms.ts @@ -27,12 +27,12 @@ class SmmsApi { baseURL: this.baseUrl, timeout: this.timeout, headers: { - Authorization: this.token + Authorization: this.token, }, httpsAgent: new Agent({ keepAlive: true, - timeout: this.timeout - }) + timeout: this.timeout, + }), }) this.logger = logger } @@ -50,7 +50,7 @@ class SmmsApi { match: false, isImage: isImage(item.storename), sha: item.hash, - downloadUrl: item.url + downloadUrl: item.url, } } @@ -69,17 +69,17 @@ class SmmsApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } do { res = await this.axiosInstance('/upload_history', { method: 'GET', headers: { - 'Content-Type': 'multipart/form-data' + 'Content-Type': 'multipart/form-data', }, params: { - page: marker - } + page: marker, + }, }) if (res && res.status === 200 && res.data && res.data.success) { if (res.data.Count === 0) { @@ -128,16 +128,16 @@ class SmmsApi { fullList: [] as any, isTruncated: false, nextMarker: '', - success: false + success: false, } const res = await this.axiosInstance('/upload_history', { method: 'GET', headers: { - 'Content-Type': 'multipart/form-data' + 'Content-Type': 'multipart/form-data', }, params: { - page: currentPage - } + page: currentPage, + }, }) if (res?.status !== 200 || !res?.data?.success) return result @@ -167,8 +167,8 @@ class SmmsApi { method: 'GET', params: { hash: DeleteHash, - format: 'json' - } + format: 'json', + }, }) return res?.status === 200 && res?.data?.success } @@ -194,13 +194,13 @@ class SmmsApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: bucketName, - targetFileRegion: region + targetFileRegion: region, }) const form = new FormData() form.append('format', 'json') form.append('smfile', fs.createReadStream(filePath), { filename: path.basename(fileName), - contentType: getFileMimeType(fileName) + contentType: getFileMimeType(fileName), }) const headers = form.getHeaders() headers.Authorization = this.token @@ -230,7 +230,7 @@ class SmmsApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) promises.push( () => @@ -242,7 +242,7 @@ class SmmsApi { reject(res) } }) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) diff --git a/src/main/manage/apis/tcyun.ts b/src/main/manage/apis/tcyun.ts index eafdd1ac..52e840c1 100644 --- a/src/main/manage/apis/tcyun.ts +++ b/src/main/manage/apis/tcyun.ts @@ -20,7 +20,7 @@ class TcyunApi { constructor(secretId: string, secretKey: string, logger: ManageLogger) { this.ctx = new COS({ SecretId: secretId, - SecretKey: secretKey + SecretKey: secretKey, }) this.logger = logger } @@ -36,7 +36,7 @@ class TcyunApi { isDir: true, checked: false, isImage: false, - match: false + match: false, } } @@ -51,7 +51,7 @@ class TcyunApi { checked: false, isImage: isImage(item.Key), match: false, - url: `${urlPrefix}/${item.Key}` + url: `${urlPrefix}/${item.Key}`, } } @@ -70,7 +70,7 @@ class TcyunApi { const { bucketName, region } = param const res = await this.ctx.getBucketDomain({ Bucket: bucketName, - Region: region + Region: region, }) if (res?.statusCode !== 200 || !res?.DomainRule?.length) return [] return res.DomainRule.filter((item: any) => item.Status === 'ENABLED').map(item => item.Name) @@ -91,7 +91,7 @@ class TcyunApi { const res = await this.ctx.putBucket({ ACL: configMap.acl, Bucket: configMap.BucketName, - Region: configMap.region + Region: configMap.region, }) return res?.statusCode === 200 } @@ -103,7 +103,7 @@ class TcyunApi { bucketConfig: { Location: region }, prefix, customUrl, - cancelToken + cancelToken, } = configMap const slicedPrefix = prefix.slice(1, prefix.length) const urlPrefix = customUrl || `https://${bucket}.cos.${region}.myqcloud.com` @@ -119,7 +119,7 @@ class TcyunApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } let res = {} as COS.GetBucketResult do { @@ -127,13 +127,13 @@ class TcyunApi { Bucket: bucket, Region: region, Prefix: slicedPrefix === '' ? undefined : slicedPrefix, - Marker: marker + Marker: marker, }) if (res?.statusCode === 200) { result.fullList.push( ...res.Contents.filter(item => parseInt(item.Size) !== 0).map(item => - this.formatFile(item, slicedPrefix, urlPrefix) - ) + this.formatFile(item, slicedPrefix, urlPrefix), + ), ) window.webContents.send(refreshDownloadFileTransferList, result) } else { @@ -157,7 +157,7 @@ class TcyunApi { bucketConfig: { Location: region }, prefix, customUrl, - cancelToken + cancelToken, } = configMap const slicedPrefix = prefix.slice(1, prefix.length) const urlPrefix = customUrl || `https://${bucket}.cos.${region}.myqcloud.com` @@ -174,7 +174,7 @@ class TcyunApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } do { res = await this.ctx.getBucket({ @@ -182,14 +182,14 @@ class TcyunApi { Region: region, Prefix: slicedPrefix === '' ? undefined : slicedPrefix, Delimiter: '/', - Marker: marker + Marker: marker, }) if (res?.statusCode === 200) { result.fullList.push( ...res.CommonPrefixes.map(item => this.formatFolder(item, slicedPrefix, urlPrefix)), ...res.Contents.filter(item => parseInt(item.Size) !== 0).map(item => - this.formatFile(item, slicedPrefix, urlPrefix) - ) + this.formatFile(item, slicedPrefix, urlPrefix), + ), ) window.webContents.send('refreshFileTransferList', result) } else { @@ -228,7 +228,7 @@ class TcyunApi { prefix, customUrl, marker, - itemsPerPage + itemsPerPage, } = configMap const slicedPrefix = prefix.slice(1) const urlPrefix = customUrl || `https://${bucket}.cos.${region}.myqcloud.com` @@ -238,26 +238,26 @@ class TcyunApi { Prefix: slicedPrefix === '' ? undefined : slicedPrefix, Delimiter: '/', Marker: marker, - MaxKeys: itemsPerPage + MaxKeys: itemsPerPage, })) as COS.GetBucketResult if (res?.statusCode !== 200) { return { fullList: [], isTruncated: false, nextMarker: '', - success: false + success: false, } } const result = { fullList: [ ...res.CommonPrefixes.map(item => this.formatFolder(item, slicedPrefix, urlPrefix)), ...res.Contents.filter(item => parseInt(item.Size) !== 0).map(item => - this.formatFile(item, slicedPrefix, urlPrefix) - ) + this.formatFile(item, slicedPrefix, urlPrefix), + ), ], isTruncated: res.IsTruncated === 'true', nextMarker: res.NextMarker || '', - success: true + success: true, } return result } @@ -278,7 +278,7 @@ class TcyunApi { Bucket: bucketName, Region: region, Key: newKey, - CopySource: handleUrlEncode(`${bucketName}.cos.${region}.myqcloud.com/${oldKey}`) + CopySource: handleUrlEncode(`${bucketName}.cos.${region}.myqcloud.com/${oldKey}`), }) if (copyRes?.statusCode !== 200) return false @@ -286,7 +286,7 @@ class TcyunApi { const deleteRes = await this.ctx.deleteObject({ Bucket: bucketName, Region: region, - Key: oldKey + Key: oldKey, }) return deleteRes?.statusCode === 204 @@ -306,7 +306,7 @@ class TcyunApi { const res = await this.ctx.deleteObject({ Bucket: bucketName, Region: region, - Key: key + Key: key, }) return res?.statusCode === 204 } @@ -321,7 +321,7 @@ class TcyunApi { let res: any const allFileList = { CommonPrefixes: [] as any[], - Contents: [] as any[] + Contents: [] as any[], } do { res = await this.ctx.getBucket({ @@ -330,7 +330,7 @@ class TcyunApi { Prefix: key, Delimiter: '/', MaxKeys: 1000, - Marker: marker + Marker: marker, }) if (res?.statusCode !== 200) return false @@ -344,7 +344,7 @@ class TcyunApi { !(await this.deleteBucketFolder({ bucketName, region, - key: item.Prefix + key: item.Prefix, })) ) { return false @@ -355,7 +355,7 @@ class TcyunApi { const res = await this.ctx.deleteMultipleObject({ Bucket: bucketName, Region: region, - Objects: allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => ({ Key: item.Key })) + Objects: allFileList.Contents.slice(i * 1000, (i + 1) * 1000).map((item: any) => ({ Key: item.Key })), }) if (res?.statusCode !== 200) return false } @@ -381,9 +381,9 @@ class TcyunApi { Region: region, Key: key, Expires: expires, - Sign: true + Sign: true, }, - () => {} + () => {}, ) return customUrl ? `${customUrl.replace(/\/+$/, '')}/${key}${res.slice(res.indexOf('?'))}` : res } @@ -417,7 +417,7 @@ class TcyunApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: bucketName, - targetFileRegion: region + targetFileRegion: region, }) files.push({ Bucket: bucketName, @@ -432,7 +432,7 @@ class TcyunApi { id, progress: Math.floor(progress.percent * 100), status: uploadTaskSpecialStatus.uploading, - cancelToken + cancelToken, }) }, onFileFinish: (err: any, data: any) => { @@ -442,27 +442,27 @@ class TcyunApi { progress: 100, status: uploadTaskSpecialStatus.uploaded, response: typeof data === 'object' ? JSON.stringify(data) : String(data), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } else { this.logger.error( formatError(err, { method: 'uploadBucketFile', - class: 'TcyunApi' - }) + class: 'TcyunApi', + }), ) instance.updateUploadTask({ id, progress: 0, status: commonTaskStatus.failed, response: typeof err === 'object' ? JSON.stringify(err) : String(err), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } - } + }, }) this.ctx.uploadFiles({ - files + files, }) } return true @@ -478,7 +478,7 @@ class TcyunApi { Bucket: bucketName, Region: region, Key: key, - Body: '' + Body: '', }) return res?.statusCode === 200 } @@ -507,7 +507,7 @@ class TcyunApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: path.join(downloadPath, fileName) + targetFilePath: path.join(downloadPath, fileName), }) fs.ensureDirSync(path.dirname(path.join(downloadPath, fileName))) this.ctx @@ -522,9 +522,9 @@ class TcyunApi { instance.updateDownloadTask({ id, progress: Math.floor(progress.percent * 100), - status: downloadTaskSpecialStatus.downloading + status: downloadTaskSpecialStatus.downloading, }) - } + }, }) .then((res: any) => { instance.updateDownloadTask({ @@ -532,22 +532,22 @@ class TcyunApi { progress: res && res.statusCode === 200 ? 100 : 0, status: res && res.statusCode === 200 ? downloadTaskSpecialStatus.downloaded : commonTaskStatus.failed, response: typeof res === 'object' ? JSON.stringify(res) : String(res), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) }) .catch((err: any) => { this.logger.error( formatError(err, { method: 'downloadBucketFile', - class: 'TcyunApi' - }) + class: 'TcyunApi', + }), ) instance.updateDownloadTask({ id, progress: 0, status: commonTaskStatus.failed, response: typeof err === 'object' ? JSON.stringify(err) : String(err), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) }) } diff --git a/src/main/manage/apis/upyun.ts b/src/main/manage/apis/upyun.ts index dfc8da58..39f4451b 100644 --- a/src/main/manage/apis/upyun.ts +++ b/src/main/manage/apis/upyun.ts @@ -16,7 +16,7 @@ import { gotUpload, hmacSha1Base64, md5, - NewDownloader + NewDownloader, } from '~/manage/utils/common' import { ManageLogger } from '~/manage/utils/logger' import { isImage } from '~/utils/common' @@ -40,7 +40,7 @@ class UpyunApi { password: string, logger: ManageLogger, antiLeechToken?: string, - expireTime?: number + expireTime?: number, ) { this.ser = new Upyun.Service(bucket, operator, password) this.cli = new Upyun.Client(this.ser) @@ -78,7 +78,7 @@ class UpyunApi { checked: false, isImage: false, match: false, - Key: key + Key: key, } } @@ -98,14 +98,14 @@ class UpyunApi { match: false, isImage: isImage(item.name), url, - key + key, } } 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}` : ''}` + `${method.toUpperCase()}&${encodeURI(uri)}&${new Date().toUTCString()}${contentMd5 ? `&${contentMd5}` : ''}`, )}` } @@ -132,7 +132,7 @@ class UpyunApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } const folderQueue = [prefix] const getFolderFile = async (folder: any) => { @@ -141,7 +141,7 @@ class UpyunApi { do { res = await this.cli.listDir(key, { limit: 10000, - iter: marker + iter: marker, }) if (res) { res.files?.forEach((item: any) => { @@ -185,12 +185,12 @@ class UpyunApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } do { res = await this.cli.listDir(prefix, { limit: 10000, - iter: marker + iter: marker, }) if (res) { res.files?.forEach((item: any) => { @@ -236,11 +236,11 @@ class UpyunApi { fullList: [] as any, isTruncated: false, nextMarker: '', - success: false + success: false, } res = await this.cli.listDir(prefix, { limit: itemsPerPage, - iter: marker || '' + iter: marker || '', }) if (res) { res.files?.forEach((item: any) => { @@ -278,12 +278,12 @@ class UpyunApi { Authorization: authorization, 'X-Upyun-Move-Source': xUpyunMoveSource, 'Content-Length': 0, - Date: new Date().toUTCString() + Date: new Date().toUTCString(), } const res = await axios({ method, url: `http://v0.api.upyun.com${uri}`, - headers + headers, }) return res.status === 200 } @@ -313,24 +313,24 @@ class UpyunApi { let isTruncated const allFileList = { CommonPrefixes: [] as any[], - Contents: [] as any[] + Contents: [] as any[], } do { const res = await this.cli.listDir(key, { limit: 10000, - iter: marker + iter: marker, }) if (res) { res.files.forEach((item: any) => { item.type === 'N' && allFileList.Contents.push({ ...item, - key: `${key}${item.name}` + key: `${key}${item.name}`, }) item.type === 'F' && allFileList.CommonPrefixes.push({ ...item, - key: `${key}${item.name}/` + key: `${key}${item.name}/`, }) }) marker = res.next @@ -351,7 +351,7 @@ class UpyunApi { if (allFileList.CommonPrefixes.length > 0) { for (const item of allFileList.CommonPrefixes) { const res = await this.deleteBucketFolder({ - key: item.key + key: item.key, }) if (!res) { return false @@ -390,7 +390,7 @@ class UpyunApi { sourceFilePath: filePath, targetFilePath: key, targetFileBucket: bucketName, - targetFileRegion: region + targetFileRegion: region, }) const date = new Date().toUTCString() const uri = `/${key}` @@ -400,7 +400,7 @@ class UpyunApi { 'save-key': uri, expiration: Math.floor(Date.now() / 1000) + 2592000, date, - 'content-length': fileSize + 'content-length': fileSize, } const base64Policy = Buffer.from(JSON.stringify(uplpadPolicy)).toString('base64') const stringToSign = `${method}&/${bucketName}&${date}&${base64Policy}` @@ -411,7 +411,7 @@ class UpyunApi { form.append('authorization', authorization) form.append('file', fs.createReadStream(filePath), { filename: path.basename(key), - contentType: getFileMimeType(fileName) + contentType: getFileMimeType(fileName), }) const headers = form.getHeaders() headers.Host = 'v0.api.upyun.com' @@ -452,7 +452,7 @@ class UpyunApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) const preSignedUrl = `${customUrl}/${key}` promises.push( @@ -465,7 +465,7 @@ class UpyunApi { reject(res) } }) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) diff --git a/src/main/manage/apis/webdavplist.ts b/src/main/manage/apis/webdavplist.ts index ed819eaa..61ea1f87 100644 --- a/src/main/manage/apis/webdavplist.ts +++ b/src/main/manage/apis/webdavplist.ts @@ -35,7 +35,7 @@ class WebdavplistApi { sslEnabled: boolean, proxy: string | undefined, authType: 'basic' | 'digest' | undefined, - logger: ManageLogger + logger: ManageLogger, ) { this.endpoint = formatEndpoint(endpoint, sslEnabled) this.username = username @@ -52,7 +52,7 @@ class WebdavplistApi { maxBodyLength: 4 * 1024 * 1024 * 1024, maxContentLength: 4 * 1024 * 1024 * 1024, httpsAgent: sslEnabled ? this.agent : undefined, - httpAgent: !sslEnabled ? this.agent : undefined + httpAgent: !sslEnabled ? this.agent : undefined, } if (this.authType === 'digest') { options.authType = AuthType.Digest @@ -75,7 +75,7 @@ class WebdavplistApi { checked: false, isImage: false, match: false, - url: isWebPath ? urlPrefix : `${urlPrefix}${item.filename}` + url: isWebPath ? urlPrefix : `${urlPrefix}${item.filename}`, } } @@ -92,7 +92,7 @@ class WebdavplistApi { checked: false, match: false, isImage: isImage(item.basename), - url: isWebPath ? urlPrefix : `${urlPrefix}${item.filename}` + url: isWebPath ? urlPrefix : `${urlPrefix}${item.filename}`, } } @@ -113,12 +113,12 @@ class WebdavplistApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { res = await this.ctx.getDirectoryContents(prefix, { deep: true, - details: true + details: true, }) if (this.isRequestSuccess(res.status)) { if (res.data?.length) { @@ -158,12 +158,12 @@ class WebdavplistApi { const result = { fullList: [] as any, success: false, - finished: false + finished: false, } try { res = await this.ctx.getDirectoryContents(prefix, { deep: false, - details: true + details: true, }) if (this.isRequestSuccess(res.status)) { if (res.data?.length) { @@ -263,7 +263,7 @@ class WebdavplistApi { targetFilePath: key, targetFileBucket: bucketName, targetFileRegion: region, - noProgress: true + noProgress: true, }) this.ctx .putFileContents(key, this.authType === 'digest' ? fs.readFileSync(filePath) : fs.createReadStream(filePath), { @@ -272,9 +272,9 @@ class WebdavplistApi { instance.updateUploadTask({ id, progress: Math.floor((progressEvent.loaded / progressEvent.total) * 100), - status: uploadTaskSpecialStatus.uploading + status: uploadTaskSpecialStatus.uploading, }) - } + }, }) .then((res: boolean) => { if (res) { @@ -282,14 +282,14 @@ class WebdavplistApi { id, progress: 100, status: uploadTaskSpecialStatus.uploaded, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } else { instance.updateUploadTask({ id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) } }) @@ -299,7 +299,7 @@ class WebdavplistApi { id, progress: 0, status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) }) } @@ -311,7 +311,7 @@ class WebdavplistApi { let result = false try { await this.ctx.createDirectory(key, { - recursive: true + recursive: true, }) result = true } catch (error) { @@ -336,16 +336,16 @@ class WebdavplistApi { progress: 0, status: commonTaskStatus.queuing, sourceFileName: fileName, - targetFilePath: savedFilePath + targetFilePath: savedFilePath, }) let preSignedUrl = await this.getPreSignedUrl({ - key + key, }) let headers = {} as IStringKeyMap if (this.authType === 'basic' || !this.authType) { const base64Str = Buffer.from(`${this.username}:${this.password}`).toString('base64') headers = { - Authorization: `Basic ${base64Str}` + Authorization: `Basic ${base64Str}`, } } else if (this.authType === 'digest') { const authHeader = await getAuthHeader( @@ -353,10 +353,10 @@ class WebdavplistApi { this.endpoint, `/${key.replace(/^\/+/, '')}`, this.username, - this.password + this.password, ) headers = { - Authorization: authHeader + Authorization: authHeader, } preSignedUrl = `${this.endpoint}/${key.replace(/^\/+/, '')}` } @@ -370,9 +370,9 @@ class WebdavplistApi { } else { reject(res) } - } + }, ) - }) + }), ) } const pool = new ConcurrencyPromisePool(maxDownloadFileCount) diff --git a/src/main/manage/datastore/db.ts b/src/main/manage/datastore/db.ts index 16482f72..5a414bf5 100644 --- a/src/main/manage/datastore/db.ts +++ b/src/main/manage/datastore/db.ts @@ -14,7 +14,7 @@ class ManageDB { this.#db = new JSONStore(this.#ctx.configPath) const initParams: IStringKeyMap = { picBed: {}, - settings: {} + settings: {}, } for (const key in initParams) { if (!this.#db.has(key)) { diff --git a/src/main/manage/datastore/dbChecker.ts b/src/main/manage/datastore/dbChecker.ts index c02d9c03..dbde712d 100644 --- a/src/main/manage/datastore/dbChecker.ts +++ b/src/main/manage/datastore/dbChecker.ts @@ -18,7 +18,7 @@ let hasCheckPath = false const errorMsg = { broken: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT'), - brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP') + brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP'), } function manageDbChecker() { @@ -30,30 +30,30 @@ function manageDbChecker() { let configFile: string = '{}' const optionsTpl = { title: $t('TIPS_NOTICE'), - body: '' + body: '', } // config save bak try { configFile = fs.readFileSync(manageConfigFilePath, { encoding: 'utf-8' }) JSON.parse(configFile) - } catch (e) { + } catch (_e) { fs.unlinkSync(manageConfigFilePath) if (fs.existsSync(manageConfigFileBackupPath)) { try { configFile = fs.readFileSync(manageConfigFileBackupPath, { - encoding: 'utf-8' + encoding: 'utf-8', }) JSON.parse(configFile) writeFile.sync(manageConfigFilePath, configFile, { - encoding: 'utf-8' + encoding: 'utf-8', }) const stats = fs.statSync(manageConfigFileBackupPath) optionsTpl.body = `${errorMsg.brokenButBackup}\n${$t('TIPS_PICGO_BACKUP_FILE_VERSION', { - v: dayjs(stats.mtime).format('YYYY-MM-DD HH:mm:ss') + v: dayjs(stats.mtime).format('YYYY-MM-DD HH:mm:ss'), })}` notificationList.push(optionsTpl) return - } catch (e) { + } catch (_e) { optionsTpl.body = errorMsg.broken notificationList.push(optionsTpl) return @@ -64,7 +64,7 @@ function manageDbChecker() { return } writeFile.sync(manageConfigFileBackupPath, configFile, { - encoding: 'utf-8' + encoding: 'utf-8', }) } } @@ -85,7 +85,7 @@ function managePathChecker(): string { } try { const configString = fs.readFileSync(defaultManageConfigPath, { - encoding: 'utf-8' + encoding: 'utf-8', }) const config = JSON.parse(configString) const userConfigPath: string = config.configPath || '' @@ -102,7 +102,7 @@ function managePathChecker(): string { if (!hasCheckPath) { const optionsTpl = { title: $t('TIPS_NOTICE'), - body: $t('TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR') + body: $t('TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR'), } notificationList?.push(optionsTpl) hasCheckPath = true diff --git a/src/main/manage/datastore/upDownTaskQueue.ts b/src/main/manage/datastore/upDownTaskQueue.ts index 4f3bb26a..d3e43c60 100644 --- a/src/main/manage/datastore/upDownTaskQueue.ts +++ b/src/main/manage/datastore/upDownTaskQueue.ts @@ -108,7 +108,7 @@ class UpDownTaskQueue { item => item.status !== uploadTaskSpecialStatus.uploaded && item.status !== commonTaskStatus.canceled && - item.status !== commonTaskStatus.failed + item.status !== commonTaskStatus.failed, ) } @@ -117,7 +117,7 @@ class UpDownTaskQueue { item => item.status !== downloadTaskSpecialStatus.downloaded && item.status !== commonTaskStatus.canceled && - item.status !== commonTaskStatus.failed + item.status !== commonTaskStatus.failed, ) } @@ -137,8 +137,8 @@ class UpDownTaskQueue { this.persistPath, JSON.stringify({ uploadTaskQueue: this.uploadTaskQueue, - downloadTaskQueue: this.downloadTaskQueue - }) + downloadTaskQueue: this.downloadTaskQueue, + }), ) } catch (e) { console.log(e) @@ -151,7 +151,7 @@ class UpDownTaskQueue { const persistData = JSON.parse(fs.readFileSync(this.persistPath, { encoding: 'utf-8' })) this.uploadTaskQueue = persistData.uploadTaskQueue this.downloadTaskQueue = persistData.downloadTaskQueue - } catch (e) { + } catch (_e) { this.uploadTaskQueue = [] this.downloadTaskQueue = [] } @@ -163,19 +163,19 @@ class UpDownTaskQueue { this.persistPath, JSON.stringify({ uploadTaskQueue: this.uploadTaskQueue, - downloadTaskQueue: this.downloadTaskQueue - }) + downloadTaskQueue: this.downloadTaskQueue, + }), ) } try { JSON.parse(fs.readFileSync(this.persistPath, { encoding: 'utf-8' })) - } catch (e) { + } catch (_e) { fs.writeFileSync( this.persistPath, JSON.stringify({ uploadTaskQueue: this.uploadTaskQueue, - downloadTaskQueue: this.downloadTaskQueue - }) + downloadTaskQueue: this.downloadTaskQueue, + }), ) } } diff --git a/src/main/manage/manageApi.ts b/src/main/manage/manageApi.ts index 29a92e3d..e6ac8e97 100644 --- a/src/main/manage/manageApi.ts +++ b/src/main/manage/manageApi.ts @@ -37,7 +37,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { 's3plist', 'webdavplist', 'local', - 'sftp' + 'sftp', ] private readonly CLOUD_STORAGE_CLIENTS = ['tcyun', 'aliyun', 'qiniu', 's3plist'] @@ -51,7 +51,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { 's3plist', 'webdavplist', 'local', - 'sftp' + 'sftp', ] private readonly FILE_LIST_CLIENTS = ['tcyun', 'aliyun', 'qiniu', 'upyun', 'smms', 's3plist'] @@ -70,7 +70,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { return { class: 'ManageApi', method, - picbedName: this.currentPicBedConfig.picBedName + picbedName: this.currentPicBedConfig.picBedName, } } @@ -86,14 +86,14 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.currentPicBedConfig.token, this.currentPicBedConfig.githubUsername, this.currentPicBedConfig.proxy, - this.logger + this.logger, ), imgur: () => new API.ImgurApi( this.currentPicBedConfig.imgurUserName, this.currentPicBedConfig.accessToken, this.currentPicBedConfig.proxy, - this.logger + this.logger, ), local: () => new API.LocalApi(this.logger), qiniu: () => new API.QiniuApi(this.currentPicBedConfig.accessKey, this.currentPicBedConfig.secretKey, this.logger), @@ -108,7 +108,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.currentPicBedConfig.proxy, this.logger, this.currentPicBedConfig.dogeCloudSupport || false, - this.currentPicBedConfig.bucketName || '' + this.currentPicBedConfig.bucketName || '', ), sftp: () => new API.SftpApi( @@ -120,7 +120,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.currentPicBedConfig.passphrase, this.currentPicBedConfig.fileMode, this.currentPicBedConfig.dirMode, - this.logger + this.logger, ), tcyun: () => new API.TcyunApi(this.currentPicBedConfig.secretId, this.currentPicBedConfig.secretKey, this.logger), upyun: () => @@ -130,7 +130,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.currentPicBedConfig.password, this.logger, this.currentPicBedConfig.antiLeechToken, - this.currentPicBedConfig.expireTime + this.currentPicBedConfig.expireTime, ), webdavplist: () => new API.WebdavplistApi( @@ -140,8 +140,8 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.currentPicBedConfig.sslEnabled, this.currentPicBedConfig.proxy, this.currentPicBedConfig.authType, - this.logger - ) + this.logger, + ), } createClient() { @@ -153,7 +153,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { supportedProviders: string[], method: string, operation: (client: any) => Promise, - defaultValue: T + defaultValue: T, ): Promise { if (!supportedProviders.includes(this.currentPicBedConfig.picBedName)) { return defaultValue @@ -171,7 +171,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { const window = windowManager.get(IWindowList.SETTING_WINDOW)! window.webContents.send(eventName, defaultResult) ipcMain.removeAllListeners( - eventName === refreshDownloadFileTransferList ? cancelDownloadLoadingFileList : 'cancelLoadingFileList' + eventName === refreshDownloadFileTransferList ? cancelDownloadLoadingFileList : 'cancelLoadingFileList', ) } @@ -244,7 +244,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { smms: [{ Name: 'smms', Location: 'smms', CreationDate: new Date().toISOString() }], webdavplist: [{ Name: 'webdav', Location: 'webdav', CreationDate: new Date().toISOString() }], local: [{ Name: 'local', Location: 'local', CreationDate: new Date().toISOString() }], - sftp: [{ Name: 'sftp', Location: 'sftp', CreationDate: new Date().toISOString() }] + sftp: [{ Name: 'sftp', Location: 'sftp', CreationDate: new Date().toISOString() }], } const staticResult = staticBuckets[this.currentPicBedConfig.picBedName as keyof typeof staticBuckets] @@ -262,7 +262,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { const staticDomains = { upyun: [this.currentPicBedConfig.customUrl], smms: ['https://smms.app'], - imgur: ['https://imgur.com'] + imgur: ['https://imgur.com'], } const staticResult = staticDomains[this.currentPicBedConfig.picBedName as keyof typeof staticDomains] @@ -277,7 +277,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.CLOUD_STORAGE_CLIENTS, 'createBucket', client => client.createBucket(param!), - false + false, ) } @@ -314,9 +314,9 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.ALL_CLIENTS, 'getBucketListRecursively', client => client.getBucketListRecursively(param!), - defaultResult + defaultResult, ) - } catch (error: any) { + } catch (_e: any) { this.sendDefaultResult(refreshDownloadFileTransferList, defaultResult) return {} } @@ -335,9 +335,9 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.ALL_CLIENTS, 'getBucketListBackstage', client => client.getBucketListBackstage(param!), - defaultResult + defaultResult, ) - } catch (error: any) { + } catch (_error: any) { this.sendDefaultResult('refreshFileTransferList', defaultResult) return {} } @@ -358,7 +358,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.FILE_LIST_CLIENTS, 'getBucketFileList', client => client.getBucketFileList(param!), - defaultResponse + defaultResponse, ) } @@ -367,7 +367,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.ALL_CLIENTS, 'deleteBucketFile', client => client.deleteBucketFile(param!), - false + false, ) } @@ -376,7 +376,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.FOLDER_SUPPORT_CLIENTS, 'deleteBucketFolder', client => client.deleteBucketFolder(param!), - false + false, ) } @@ -386,7 +386,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { supportedClients, 'renameBucketFile', client => client.renameBucketFile(param!), - false + false, ) } @@ -395,7 +395,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.ALL_CLIENTS, 'downloadBucketFile', client => client.downloadBucketFile(param!), - false + false, ) } @@ -408,7 +408,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.FOLDER_SUPPORT_CLIENTS, 'createBucketFolder', client => client.createBucketFolder(param!), - false + false, ) } @@ -417,7 +417,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { this.ALL_CLIENTS, 'uploadBucketFile', client => client.uploadBucketFile(param!), - false + false, ) } @@ -427,7 +427,7 @@ export class ManageApi extends EventEmitter implements IManageApiType { supportedClients, 'getPreSignedUrl', client => client.getPreSignedUrl(param!), - 'error' + 'error', ) } } diff --git a/src/main/manage/utils/common.ts b/src/main/manage/utils/common.ts index 90f8e8d9..6eed5a94 100644 --- a/src/main/manage/utils/common.ts +++ b/src/main/manage/utils/common.ts @@ -25,11 +25,11 @@ export const getFSFile = async (filePath: string, stream: boolean = false): Prom extension: path.extname(filePath), fileName: path.basename(filePath), buffer: stream ? fs.createReadStream(filePath) : await fs.readFile(filePath), - success: true + success: true, } - } catch (e) { + } catch (_e) { return { - success: false + success: false, } } } @@ -47,7 +47,7 @@ const getTempDirPath = () => { const checkTempFolderExist = async (tempPath: string) => { try { await fs.access(tempPath) - } catch (e) { + } catch (_e) { await fs.mkdir(tempPath) } } @@ -64,7 +64,7 @@ export const downloadFileFromUrl = async (urls: string[]) => { const res = await axios({ method: 'get', url, - responseType: 'stream' + responseType: 'stream', }) res.data.pipe(writer) await finishDownload(writer) @@ -87,7 +87,7 @@ export const NewDownloader = async ( savedFilePath: string, logger?: ManageLogger, proxy?: string, - headers?: any + headers?: any, ): Promise => { const options = { url: encodeURI(preSignedUrl), @@ -98,10 +98,10 @@ export const NewDownloader = async ( instance.updateDownloadTask({ id, progress: Math.floor(Number(percentage)), - status: downloadTaskSpecialStatus.downloading + status: downloadTaskSpecialStatus.downloading, }) }, - maxAttempts: 3 + maxAttempts: 3, } as any if (proxy) { options.proxy = proxy @@ -116,7 +116,7 @@ export const NewDownloader = async ( id, progress: 100, status: downloadTaskSpecialStatus.downloaded, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) return true } catch (e: any) { @@ -127,7 +127,7 @@ export const NewDownloader = async ( progress: 0, status: commonTaskStatus.failed, response: formatError(e, { method: 'NewDownloader' }), - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) return false } @@ -143,23 +143,23 @@ export const gotUpload = async ( logger?: ManageLogger, timeout: number = 30000, throwHttpErrors: boolean = false, - agent: any = {} + agent: any = {}, ) => { got(url, { headers, method, body, timeout: { - lookup: timeout + lookup: timeout, }, throwHttpErrors, - agent + agent, }) .on('uploadProgress', (progress: any) => { instance.updateUploadTask({ id, progress: Math.floor(progress.percent * 100), - status: uploadTaskSpecialStatus.uploading + status: uploadTaskSpecialStatus.uploading, }) }) .then((res: any) => { @@ -170,7 +170,7 @@ export const gotUpload = async ( res?.statusCode === 200 || res?.statusCode === 201 ? uploadTaskSpecialStatus.uploaded : commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) }) .catch((err: any) => { @@ -180,7 +180,7 @@ export const gotUpload = async ( progress: 0, response: formatError(err, { method: 'gotUpload' }), status: commonTaskStatus.failed, - finishTime: new Date().toLocaleString() + finishTime: new Date().toLocaleString(), }) }) } @@ -193,14 +193,14 @@ export const formatError = (err: any, params: IStringKeyMap) => { name: 'RequestError', code: err.code, stack: err.stack ?? '', - timings: err.timings ?? {} + timings: err.timings ?? {}, } } else if (err instanceof Error) { return { ...params, name: err.name ?? '', message: err.message ?? '', - stack: err.stack ?? '' + stack: err.stack ?? '', } } if (typeof err === 'object') { @@ -212,12 +212,12 @@ export const formatError = (err: any, params: IStringKeyMap) => { const commonOptions = { keepAlive: true, keepAliveMsecs: 1000, - scheduling: 'lifo' as 'lifo' | 'fifo' | undefined + scheduling: 'lifo' as 'lifo' | 'fifo' | undefined, } as any export const getAgent = ( proxy: any, - https: boolean = true + https: boolean = true, ): { https?: HttpsProxyAgent http?: HttpProxyAgent @@ -225,7 +225,7 @@ export const getAgent = ( const formatProxy = formatHttpProxy(proxy, 'string') as any const commonResult = { https: undefined, - http: undefined + http: undefined, } if (!formatProxy) return commonResult commonOptions.proxy = formatProxy.replace('127.0.0.1', 'localhost') @@ -233,16 +233,16 @@ export const getAgent = ( return { https: new HttpsProxyAgent({ ...commonOptions, - rejectUnauthorized: false + rejectUnauthorized: false, }), - http: undefined + http: undefined, } } return { http: new HttpProxyAgent({ - ...commonOptions + ...commonOptions, }), - https: undefined + https: undefined, } } @@ -255,14 +255,14 @@ export const getInnerAgent = (proxy: any, sslEnabled: boolean = true) => { ...commonOptions, rejectUnauthorized: false, host: formatProxy.host, - port: formatProxy.port - }) + port: formatProxy.port, + }), } : { agent: new https.Agent({ rejectUnauthorized: false, - keepAlive: true - }) + keepAlive: true, + }), } } return formatProxy @@ -270,13 +270,13 @@ export const getInnerAgent = (proxy: any, sslEnabled: boolean = true) => { agent: new http.Agent({ ...commonOptions, host: formatProxy.host, - port: formatProxy.port - }) + port: formatProxy.port, + }), } : { agent: new http.Agent({ - ...commonOptions - }) + ...commonOptions, + }), } } @@ -287,7 +287,7 @@ export function getOptions( responseType?: string, body?: any, timeout?: number, - proxy?: any + proxy?: any, ): OptionsOfTextResponseBody { return { ...(method && { method: method.toUpperCase() }), @@ -297,9 +297,9 @@ export function getOptions( ...(responseType && { responseType }), ...(timeout !== undefined ? { timeout: { request: timeout } } : { timeout: { request: 30000 } }), ...(proxy && { - agent: Object.fromEntries(Object.entries(getAgent(proxy)).filter(([, v]) => v !== undefined)) + agent: Object.fromEntries(Object.entries(getAgent(proxy)).filter(([, v]) => v !== undefined)), }), - throwHttpErrors: false + throwHttpErrors: false, } } diff --git a/src/main/manage/utils/dogeAPI.ts b/src/main/manage/utils/dogeAPI.ts index faacb30f..d7064b1e 100644 --- a/src/main/manage/utils/dogeAPI.ts +++ b/src/main/manage/utils/dogeAPI.ts @@ -17,7 +17,7 @@ export async function dogecloudApi( data = {}, jsonMode: boolean = false, accessKey: string, - secretKey: string + secretKey: string, ) { const body = jsonMode ? JSON.stringify(data) : querystring.encode(data) const sign = crypto @@ -33,14 +33,14 @@ export async function dogecloudApi( responseType: 'json', headers: { 'Content-Type': jsonMode ? 'application/json' : 'application/x-www-form-urlencoded', - Authorization: authorization - } + Authorization: authorization, + }, }) if (res.data.code !== 200) { throw new Error('API Error') } return res.data.data - } catch (err: any) { + } catch (_e: any) { throw new Error('API Error') } } @@ -55,23 +55,23 @@ export async function getTempToken(accessKey: string, secretKey: string): Promis '/auth/tmp_token.json', { channel: 'OSS_FULL', - scopes: ['*'] + scopes: ['*'], }, true, accessKey, - secretKey + secretKey, ) const token = data.Credentials picgo.saveConfig({ Credentials: { 'doge-token': { token, - expires: data.ExpiredAt * 1000 - } - } + expires: data.ExpiredAt * 1000, + }, + }, }) return token - } catch (err: any) { + } catch (_e: any) { return {} } } diff --git a/src/main/manage/utils/logger.ts b/src/main/manage/utils/logger.ts index abcb8c7d..7c676b11 100644 --- a/src/main/manage/utils/logger.ts +++ b/src/main/manage/utils/logger.ts @@ -17,7 +17,7 @@ export class ManageLogger implements ILogger { [ILogType.success]: 'green', [ILogType.info]: 'blue', [ILogType.warn]: 'yellow', - [ILogType.error]: 'red' + [ILogType.error]: 'red', } readonly #ctx: IManageApiType @@ -67,12 +67,12 @@ export class ManageLogger implements ILogger { return { isLarge: logFileSize > logFileSizeLimit, logFileSize, - logFileSizeLimit + logFileSizeLimit, } } fs.ensureFileSync(logPath) return { - isLarge: false + isLarge: false, } } diff --git a/src/main/server/index.ts b/src/main/server/index.ts index 723be8c7..be648fc7 100644 --- a/src/main/server/index.ts +++ b/src/main/server/index.ts @@ -21,20 +21,20 @@ const serverTempDir = path.join(appPath, 'serverTemp') fs.ensureDirSync(serverTempDir) const multerStorage = multer.diskStorage({ - destination: function (_req: any, _file: any, cb: (arg0: null, arg1: any) => void) { + destination(_req: any, _file: any, cb: (arg0: null, arg1: any) => void) { fs.ensureDirSync(serverTempDir) cb(null, serverTempDir) }, - filename: function (_req: any, file: { originalname: any }, cb: (arg0: null, arg1: any) => void) { + filename(_req: any, file: { originalname: any }, cb: (arg0: null, arg1: any) => void) { if (!/[^\u0000-\u00ff]/.test(file.originalname)) { file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8') } cb(null, file.originalname) - } + }, }) const uploadMulter = multer({ - storage: multerStorage + storage: multerStorage, }) class Server { @@ -85,8 +85,8 @@ class Server { response, statusCode: 404, body: { - success: false - } + success: false, + }, }) } else { const remoteAddress = request.socket.remoteAddress || 'unknown' @@ -109,8 +109,8 @@ class Server { response, body: { success: false, - message: 'Error processing formData' - } + message: 'Error processing formData', + }, }) } // @ts-expect-error since the multer type is not correct @@ -121,7 +121,7 @@ class Server { handler({ list, response, - urlparams: urlSP + urlparams: urlSP, }) } }) @@ -140,8 +140,8 @@ class Server { response, body: { success: false, - message: 'Not sending data in JSON format' - } + message: 'Not sending data in JSON format', + }, }) } logger.info('[PicList Server] get the request', body) @@ -149,7 +149,7 @@ class Server { handler!({ ...postObj, response, - urlparams: urlSP + urlparams: urlSP, }) }) } @@ -167,7 +167,7 @@ class Server { if (handler) { handler({ response, - urlparams: query ? new URLSearchParams(query) : undefined + urlparams: query ? new URLSearchParams(query) : undefined, }) } } @@ -186,7 +186,7 @@ class Server { await axios.post(ensureHTTPLink(`${this.#config.host}:${port}/heartbeat`)) logger.info(`[PicList Server] server is already running at ${port}`) this.shutdown(true) - } catch (e) { + } catch (_e) { logger.warn(`[PicList Server] ${port} is busy, trying with port ${(port as number) + 1}`) // fix a bug: not write an increase number to config file // to solve the auto number problem diff --git a/src/main/server/routerManager.ts b/src/main/server/routerManager.ts index e2689412..ca7f06e8 100644 --- a/src/main/server/routerManager.ts +++ b/src/main/server/routerManager.ts @@ -42,7 +42,7 @@ router.post( async ({ response, list = [], - urlparams + urlparams, }: { response: IHttpResponse list?: string[] @@ -58,8 +58,8 @@ router.post( response, body: { success: false, - message: 'server key is uncorrect' - } + message: 'server key is uncorrect', + }, }) return } @@ -99,7 +99,7 @@ router.post( const treatedFullResult = { isEncrypted: 1, EncryptedData: new AESHelper().encrypt(JSON.stringify(fullResult)), - ...fullResult + ...fullResult, } delete treatedFullResult.config handleResponse({ @@ -107,16 +107,16 @@ router.post( body: { success: true, result: [res], - fullResult: [treatedFullResult] - } + fullResult: [treatedFullResult], + }, }) } else { handleResponse({ response, body: { success: false, - message: errorMessage - } + message: errorMessage, + }, }) } } else { @@ -124,7 +124,7 @@ router.post( // upload with files const pathList = list.map(item => { return { - path: item + path: item, } }) const win = windowManager.getAvailableWindow() @@ -136,7 +136,7 @@ router.post( const treatedItem = { isEncrypted: 1, EncryptedData: new AESHelper().encrypt(JSON.stringify(item.fullResult)), - ...item.fullResult + ...item.fullResult, } delete treatedItem.config treatedItem.imgUrl = useShortUrl ? treatedItem.shortUrl || treatedItem.imgUrl : treatedItem.imgUrl @@ -149,16 +149,16 @@ router.post( body: { success: true, result: res, - fullResult - } + fullResult, + }, }) } else { handleResponse({ response, body: { success: false, - message: errorMessage - } + message: errorMessage, + }, }) } } @@ -172,11 +172,11 @@ router.post( response, body: { success: false, - message: errorMessage - } + message: errorMessage, + }, }) } - } + }, ) router.post( @@ -187,8 +187,8 @@ router.post( response, body: { success: false, - message: 'no file to delete' - } + message: 'no file to delete', + }, }) return } @@ -205,8 +205,8 @@ router.post( response, body: { success: !!successCount, - message: successCount ? `delete success: ${successCount}, fail: ${failCount}` : deleteErrorMessage - } + message: successCount ? `delete success: ${successCount}, fail: ${failCount}` : deleteErrorMessage, + }, }) } catch (err: any) { logger.error(err) @@ -214,11 +214,11 @@ router.post( response, body: { success: false, - message: deleteErrorMessage - } + message: deleteErrorMessage, + }, }) } - } + }, ) router.any('/heartbeat', async ({ response }: { response: IHttpResponse }) => { @@ -226,8 +226,8 @@ router.any('/heartbeat', async ({ response }: { response: IHttpResponse }) => { response, body: { success: true, - result: 'alive' - } + result: 'alive', + }, }) }) diff --git a/src/main/server/utils.ts b/src/main/server/utils.ts index e7606ca2..f15758c4 100644 --- a/src/main/server/utils.ts +++ b/src/main/server/utils.ts @@ -19,11 +19,11 @@ export const handleResponse = ({ 'Content-Type': 'application/json', 'access-control-allow-headers': '*', 'access-control-allow-methods': 'POST, GET, OPTIONS', - 'access-control-allow-origin': '*' + 'access-control-allow-origin': '*', }, body = { - success: false - } + success: false, + }, }: { response: IHttpResponse statusCode?: number @@ -55,7 +55,7 @@ export const deleteChoosedFiles = async (list: ImgInfo[]): Promise => const noteFunc = (value: boolean) => { const notification = new Notification({ title: $t('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'), - body: $t(value ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED' : 'GALLERY_SYNC_DELETE_NOTICE_FAILED') + body: $t(value ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED' : 'GALLERY_SYNC_DELETE_NOTICE_FAILED'), }) notification.show() } @@ -68,7 +68,7 @@ export const deleteChoosedFiles = async (list: ImgInfo[]): Promise => picgo.emit(ICOREBuildInEvent.REMOVE, [file], GuiApi.getInstance()) }, 500) result.push(true) - } catch (e) { + } catch (_e) { result.push(false) } } diff --git a/src/main/server/webServer/index.ts b/src/main/server/webServer/index.ts index 538d8cae..f80a31ca 100644 --- a/src/main/server/webServer/index.ts +++ b/src/main/server/webServer/index.ts @@ -383,13 +383,13 @@ function generateDirectoryListingHtml(files: any[], requestPath: string, fullPat ? new Date(fileInfo.mtime).toLocaleDateString('en-US', { year: '2-digit', month: 'numeric', - day: 'numeric' + day: 'numeric', }) + ' ' + new Date(fileInfo.mtime).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', - hour12: true + hour12: true, }) : '' @@ -454,7 +454,7 @@ function sortFiles(files: string[], fullPath: string): any[] { let stats try { stats = fs.statSync(filePath) - } catch (err) { + } catch (_e) { stats = null } @@ -462,7 +462,7 @@ function sortFiles(files: string[], fullPath: string): any[] { name: file, isDirectory: stats ? stats.isDirectory() : false, size: stats ? stats.size : 0, - mtime: stats ? stats.mtime : null + mtime: stats ? stats.mtime : null, } }) .sort((a, b) => { @@ -474,25 +474,25 @@ function sortFiles(files: string[], fullPath: string): any[] { }) } -function generateErrorPage(errorCode: number, errorMessage: string): string { - const errorDescriptions: { [key: number]: { title: string; description: string } } = { +function generateErrorPage(errorCode: number, _e: string): string { + const errorDescriptions: Record = { 404: { title: 'Page Not Found', - description: 'The file or directory you are looking for could not be found.' + description: 'The file or directory you are looking for could not be found.', }, 500: { title: 'Server Error', - description: 'An internal server error occurred while processing your request.' + description: 'An internal server error occurred while processing your request.', }, 403: { title: 'Access Denied', - description: 'You do not have permission to access this resource.' - } + description: 'You do not have permission to access this resource.', + }, } const error = errorDescriptions[errorCode] || { title: 'Unknown Error', - description: 'An unexpected error occurred.' + description: 'An unexpected error occurred.', } return ` @@ -622,7 +622,7 @@ function serveFile(res: http.ServerResponse, filePath: fs.PathLike) { const readStream = fs.createReadStream(filePath) const ext = path.extname(filePath.toString()).toLowerCase() - const contentTypes: { [key: string]: string } = { + const contentTypes: Record = { '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript', @@ -634,7 +634,7 @@ function serveFile(res: http.ServerResponse, filePath: fs.PathLike) { '.svg': 'image/svg+xml', '.pdf': 'application/pdf', '.txt': 'text/plain', - '.md': 'text/markdown' + '.md': 'text/markdown', } const contentType = contentTypes[ext] || 'application/octet-stream' @@ -662,7 +662,7 @@ class WebServer { enableWebServer: picgo.getConfig(configPaths.settings.enableWebServer) || false, webServerHost: picgo.getConfig(configPaths.settings.webServerHost) || '0.0.0.0', webServerPort: picgo.getConfig(configPaths.settings.webServerPort) || 37777, - webServerPath: picgo.getConfig(configPaths.settings.webServerPath) || defaultPath + webServerPath: picgo.getConfig(configPaths.settings.webServerPath) || defaultPath, } } @@ -678,7 +678,7 @@ class WebServer { } else { serveFile(res, filePath) } - } catch (err) { + } catch (_e) { logger.error(`File not found: ${filePath}`) res.writeHead(404, { 'Content-Type': 'text/html' }) res.end(generateErrorPage(404, 'The requested file or directory was not found')) @@ -694,9 +694,9 @@ class WebServer { this.#config.webServerHost, () => { logger.info( - `Web server is running at http://${this.#config.webServerHost}:${this.#config.webServerPort}, root path is ${this.#config.webServerPath}` + `Web server is running at http://${this.#config.webServerHost}:${this.#config.webServerPort}, root path is ${this.#config.webServerPath}`, ) - } + }, ) .on('error', err => { logger.error(err) diff --git a/src/main/utils/autoStart.ts b/src/main/utils/autoStart.ts index 0dd06418..36286750 100644 --- a/src/main/utils/autoStart.ts +++ b/src/main/utils/autoStart.ts @@ -8,7 +8,7 @@ export const setAutoStart = async (enable: boolean): Promise => { try { if (process.platform !== 'linux') { app.setLoginItemSettings({ - openAtLogin: enable + openAtLogin: enable, }) return } diff --git a/src/main/utils/beforeOpen.ts b/src/main/utils/beforeOpen.ts index 3c5e2ed2..f857236a 100644 --- a/src/main/utils/beforeOpen.ts +++ b/src/main/utils/beforeOpen.ts @@ -35,7 +35,7 @@ function copyFileOutsideOfElectronAsar(sourceInAsarArchive: string, destOutsideA fs.readdirSync(sourceInAsarArchive).forEach(function (fileOrFolderName) { copyFileOutsideOfElectronAsar( `${sourceInAsarArchive}/${fileOrFolderName}`, - `${destOutsideAsarArchive}/${fileOrFolderName}` + `${destOutsideAsarArchive}/${fileOrFolderName}`, ) }) } @@ -52,7 +52,7 @@ function resolveMacWorkFlow() { path .join(__dirname, '../../resources', 'Upload pictures with PicList.workflow') .replace('app.asar', 'app.asar.unpacked'), - dest + dest, ) } catch (e) { console.log(e) @@ -94,7 +94,7 @@ function resolveClipboardImageGenerator() { return files.map(item => { return { origin: path.join(__dirname, '../../resources', item).replace('app.asar', 'app.asar.unpacked'), - dest: path.join(CONFIG_DIR, item) + dest: path.join(CONFIG_DIR, item), } }) } @@ -110,7 +110,7 @@ function resolveOtherI18nFiles() { } i18nManager.setOutterI18nFolder(i18nFolder) const i18nFiles = fs.readdirSync(path.join(CONFIG_DIR, 'i18n'), { - withFileTypes: true + withFileTypes: true, }) i18nFiles.forEach(item => { if (item.isFile() && item.name?.endsWith('.yml')) { diff --git a/src/main/utils/clipboardPoll.ts b/src/main/utils/clipboardPoll.ts index 66c249d8..7f4da6fb 100644 --- a/src/main/utils/clipboardPoll.ts +++ b/src/main/utils/clipboardPoll.ts @@ -5,7 +5,6 @@ import logger from '@core/picgo/logger' import { clipboard, NativeImage } from 'electron' class ClipboardWatcher extends EventEmitter { - // eslint-disable-next-line no-undef timer: NodeJS.Timeout | null lastImageHash: string | null diff --git a/src/main/utils/common.ts b/src/main/utils/common.ts index 16774c6f..e7c5de7c 100644 --- a/src/main/utils/common.ts +++ b/src/main/utils/common.ts @@ -64,12 +64,12 @@ export const showNotification = ( body: '', clickToCopy: false, copyContent: '', - clickFn: () => {} - } + clickFn: () => {}, + }, ) => { const notification = new Notification({ title: options.title, - body: options.body + body: options.body, }) const handleClick = () => { if (options.clickToCopy) { @@ -141,8 +141,8 @@ const createC1NShortUrl = async (url: string) => { form.append('url', url) const res = await axios.post(c1nApi, form, { headers: { - token: c1nToken - } + token: c1nToken, + }, }) if (res.status >= 200 && res.status < 300 && res.data?.code === 0) { return res.data.data @@ -168,7 +168,7 @@ const createYOURLSShortLink = async (url: string) => { signature, action: 'shorturl', format: 'json', - url + url, }) try { const res = await axios.get(`${domain}/yourls-api.php?${params.toString()}`) @@ -222,7 +222,7 @@ const createShortUrlFromSink = async (url: string) => { const res = await axios.post( `${sinkDomain}/api/link/create`, { url }, - { headers: { Authorization: `Bearer ${sinkToken}` } } + { headers: { Authorization: `Bearer ${sinkToken}` } }, ) if (res.data?.link?.slug) { return `${sinkDomain}/${res.data.link.slug}` @@ -276,10 +276,10 @@ 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 + 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]) + 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] } } @@ -293,7 +293,7 @@ export const formatEndpoint = (endpoint: string, sslEnabled: boolean): string => export const formatHttpProxy = ( proxy: string | undefined, - type: 'object' | 'string' + type: 'object' | 'string', ): IHTTPProxy | undefined | string => { if (!proxy) return undefined if (/^https?:\/\//.test(proxy)) { @@ -303,7 +303,7 @@ export const formatHttpProxy = ( : { host: hostname, port: Number(port), - protocol: protocol.slice(0, -1) + protocol: protocol.slice(0, -1), } } const [host, port] = proxy.split(':') @@ -312,7 +312,7 @@ export const formatHttpProxy = ( : { host, port: port ? Number(port) : 80, - protocol: 'http' + protocol: 'http', } } diff --git a/src/main/utils/configPaths.ts b/src/main/utils/configPaths.ts index 571d1112..b8db68ec 100644 --- a/src/main/utils/configPaths.ts +++ b/src/main/utils/configPaths.ts @@ -17,14 +17,12 @@ import type { ITcYunConfig, IUploaderConfig, IUpYunConfig, - IWebdavPlistConfig + IWebdavPlistConfig, } from '#/types/types' export type manualPageOpenType = 'window' | 'browser' -interface IPicGoPlugins { - [key: `picgo-plugin-${string}`]: boolean -} +type IPicGoPlugins = Record<`picgo-plugin-${string}`, boolean> export interface IConfigStruct { picBed: { @@ -48,9 +46,7 @@ export interface IConfigStruct { [others: string]: any } settings: { - shortKey: { - [key: string]: IShortKeyConfig - } + shortKey: Record logLevel: string[] logPath: string logFileSizeLimit: number @@ -132,12 +128,12 @@ export const configPaths = { secondUploaderConfig: 'picBed.secondUploaderConfig', proxy: 'picBed.proxy', transformer: 'picBed.transformer', - list: 'picBed.list' + list: 'picBed.list', }, settings: { shortKey: { _path: 'settings.shortKey', - 'picgo:upload': 'settings.shortKey[picgo:upload]' + 'picgo:upload': 'settings.shortKey[picgo:upload]', }, logLevel: 'settings.logLevel', logPath: 'settings.logPath', @@ -192,7 +188,7 @@ export const configPaths = { autoImport: 'settings.autoImport', autoImportPicBed: 'settings.autoImportPicBed', galleryPicBedFilter: 'settings.galleryPicBedFilter', - enableSecondUploader: 'settings.enableSecondUploader' + enableSecondUploader: 'settings.enableSecondUploader', }, needReload: 'needReload', picgoPlugins: 'picgoPlugins', @@ -201,8 +197,8 @@ export const configPaths = { compress: 'buildIn.compress', watermark: 'buildIn.watermark', rename: 'buildIn.rename', - skipProcess: 'buildIn.skipProcess' + skipProcess: 'buildIn.skipProcess', }, debug: 'debug', - PICGO_ENV: 'PICGO_ENV' + PICGO_ENV: 'PICGO_ENV', } diff --git a/src/main/utils/deleteFunc.ts b/src/main/utils/deleteFunc.ts index cb99c509..03f062fc 100644 --- a/src/main/utils/deleteFunc.ts +++ b/src/main/utils/deleteFunc.ts @@ -33,7 +33,7 @@ const dogeRegionMap: IStringKeyMap = { 'ap-shanghai': '0', 'ap-beijing': '1', 'ap-guangzhou': '2', - 'ap-chengdu': '3' + 'ap-chengdu': '3', } async function dogecloudApi( @@ -41,7 +41,7 @@ async function dogecloudApi( data = {}, jsonMode: boolean = false, accessKey: string, - secretKey: string + secretKey: string, ) { const body = jsonMode ? JSON.stringify(data) : querystring.encode(data) const sign = crypto @@ -57,14 +57,14 @@ async function dogecloudApi( responseType: 'json', headers: { 'Content-Type': jsonMode ? 'application/json' : 'application/x-www-form-urlencoded', - Authorization: authorization - } + Authorization: authorization, + }, }) if (res.data.code !== 200) { throw new Error('API Error') } return res.data.data - } catch (err: any) { + } catch (_err: any) { throw new Error('API Error') } } @@ -75,11 +75,11 @@ async function getDogeToken(accessKey: string, secretKey: string): Promise item.name === bucketName || item.s3Bucket === bucketName) @@ -214,7 +214,7 @@ export async function removeFileFromDogeInMain(configMap: IStringKeyMap) { sessionToken: token.Credentials?.sessionToken, endpoint: bucket?.s3Endpoint, region: dogeRegionMap[bucket?.s3Endpoint?.split('.')[1] || 'ap-shanghai'], - bucketName: bucket?.s3Bucket + bucketName: bucket?.s3Bucket, } return await removeFileFromS3InMain(newConfigMap, true) } @@ -225,7 +225,7 @@ function createHuaweiAuthorization( fileName: string, accessKey: string, secretKey: string, - date: string = new Date().toUTCString() + 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') @@ -247,8 +247,8 @@ export async function removeFileFromHuaweiInMain(configMap: IStringKeyMap) { headers: { Host: `${bucketName}.${endpoint}`, Date: date, - Authorization: authorization - } + Authorization: authorization, + }, }) return res.status === 204 } diff --git a/src/main/utils/digestAuth.ts b/src/main/utils/digestAuth.ts index d48d76b0..4f84c2a8 100644 --- a/src/main/utils/digestAuth.ts +++ b/src/main/utils/digestAuth.ts @@ -17,7 +17,7 @@ export function digestAuthHeader( uri: string, wwwAuthenticate: string, username: string, - password: string + password: string, ) { const parts = wwwAuthenticate.split(',') const opts = {} as IStringKeyMap diff --git a/src/main/utils/enum.ts b/src/main/utils/enum.ts index 94c8f8ad..19007e56 100644 --- a/src/main/utils/enum.ts +++ b/src/main/utils/enum.ts @@ -2,7 +2,7 @@ export const ILogType = { success: 'success', info: 'info', warn: 'warn', - error: 'error' + error: 'error', } export const ICOREBuildInEvent = { @@ -16,7 +16,7 @@ export const ICOREBuildInEvent = { UNINSTALL: 'uninstall', UPDATE: 'update', NOTIFICATION: 'notification', - REMOVE: 'remove' + REMOVE: 'remove', } export const IPicGoHelperType = { @@ -24,7 +24,7 @@ export const IPicGoHelperType = { beforeTransformPlugins: 'beforeTransformPlugins', beforeUploadPlugins: 'beforeUploadPlugins', uploader: 'uploader', - transformer: 'transformer' + transformer: 'transformer', } export const IPasteStyle = { @@ -32,7 +32,7 @@ export const IPasteStyle = { HTML: 'HTML', URL: 'URL', UBB: 'UBB', - CUSTOM: 'Custom' + CUSTOM: 'Custom', } export const IWindowList = { @@ -40,7 +40,7 @@ export const IWindowList = { TRAY_WINDOW: 'TRAY_WINDOW', MINI_WINDOW: 'MINI_WINDOW', RENAME_WINDOW: 'RENAME_WINDOW', - TOOLBOX_WINDOW: 'TOOLBOX_WINDOW' + TOOLBOX_WINDOW: 'TOOLBOX_WINDOW', } export const IRemoteNoticeActionType = { @@ -49,22 +49,22 @@ export const IRemoteNoticeActionType = { SHOW_DIALOG: 'SHOW_DIALOG', // dialog notice COMMON: 'COMMON', VOID: 'VOID', // do nothing - SHOW_MESSAGE_BOX: 'SHOW_MESSAGE_BOX' + SHOW_MESSAGE_BOX: 'SHOW_MESSAGE_BOX', } export const IRemoteNoticeTriggerHook = { APP_START: 'APP_START', - SETTING_WINDOW_OPEN: 'SETTING_WINDOW_OPEN' + SETTING_WINDOW_OPEN: 'SETTING_WINDOW_OPEN', } export const IRemoteNoticeTriggerCount = { ONCE: 'ONCE', // default - ALWAYS: 'ALWAYS' + ALWAYS: 'ALWAYS', } export const IRPCType = { INVOKE: 'INVOKE', - SEND: 'SEND' + SEND: 'SEND', } export const IRPCActionType = { @@ -186,58 +186,58 @@ export const IRPCActionType = { 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' + 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' + HAS_PROBLEM_WITH_PROXY: 'HAS_PROBLEM_WITH_PROXY', } export const IToolboxItemCheckStatus = { INIT: 'init', LOADING: 'loading', SUCCESS: 'success', - ERROR: 'error' + ERROR: 'error', } export const ISartMode = { QUIET: 'quiet', MINI: 'mini', MAIN: 'main', - NO_TRAY: 'no-tray' + NO_TRAY: 'no-tray', } export const II18nLanguage = { ZH_CN: 'zh-CN', ZH_TW: 'zh-TW', - EN: 'en' + EN: 'en', } export const IShortUrlServer = { C1N: 'c1n', YOURLS: 'yourls', CFWORKER: 'cf_worker', - SINK: 'sink' + SINK: 'sink', } export const commonTaskStatus = { queuing: 'queuing', failed: 'failed', canceled: 'canceled', - paused: 'paused' + paused: 'paused', } // manage task status export const uploadTaskSpecialStatus = { uploading: 'uploading', - uploaded: 'uploaded' + uploaded: 'uploaded', } export const downloadTaskSpecialStatus = { downloading: 'downloading', - downloaded: 'downloaded' + downloaded: 'downloaded', } diff --git a/src/main/utils/getPicBeds.ts b/src/main/utils/getPicBeds.ts index dee37c16..21813e61 100644 --- a/src/main/utils/getPicBeds.ts +++ b/src/main/utils/getPicBeds.ts @@ -12,7 +12,7 @@ const getPicBeds = () => { return { type: item, name: picgo.helper.uploader.get(item)!.name || item, - visible: visible ? visible.visible : true + visible: visible ? visible.visible : true, } }) .sort(a => { diff --git a/src/main/utils/handleUploaderConfig.ts b/src/main/utils/handleUploaderConfig.ts index 83db1c21..2af94aea 100644 --- a/src/main/utils/handleUploaderConfig.ts +++ b/src/main/utils/handleUploaderConfig.ts @@ -6,7 +6,7 @@ import type { IPicGoPluginOriginConfig, IStringKeyMap, IUploaderConfigItem, - IUploaderConfigListItem + IUploaderConfigListItem, } from '#/types/types' import { setTrayToolTip, trimValues } from '~/utils/common' import { configPaths } from '~/utils/configPaths' @@ -30,7 +30,7 @@ export const completeUploaderMetaConfig = (originData: IStringKeyMap): IUploader ...trimValues(originData), _id: uuid(), _createdAt: Date.now(), - _updatedAt: Date.now() + _updatedAt: Date.now(), } } @@ -46,12 +46,12 @@ export const getPicBedConfig = (type: string) => { const config = handleConfigWithFunction(_config) return { config, - name + name, } } else { return { config: [], - name + name, } } } @@ -62,16 +62,16 @@ export const changeSecondUploader = (type: string, config?: IStringKeyMap, id?: } if (id) { picgo.saveConfig({ - [configPaths.picBed.secondUploaderId]: id + [configPaths.picBed.secondUploaderId]: id, }) } if (config) { picgo.saveConfig({ - [configPaths.picBed.secondUploaderConfig]: config + [configPaths.picBed.secondUploaderConfig]: config, }) } picgo.saveConfig({ - [configPaths.picBed.secondUploader]: type + [configPaths.picBed.secondUploader]: type, }) } @@ -81,17 +81,17 @@ export const changeCurrentUploader = (type: string, config?: IStringKeyMap, id?: } if (id) { picgo.saveConfig({ - [`uploader.${type}.defaultId`]: id + [`uploader.${type}.defaultId`]: id, }) } if (config) { picgo.saveConfig({ - [`picBed.${type}`]: config + [`picBed.${type}`]: config, }) } picgo.saveConfig({ [configPaths.picBed.current]: type, - [configPaths.picBed.uploader]: type + [configPaths.picBed.uploader]: type, }) setTrayToolTip(`${type} ${config?._configName || ''}`) } @@ -102,7 +102,7 @@ export const selectUploaderConfig = (type: string, id: string) => { if (config) { picgo.saveConfig({ [`uploader.${type}.defaultId`]: id, - [`picBed.${type}`]: config + [`picBed.${type}`]: config, }) } } @@ -111,7 +111,7 @@ export const getUploaderConfigList = (type: string): IUploaderConfigItem => { if (!type) { return { configList: [], - defaultId: '' + defaultId: '', } } const currentUploaderConfig = picgo.getConfig(`uploader.${type}`) ?? {} @@ -124,7 +124,7 @@ export const getUploaderConfigList = (type: string): IUploaderConfigItem => { } return { configList, - defaultId + defaultId, } } @@ -143,11 +143,11 @@ export const deleteUploaderConfig = (type: string, id: string): IUploaderConfigI changeCurrentUploader(type, updatedConfigList[0], updatedConfigList[0]._id) } picgo.saveConfig({ - [`uploader.${type}.configList`]: updatedConfigList + [`uploader.${type}.configList`]: updatedConfigList, }) return { configList: updatedConfigList, - defaultId: newDefaultId + defaultId: newDefaultId, } } @@ -155,7 +155,7 @@ export const deleteUploaderConfig = (type: string, id: string): IUploaderConfigI * upgrade old uploader config to new format */ export const upgradeUploaderConfig = ( - type: string + type: string, ): { configList: IStringKeyMap[] defaultId: string @@ -169,13 +169,13 @@ export const upgradeUploaderConfig = ( picgo.saveConfig({ [`uploader.${type}`]: { configList: uploaderConfigList, - defaultId: uploaderConfig._id + defaultId: uploaderConfig._id, }, - [`picBed.${type}`]: uploaderConfig + [`picBed.${type}`]: uploaderConfig, }) return { configList: uploaderConfigList, - defaultId: uploaderConfig._id + defaultId: uploaderConfig._id, } } @@ -186,7 +186,7 @@ export const updateUploaderConfig = (type: string, id: string, config: IStringKe let updatedDefaultId = defaultId if (existConfig) { updatedConfig = Object.assign(existConfig, trimValues(config), { - _updatedAt: Date.now() + _updatedAt: Date.now(), }) } else { updatedConfig = completeUploaderMetaConfig(config) @@ -196,7 +196,7 @@ export const updateUploaderConfig = (type: string, id: string, config: IStringKe picgo.saveConfig({ [`uploader.${type}.configList`]: configList, [`uploader.${type}.defaultId`]: updatedDefaultId, - [`picBed.${type}`]: updatedConfig + [`picBed.${type}`]: updatedConfig, }) } @@ -216,12 +216,12 @@ export const resetUploaderConfig = (type: string, id: string) => { } }) picgo.saveConfig({ - [`uploader.${type}.configList`]: configList + [`uploader.${type}.configList`]: configList, }) const currentDefault = picgo.getConfig(`picBed.${type}`) ?? {} if (currentDefault._id === id) { picgo.saveConfig({ - [`picBed.${type}`]: configList + [`picBed.${type}`]: configList, }) } } diff --git a/src/main/utils/pasteTemplate.ts b/src/main/utils/pasteTemplate.ts index 2a529298..1ccc57a2 100644 --- a/src/main/utils/pasteTemplate.ts +++ b/src/main/utils/pasteTemplate.ts @@ -11,7 +11,7 @@ export const formatCustomLink = (customLink: string, item: ImgInfo) => { const formatObj = { url, fileName, - extName + extName, } const keys = Object.keys(formatObj) as ['url', 'fileName', 'extName'] keys.forEach(item => { @@ -41,8 +41,8 @@ export default async (style: string, item: ImgInfo, customLink: string | undefin UBB: `[IMG]${url}[/IMG]`, Custom: formatCustomLink(_customLink, { ...item, - url - }) + url, + }), } return [tpl[style], useShortUrl ? url : ''] } diff --git a/src/main/utils/performanceOptimizer.ts b/src/main/utils/performanceOptimizer.ts index 8c751750..29467bc0 100644 --- a/src/main/utils/performanceOptimizer.ts +++ b/src/main/utils/performanceOptimizer.ts @@ -1,5 +1,4 @@ export class MemoryMonitor { - // eslint-disable-next-line no-undef private static interval: NodeJS.Timeout | null = null static start(intervalMs: number = 30000) { @@ -11,10 +10,10 @@ export class MemoryMonitor { 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) + external: Math.round(memUsage.external / 1024 / 1024), } console.log( - `[Memory] RSS: ${mbUsage.rss}MB, Heap: ${mbUsage.heapUsed}/${mbUsage.heapTotal}MB, External: ${mbUsage.external}MB` + `[Memory] RSS: ${mbUsage.rss}MB, Heap: ${mbUsage.heapUsed}/${mbUsage.heapTotal}MB, External: ${mbUsage.external}MB`, ) if (mbUsage.heapUsed / mbUsage.heapTotal > 0.8 && global.gc) { diff --git a/src/main/utils/sshClient.ts b/src/main/utils/sshClient.ts index ab84118e..88a4b476 100644 --- a/src/main/utils/sshClient.ts +++ b/src/main/utils/sshClient.ts @@ -29,14 +29,14 @@ class SSHClient { ? { username, privateKeyPath: privateKey, - passphrase: passphrase || undefined + passphrase: passphrase || undefined, } : { username, password } try { await SSHClient.client.connect({ host: config.host, port: Number(config.port) || 22, - ...loginInfo + ...loginInfo, }) this._isConnected = true return true @@ -53,7 +53,7 @@ class SSHClient { ? { username, privateKey: fs.readFileSync(privateKey), - passphrase: passphrase || undefined + passphrase: passphrase || undefined, } : { username, password } remote = this.changeWinStylePathToUnix(remote) @@ -66,23 +66,21 @@ class SSHClient { 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 + ...loginInfo, }) }) return (await promise) as boolean @@ -110,7 +108,7 @@ class SSHClient { remote = this.changeWinStylePathToUnix(remote) local = this.changeWinStylePathToUnix(local) await SSHClient.client.getFile(local, remote, undefined, { - concurrency: 1 + concurrency: 1, }) return true } catch (err: any) { @@ -125,7 +123,7 @@ class SSHClient { config: { fileMode?: string dirMode?: string - } = {} + } = {}, ): Promise { if (!this._isConnected) { throw new Error('SSH 未连接') @@ -150,7 +148,7 @@ class SSHClient { dirPath: string, config: { dirMode?: string - } = {} + } = {}, ): Promise { if (!this._isConnected) { throw new Error('SSH 未连接') diff --git a/src/main/utils/static.ts b/src/main/utils/static.ts index cb9481d2..9681b1ca 100644 --- a/src/main/utils/static.ts +++ b/src/main/utils/static.ts @@ -21,5 +21,5 @@ export const picBedsCanbeDeleted = [ 'smms', 'tcyun', 'upyun', - 'webdavplist' + 'webdavplist', ] diff --git a/src/main/utils/syncSettings.ts b/src/main/utils/syncSettings.ts index d0f29971..18d436ea 100644 --- a/src/main/utils/syncSettings.ts +++ b/src/main/utils/syncSettings.ts @@ -29,7 +29,7 @@ const getSyncConfig = () => { repo: '', branch: '', token: '', - proxy: '' + proxy: '', } ) } @@ -41,7 +41,7 @@ const getProxyagent = (proxy: string | undefined) => { keepAliveMsecs: 1000, rejectUnauthorized: false, proxy: proxy.replace('127.0.0.1', 'localhost'), - scheduling: 'lifo' + scheduling: 'lifo', }) : undefined } @@ -51,8 +51,8 @@ function getOctokit(syncConfig: ISyncConfig) { return new Octokit({ auth: token, request: { - agent: getProxyagent(proxy) - } + agent: getProxyagent(proxy), + }, }) } @@ -67,7 +67,7 @@ const isSyncConfigValidate = ({ webdavPassword, webdavAuthType, webdavSslEnabled, - webdavSavePath + webdavSavePath, }: ISyncConfig) => { if (type === 'webdav') { return ( @@ -92,7 +92,7 @@ async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const defaultConfig = { content: readFileAsBase64(localFilePath), message: uploadOrUpdateMsg(fileName, false), - branch + branch, } try { switch (type) { @@ -100,7 +100,7 @@ async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${fileName}` const res = await axios.post(url, { ...defaultConfig, - access_token: token + access_token: token, }) return isHttpResSuccess(res) } @@ -110,7 +110,7 @@ async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) { ...defaultConfig, owner: username, repo, - path: fileName + path: fileName, }) return isHttpResSuccess(res) } @@ -118,7 +118,7 @@ async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const { endpoint = '' } = syncConfig const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}` const headers = { - Authorization: `token ${token}` + Authorization: `token ${token}`, } const res = await axios.post(apiUrl, defaultConfig, { headers }) return isHttpResSuccess(res) @@ -130,12 +130,12 @@ async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) { webdavPassword, webdavAuthType = 'basic', webdavSslEnabled = true, - webdavSavePath = '' + webdavSavePath = '', } = syncConfig const webdavEndpointF = formatEndpoint(webdavEndpoint, webdavSslEnabled) const options: WebDAVClientOptions = { username: webdavUsername, - password: webdavPassword + password: webdavPassword, } if (webdavAuthType === 'digest') { options.authType = AuthType.Digest @@ -170,7 +170,7 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const defaultConfig = { branch, message: uploadOrUpdateMsg(fileName), - content: readFileAsBase64(localFilePath) + content: readFileAsBase64(localFilePath), } switch (type) { case 'gitee': { @@ -178,8 +178,8 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const shaRes = await axios.get(url, { params: { access_token: token, - ref: branch - } + ref: branch, + }, }) if (!isHttpResSuccess(shaRes)) { return false @@ -191,7 +191,7 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { repo, path: fileName, sha, - access_token: token + access_token: token, }) return isHttpResSuccess(res) } @@ -201,7 +201,7 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { owner: username, repo, path: fileName, - ref: branch + ref: branch, }) if (shaRes.status !== 200) { throw new Error('get sha failed') @@ -213,7 +213,7 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { owner: username, repo, path: fileName, - sha + sha, }) return res.status === 200 } @@ -221,10 +221,10 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { const { endpoint = '' } = syncConfig const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}` const headers = { - Authorization: `token ${token}` + Authorization: `token ${token}`, } const shaRes = await axios.get(apiUrl, { - headers + headers, }) if (!isHttpResSuccess(shaRes)) { throw new Error('get sha failed') @@ -235,11 +235,11 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { apiUrl, { ...defaultConfig, - sha + sha, }, { - headers - } + headers, + }, ) return isHttpResSuccess(res) } @@ -250,12 +250,12 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) { webdavPassword, webdavAuthType = 'basic', webdavSslEnabled = true, - webdavSavePath = '' + webdavSavePath = '', } = syncConfig const webdavEndpointF = formatEndpoint(webdavEndpoint, webdavSslEnabled) const options: WebDAVClientOptions = { username: webdavUsername, - password: webdavPassword + password: webdavPassword, } if (webdavAuthType === 'digest') { options.authType = AuthType.Digest @@ -287,7 +287,7 @@ async function uploadFile(fileName: string[]): Promise { let result = false try { result = await updateLocalToRemote(syncConfig, file) - } catch (error: any) { + } catch (_e: any) { result = await uploadLocalToRemote(syncConfig, file) } logger.info(`upload ${file} ${result ? 'success' : 'failed'}`) @@ -307,7 +307,7 @@ async function downloadAndWriteFile(url: string, localFilePath: string, config: if (isHttpResSuccess(res)) { await fs.writeFile( localFilePath, - isWriteJson ? JSON.stringify(res.data, null, 2) : Buffer.from(res.data.content, 'base64') + isWriteJson ? JSON.stringify(res.data, null, 2) : Buffer.from(res.data.content, 'base64'), ) return true } @@ -324,8 +324,8 @@ async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) return downloadAndWriteFile(url, localFilePath, { params: { access_token: token, - ref: branch - } + ref: branch, + }, }) } case 'github': { @@ -334,7 +334,7 @@ async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) owner: username, repo, path: fileName, - ref: branch + ref: branch, }) if (res.status === 200) { const data = res.data as any @@ -343,9 +343,9 @@ async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) downloadUrl, localFilePath, { - httpsAgent: getProxyagent(proxy) + httpsAgent: getProxyagent(proxy), }, - true + true, ) } return false @@ -355,11 +355,11 @@ async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}` return downloadAndWriteFile(apiUrl, localFilePath, { headers: { - Authorization: `token ${token}` + Authorization: `token ${token}`, }, params: { - ref: branch - } + ref: branch, + }, }) } case 'webdav': { @@ -369,12 +369,12 @@ async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) webdavPassword, webdavAuthType = 'basic', webdavSslEnabled = true, - webdavSavePath = '' + webdavSavePath = '', } = syncConfig const webdavEndpointF = formatEndpoint(webdavEndpoint, webdavSslEnabled) const options: WebDAVClientOptions = { username: webdavUsername, - password: webdavPassword + password: webdavPassword, } if (webdavAuthType === 'digest') { options.authType = AuthType.Digest diff --git a/src/main/utils/updateChecker.ts b/src/main/utils/updateChecker.ts index b9b44f9d..6c7413e5 100644 --- a/src/main/utils/updateChecker.ts +++ b/src/main/utils/updateChecker.ts @@ -12,7 +12,7 @@ const updateChecker = async () => { if (showTip) { try { await updater.autoUpdater.checkForUpdatesAndNotify() - } catch (err) {} + } catch (_err) {} } } diff --git a/src/main/utils/windowHelper.ts b/src/main/utils/windowHelper.ts index 9d366023..d5d86c84 100644 --- a/src/main/utils/windowHelper.ts +++ b/src/main/utils/windowHelper.ts @@ -31,7 +31,7 @@ export function openMiniWindow(hideSettingWindow: boolean = true) { miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]) db.set(configPaths.settings.miniWindowPosition, [ width - miniWindow.getSize()[0], - height - miniWindow.getSize()[1] + height - miniWindow.getSize()[1], ]) } else { miniWindow.setPosition(lastPosition[0], lastPosition[1]) diff --git a/src/preload/index.ts b/src/preload/index.ts index 67ddf192..346659cf 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -43,7 +43,7 @@ try { webFrame.setVisualZoomLevelLimits(min, max) }, clipboard: { - writeText: clipboard.writeText + writeText: clipboard.writeText, }, platform: process.platform, sendRpcSync, @@ -65,7 +65,7 @@ try { }, showFilePath(file: File) { return webUtils.getPathForFile(file) - } + }, }) contextBridge.exposeInMainWorld('node', { @@ -77,27 +77,27 @@ try { extname: path.extname, sep: path.sep, posix: { - sep: path.posix.sep - } + sep: path.posix.sep, + }, }, fs: { remove: fs.remove, readFile: fs.readFile, - statSync: fs.statSync + statSync: fs.statSync, }, crypto: { randomBytes: crypto.randomBytes, - createHash: crypto.createHash + createHash: crypto.createHash, }, yaml: { - load: yaml.load + load: yaml.load, }, mime: { - lookup: mime.getType + lookup: mime.getType, }, buffer: { - from: Buffer.from - } + from: Buffer.from, + }, }) } catch (error) { console.error(error) diff --git a/src/renderer/App.vue b/src/renderer/App.vue index 58fb704c..5be54410 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -40,7 +40,7 @@ onMounted(async () => { diff --git a/src/renderer/components/ImageLocal.vue b/src/renderer/components/ImageLocal.vue index 9132694c..00cb5a14 100644 --- a/src/renderer/components/ImageLocal.vue +++ b/src/renderer/components/ImageLocal.vue @@ -63,36 +63,36 @@ onBeforeMount(async () => { diff --git a/src/renderer/components/ImageWebdav.vue b/src/renderer/components/ImageWebdav.vue index cad61f83..b27ed14c 100644 --- a/src/renderer/components/ImageWebdav.vue +++ b/src/renderer/components/ImageWebdav.vue @@ -54,15 +54,15 @@ async function getWebdavHeader(key: string) { formatEndpoint(props.config.endpoint, props.config.sslEnabled || false), `/${key.replace(/^\//, '')}`, props.config.username, - props.config.password + props.config.password, ) headers = { - Authorization: authHeader + Authorization: authHeader, } } else { headers = { Authorization: - 'Basic ' + window.node.buffer.from(`${props.config.username}:${props.config.password}`).toString('base64') + 'Basic ' + window.node.buffer.from(`${props.config.username}:${props.config.password}`).toString('base64'), } } return headers @@ -107,36 +107,36 @@ onMounted(fetchImage) diff --git a/src/renderer/components/ui/TitleBar.vue b/src/renderer/components/ui/TitleBar.vue index d0909036..2b198fd5 100644 --- a/src/renderer/components/ui/TitleBar.vue +++ b/src/renderer/components/ui/TitleBar.vue @@ -89,21 +89,21 @@ onBeforeUnmount(() => { .title-bar { position: fixed; top: 0; - left: 0; right: 0; + left: 0; + z-index: 1000; + border-bottom: 1px solid var(--color-border); height: 32px; background: var(--color-background-secondary); - border-bottom: 1px solid var(--color-border); - z-index: 1000; -webkit-app-region: drag; } .title-bar-content { display: flex; - align-items: center; justify-content: space-between; - height: 100%; + align-items: center; padding: 0 16px; + height: 100%; } .title-left { @@ -132,11 +132,11 @@ onBeforeUnmount(() => { } .app-version { + border-radius: 4px; + padding: 2px 6px; font-size: 12px; color: var(--color-text-secondary); background: var(--color-border); - padding: 2px 6px; - border-radius: 4px; } .title-center { @@ -155,24 +155,24 @@ onBeforeUnmount(() => { } .progress-bar { - flex: 1; + overflow: hidden; + border-radius: 2px; height: 4px; background: var(--color-border); - border-radius: 2px; - overflow: hidden; + flex: 1; } .progress-fill { + border-radius: 2px; height: 100%; background: var(--color-success); - border-radius: 2px; transition: width 0.3s ease; } .progress-text { + min-width: 35px; font-size: 11px; color: var(--color-text-secondary); - min-width: 35px; } .title-right { @@ -189,21 +189,21 @@ onBeforeUnmount(() => { .control-button { display: flex; - align-items: center; justify-content: center; + align-items: center; + border: none; + border-radius: 4px; width: 28px; height: 20px; - border: none; - background: transparent; - border-radius: 4px; color: var(--color-text-secondary); - cursor: pointer; + background: transparent; transition: var(--transition); + cursor: pointer; } .control-button:hover { - background: var(--color-surface-elevated); color: var(--color-text-primary); + background: var(--color-surface-elevated); } .pin-button.active { @@ -212,7 +212,7 @@ onBeforeUnmount(() => { } .close-button:hover { - background: var(--color-danger); color: white; + background: var(--color-danger); } diff --git a/src/renderer/components/ui/UIServiceProvider.vue b/src/renderer/components/ui/UIServiceProvider.vue index 997ff621..64f27294 100644 --- a/src/renderer/components/ui/UIServiceProvider.vue +++ b/src/renderer/components/ui/UIServiceProvider.vue @@ -37,7 +37,7 @@ const confirmOptions = reactive({ confirmButtonText: 'Confirm', cancelButtonText: 'Cancel', showClose: true, - center: false + center: false, }) let confirmResolve: ((value: boolean) => void) | null = null @@ -67,7 +67,7 @@ const showConfirm = (options: ConfirmOptions): Promise => { cancelButtonText: 'Cancel', showClose: true, center: false, - ...options + ...options, }) confirmResolve = resolve confirmVisible.value = true @@ -82,20 +82,20 @@ onMounted(() => { success: messageRef.value.success, error: messageRef.value.error, warning: messageRef.value.warning, - info: messageRef.value.info + info: messageRef.value.info, }) } // Initialize confirm service const { setConfirmService } = useConfirm() setConfirmService({ - confirm: showConfirm + confirm: showConfirm, }) }) diff --git a/src/renderer/hooks/useAppStore.ts b/src/renderer/hooks/useAppStore.ts index 0ad962fc..2f499aaf 100644 --- a/src/renderer/hooks/useAppStore.ts +++ b/src/renderer/hooks/useAppStore.ts @@ -6,8 +6,8 @@ import type { IStringKeyMap } from '#/types/types' export const useAppStore = defineStore('app', () => { const settings = ref({ app: { - theme: 'light' - } + theme: 'light', + }, }) const loading = ref(false) const error = ref() @@ -77,6 +77,6 @@ export const useAppStore = defineStore('app', () => { clearError, setTheme, toggleTheme, - applyTheme + applyTheme, } }) diff --git a/src/renderer/hooks/useConfirm.ts b/src/renderer/hooks/useConfirm.ts index 37f36f20..b989d4ff 100644 --- a/src/renderer/hooks/useConfirm.ts +++ b/src/renderer/hooks/useConfirm.ts @@ -31,7 +31,7 @@ export function useConfirm() { return { setConfirmService, - confirm + confirm, } } diff --git a/src/renderer/hooks/useMessage.ts b/src/renderer/hooks/useMessage.ts index 19f2a908..7ddba0df 100644 --- a/src/renderer/hooks/useMessage.ts +++ b/src/renderer/hooks/useMessage.ts @@ -53,7 +53,7 @@ export function useMessage() { success, error, warning, - info + info, } } diff --git a/src/renderer/hooks/useVirtualGrid.ts b/src/renderer/hooks/useVirtualGrid.ts index e74f1d67..77221c53 100644 --- a/src/renderer/hooks/useVirtualGrid.ts +++ b/src/renderer/hooks/useVirtualGrid.ts @@ -25,7 +25,7 @@ export function useVirtualGrid(options: UseVirtualGridOptions) { itemsPerRow, totalRows, rowHeight, - totalHeight + totalHeight, } }) @@ -101,7 +101,7 @@ export function useVirtualGrid(options: UseVirtualGridOptions) { if (scrollTop.value > totalHeight - containerHeight.value) { scrollTop.value = Math.max(0, totalHeight - containerHeight.value) } - } + }, ) return { @@ -111,6 +111,6 @@ export function useVirtualGrid(options: UseVirtualGridOptions) { updateScrollTop, scrollToItem, scrollToTop, - scrollToBottom + scrollToBottom, } } diff --git a/src/renderer/i18n/locales/en.json b/src/renderer/i18n/locales/en.json index 9203c18c..fdbd1f6d 100644 --- a/src/renderer/i18n/locales/en.json +++ b/src/renderer/i18n/locales/en.json @@ -1,856 +1,308 @@ { "app": { "title": "PicList" }, - "titleBar": { "alwaysOnTop": "Always On Top", "close": "Close", "minimize": "Minimize", "miniWindow": "Mini Window" }, "common": { - "confirm": "Confirm", "cancel": "Cancel", "close": "Close", - "reset": "Reset", + "confirm": "Confirm", "import": "Import", + "reset": "Reset", "submit": "Submit" }, "navigation": { - "upload": "Upload", - "manage": "Manage", - "gallery": "Gallery", - "settings": "Settings", - "plugins": "Plugins", - "picbed": "PicBed", - "close": "Close", - "copyPicBedConfig": "Copy PicBed Config", - "selected": "Selected", - "moreOptions": "More Options", - "picBedQrCode": "PicBed QR Code", "choosePicBed": "Choose PicBed", - "selectPicBeds": "Select PicBeds", - "copySuccess": "Copy Success", + "close": "Close", "collapse": "Collapse Sidebar", - "expand": "Expand Sidebar" - }, - "settings": { - "theme": { - "light": "Light", - "dark": "Dark", - "auto": "Auto", - "lightDesc": "Light Mode", - "darkDesc": "Dark Mode", - "autoDesc": "Auto Mode", - "toggle": "Toggle Theme" - } + "copyPicBedConfig": "Copy PicBed Config", + "copySuccess": "Copy Success", + "expand": "Expand Sidebar", + "gallery": "Gallery", + "manage": "Manage", + "moreOptions": "More Options", + "picbed": "PicBed", + "picBedQrCode": "PicBed QR Code", + "plugins": "Plugins", + "selected": "Selected", + "selectPicBeds": "Select PicBeds", + "settings": "Settings", + "upload": "Upload" }, "pages": { - "upload": { - "uploadViewHint": "Click to open picbeds settings", - "imageProcessName": "Image Processing", - "changePicBed": "Change PicBed", - "dragFileToHere": "Drag file to here, or click to upload", - "dragValidPictureOrUrl": "Please drag a valid picture file or URL here", - "uploadHint": "All formats are supported, but images are recommended", - "uploadFailed": "Upload Failed", - "quickUpload": "Quick Upload", - "clipboardPicture": "Clipboard", - "clickToUpload": "Click to Upload", - "urlUpload": "URL Upload", - "inputUrlTip": "Please enter URL(s)", - "httpPrefixTip": "Starts with http:// or https://", - "multipleUrlsHint": "Each URL on a separate line for multiple uploads", - "inputValidUrl": "Please enter a valid URL", - "invalidUrlsFound": "Invalid URLs found: {urls}", - "uploadingMultipleUrls": "Uploading {count} URLs...", - "linkFormat": "Link Format", - "outputFormat": "Output Format", - "urlType": { "title": "Link Type", "normal": "Long Link", "short": "Short Link" } - }, - "imageProcess": { - "title": "Image Processing Settings", - "description": "Configure image processing options, including compression, watermarking, format conversion, etc.", - "generalSettings": "General", - "watermarkSettings": "Watermark", - "transformSettings": "Transform", - "cancel": "Cancel", - "confirm": "Confirm", - "general": { - "skipProcessExtList": "Skip Processed File Extensions", - "skipProcessExtListLabel": "Skip Processed Extensions", - "skipProcessExtListPlaceholder": "Enter file extensions to skip processing, separated by commas (e.g.: jpg,png,gif)", - "basicImageProcessing": "Basic Image Processing", - "isRemoveExif": "Remove Exif Information", - "quality": "Compression Quality (1-100)", - "formatConversion": "Image Format Conversion", - "isConvert": "Convert Format", - "destinationFormat": "Destination Format", - "specificFormatConversion": "Specific Format Conversion, please fill in JSON format, such as: {'{'}\"png\": \"jpg\"{'}'}" - }, - "watermark": { - "title": "Watermark Settings", - "description": "Add text or image watermark to the image", - "isAdd": "Enable or Disable Watermark", - "type": "Watermark Type", - "text": "Text", - "image": "Image", - "isFullScreen": "Enable Full Screen Watermark", - "degree": "Watermark Rotation Angle", - "scaleRatio": "Watermark Scale Ratio", - "inputText": "Watermark Text", - "inputTextPlaceholder": "Please enter watermark text", - "textFontPath": "Watermark Font Path (Automatically downloaded before first use)", - "textFontPathPlaceholder": "Optional, please enter path", - "color": "Watermark Color, manually enter or use color picker", - "imagePath": "Watermark Image Path (Leave empty to use default image)", - "imagePathPlaceholder": "Optional, please enter path", - "position": "Watermark Position", - "positionOptions": { - "top": "Top", - "bottom": "Bottom", - "left": "Left", - "right": "Right", - "topLeft": "Top Left", - "topRight": "Top Right", - "bottomLeft": "Bottom Left", - "bottomRight": "Bottom Right", - "center": "Center" - }, - "imageOpacity": "Watermark Opacity" - }, - "transform": { - "title": "Transform Settings", - "description": "Adjust image size, rotation, flipping, etc.", - "isFlip": "Vertical Flip", - "isFlop": "Horizontal Flip", - "rotationTitle": "Rotation Settings", - "rotationDescription": "Set image rotation parameters", - "isRotate": "Enable Rotation", - "rotationDegree": "Rotation Angle", - "resizeTitle": "Resize", - "resizeDescription": "Set image scaling parameters", - "isResize": "Enable Resize", - "resizeWidth": "Resize Width (0 means scale by height)", - "resizeHeight": "Resize Height (0 means scale by width)", - "skipResizeOfSmallImgHeight": "Skip resizing when image is smaller than set", - "percentageResize": "Resize by Percentage", - "isResizeByPercent": "Enable Resize by Percentage", - "isResizeByPercentHint": "Higher priority", - "resizePercent": "Resize Percentage (Enter 50 for 50%)" - }, - "perPicBed": { - "title": "Per-PicBed Settings", - "description": "Configure settings for each PicBed individually" - } - }, - "settings": { - "title": "Settings", - "description": "Configure the PicList application", - "docs": "Documentation", - "clickToSet": "Click to Set", - "clickToOpen": "Click to Open", - "system": { - "title": "General", - "languageAndAppearance": "Language and Appearance", - "chooseLanguage": "Choose Language", - "startMode": "Startup Mode", - "quietMode": "Quiet Mode", - "miniMode": "Mini Mode", - "mainMode": "Main Mode", - "noTrayMode": "No Tray Mode", - "windowBehavior": "Window Behavior", - "isHideDock": "Hide Dock Icon", - "hideDockHint": "Cannot hide both dock and tray at the same time", - "needRestart": "Requires restart to take effect", - "mainWindowSize": "Set Main Window Size (Requires Restart)", - "autoCloseMiniWindow": "Close Mini Window when Opening Main Window", - "autoCloseMainWindow": "Close Main Window when Opening Mini Window", - "miniWindowOnTop": "Mini Window On Top", - "isCustomMiniIcon": "Custom Mini Icon", - "customMiniIconPath": "Custom Mini Icon Path", - "startupAndShortcuts": "Startup and Shortcuts", - "autoLaunch": "Auto Launch", - "setShortCuts": "Set Shortcuts", - "setMainWindowSize": "Set Main Window Size (Requires Restart)", - "mainWindowHeight": "Main Window Height", - "mainWindowWidth": "Main Window Width", - "rawPicGoSize": "Original PicGo Window Size, 800x450", - "rawPicGoSizeHint": "Not recommended, only for compatibility with old PicGo window size" - }, - "sync": { - "title": "Sync", - "syncConfiguration": "Sync Configuration", - "syncEndpointConfig": "Sync Endpoint Configuration", - "upDownloadSettings": "Upload and Download Settings", - "uploadSettings": "Upload Settings", - "downloadSettings": "Download Settings", - "syncResult": { "success": "Sync Successful", "failed": "Sync Failed" }, - "commonConfig": "Common Configuration", - "manageConfig": "Manage Configuration", - "allConfig": "All Configuration", - "migrateFromPicGo": "Migrate from PicGo", - "mirgrateTitle": "Notification", - "mirgrateContent": "You are about to import configuration files and albums from PicGo, which will overwrite the current configuration files and albums. Do you want to continue?", - "mirgrateSuccess": "Import Successful, Please Restart PicList to Take Effect", - "mirgrateFailed": "Import Failed", - "fileManagement": "File Management", - "openConfigFile": "Open Configuration File", - "openConfigFileDir": "Open Configuration File Directory", - "syncConfigNote": "The files to be synced are configuration files", - "selectType": "Please select sync type", - "giteaHost": "Gitea Address", - "webdavEndpoint": "WebDAV Endpoint", - "gitea": { - "username": "Username", - "repo": "Repository Name", - "branch": "Branch Name", - "token": "Access Token" - }, - "github": { - "username": "GitHub Username", - "repo": "Private Repository Name", - "branch": "GitHub Branch Name", - "token": "GitHub Access Token" - }, - "gitee": { - "username": "Gitee Username", - "repo": "Gitee Repository Name", - "branch": "Gitee Branch Name", - "token": "Gitee Access Token" - }, - "webdav": { - "username": "WebDAV Username", - "password": "WebDAV Password", - "savePath": "WebDAV Save Path", - "authType": "WebDAV Auth Type", - "enableSSL": "Enable SSL/TLS" - }, - "syncConfigProxy": "Proxy" - }, - "upload": { - "title": "Upload", - "uploadBehavior": "Upload Behavior", - "autoImportInManage": "Auto Import Configuration in Management Page", - "autoImportInManageHint": "After enabling, the management page will automatically import the corresponding image bed configuration", - "autoImportPicBed": "Select the image bed to enable auto import", - "enableSecondPicBed": "Enable Second Image Bed Sync Upload", - "enableSecondPicBedHint": "After enabling, it will sync upload to the second image bed for backup", - "setSecondPicBed": "Set Second Image Bed", - "uploadProcessing": "Upload Processing", - "deleteCloud": "Sync delete cloud files when deleting in album", - "manualRname": "Manual Rename", - "timestampRname": "Timestamp Rename", - "advancedRname": "Advanced Rename", - "enableAdvancedRname": "Enable Advanced Rename", - "advancedRnameFormat": "Advanced Rename Format", - "availablePlaceholders": "Available Placeholders", - "copySuccess": "Copy Successful: {content}", - "placeholder": { - "categoryTime": "Time Related", - "categoryHash": "Hash Related", - "categoryFile": "File Related", - "year4": "Year, 4 Digits", - "year2": "Year, 2 Digits", - "month": "Month, 2 Digits", - "date": "Date, 2 Digits", - "hour": "Hour, 2 Digits", - "minute": "Minute, 2 Digits", - "second": "Second, 2 Digits", - "millisecond": "Millisecond, 3 Digits", - "timestamp": "Timestamp, 13 Digits", - "md5": "MD5 Hash", - "md5-16": "MD5 Hash (First 16 Digits)", - "localFolder": "Local Folder Structure", - "filename": "Original File Name", - "randomString": "Random String (number of digits)", - "uuid": "Random UUID", - "sha256": "SHA256 Hash", - "sha256-n": "SHA256 Hash (First n Digits)" - }, - "imageProcessing": "Image Processing Settings", - "deleteLocalFileAfterUpload": "Delete Local File After Upload", - "clipboardAndNotification": "Clipboard and Notification", - "enableUploadNotification": "Enable Upload Progress Notification", - "enableUploadResultNotification": "Enable Upload Result Notification", - "autoCopyUrlAfterUpload": "Auto Copy URL After Upload", - "useBuiltInClipboardUpload": "Use Built-in Clipboard Upload", - "useBuiltInClipboardUploadHint": "When disabled, the script file will be used to obtain images.", - "isAutoListenClipboard": "Automatically listen for clipboard uploads when the software starts.", - "urlFormatAndLinkType": "URL Format and Link Type", - "customLinkFormat": "Custom Link Format", - "urlPlaceholder": "Use placeholder $url to represent the position of the URL", - "fileNamePlaceholder": "Use placeholder $fileName to represent the position of the file name", - "extNamePlaceholder": "Use placeholder $extName to represent the position of the file format", - "enableShortUrl": "Use Short URL", - "shortUrlServer": "Short URL Service", - "c1nToken": "C1N Token", - "yourlsDomain": "Yourls Domain", - "yourlsSignature": "Yourls Signature", - "cfWorkerHost": "CF Worker Address", - "sinkDomain": "Sink Domain", - "sinkToken": "Sink Token", - "encodeOutputUrl": "Escape output (copy) URL", - "chooseShowedPicBed": "Please select the image bed to display in the menu", - "galleryPicBedFilter": "Gallery PicBed Filter", - "galleryPicBedFilterDescription": "Choose which picbeds to show in the gallery. If none are selected, all picbeds will be shown." - }, - "advanced": { - "title": "Advanced", - "logging": "Logging", - "logFilePath": "Log File Path", - "setLog": "Set Log", - "logFile": "General Log File", - "guiLogFile": "GUI Log File", - "manageLogFile": "Manage Log File", - "logLevel": "Log Level", - "chooseLogLevel": "Please select log level", - "logFileSize": "Log File Size", - "networkAndProxy": "Network and Proxy", - "setProxyAndMirror": "Set Proxy and Mirror Address", - "uploadProxy": "Upload Proxy", - "pluginInstallProxy": "Plugin Install Proxy", - "pluginInstallMirror": "Plugin Install Mirror", - "serverSettings": "Server Settings", - "enableServer": "Enable Upload API Service", - "uploadServer": "Upload API Service Settings", - "serverSettingsNotice": "If you don't know the purpose of the Upload API Service, please read the documentation or do not modify the configuration.", - "serverHost": "Listen Address", - "serverPort": "Listen Port", - "serverKey": "Authentication Key", - "serverKeyPlaceholder": "Please enter the authentication key to prevent API abuse", - "webServerSettings": "Web Server Settings", - "webServerNotice": "If you don't know the purpose of the Web Server, please read the documentation or do not modify the configuration.", - "enableWebServer": "Enable Web Server", - "webServerHost": "Web Server Listen Address", - "webServerPort": "Web Server Listen Port", - "webServerPath": "Web Server Path", - "webServerPlaceholderHost": "Recommended default address: 127.0.0.1", - "webServerPlaceholderPort": "Recommended default port: 37777", - "serverEncryptionKey": "API Data Encryption Key", - "logLevelList": { - "all": "All", - "success": "Success", - "info": "Info", - "warn": "Warn", - "error": "Error", - "none": "No Log" - } - }, - "update": { - "title": "Update", - "applicationUpdates": "Application Updates", - "checkUpdate": "Check for Updates", - "clickToCheck": "Click to Check", - "openUpdateHelper": "Open Update Helper", - "openUpdateHelperDesc": "Show notification when a new version is available", - "currentVersion": "Current Version: {version}", - "newestVersion": "Newest Version: {version}", - "getting": "Getting...", - "hasNewVersion": "PicList has been updated, please click OK to restart and trigger the update", - "networkError": "Network error, please check your network connection", - "releaseNotes": "Release Notes", - "releaseNotesDescription": "View the latest changes and updates", - "latestReleaseNotes": "Latest Release Notes", - "refresh": "Refresh", - "retry": "Retry", - "loadingReleaseNotes": "Loading release notes...", - "releaseNotesError": "Failed to load release notes. Please check your network connection.", - "noReleaseNotes": "No release notes available", - "lastUpdated": "Last updated", - "justNow": "just now", - "minutesAgo": "{minutes} minutes ago", - "hoursAgo": "{hours} hours ago", - "daysAgo": "{days} days ago" - } - }, - "plugin": { - "title": "Plugins", - "description": "PicList Plugin Management", - "importLocal": "Import Local Plugin", - "updateAll": "Update All Plugins", - "list": "Plugin List", - "searchPlaceholder": "Search for PicGo plugins on npm, or click the button above to view the excellent plugin list", - "needRestart": "Need Restart to Take Effect", - "restartApp": "Restart Application", - "loading": "Loading...", - "install": "Install", - "installing": "Installing...", - "installed": "Installed", - "doingSomething": "Doing Something...", - "settings": "Settings", - "disabled": "Disabled", - "noPluginsFound": "No Plugins Found", - "tryDifferentSearch": "Try Different Search Keywords", - "NoPluginsInstalled": "No Plugins Installed", - "installPluginsToGetStarted": "Please install plugins to get started", - "browsePlugins": "Browse Plugins", - "configThing": "Config {c}", - "pluginList": "Plugin List", - "notGuiImplement": "This plugin does not have a GUI implementation, continue?", - "updateSuccess": "Update Success", - "setResult": "Set Result", - "setSuccess": "Set Success" - }, - "inputBox": { - "title": "Input Box" - }, "configForm": { "configName": "Config Name", "configNamePlaceholder": "Please enter config name" }, - "rename": { - "placeholder": "Please enter new file name" - }, - "shortKey": { - "title": "Shortcut Key", - "name": "Shortcut Key Name", - "bind": "Shortcut Key Binding", - "status": "Status", - "source": "Source", - "handle": "Action", - "noBinding": "Not Bound", - "enable": "Enable", - "disable": "Disable", - "enabled": "Enabled", - "disabled": "Disabled", - "edit": "Edit", - "changeUpload": "Change Upload Shortcut", - "keyBinding": "Key Binding", - "pressKeys": "Press the keys to set the shortcut", - "pressHint": "Click the input box and press the keys you want to bind" - }, - "picBedConfigs": { - "title": "Config", - "viewDoc": "View Document", - "copyAPI": "Copy Upload API", - "noConfigOptions": "No Config Options", - "setSuccess": "Set Success", - "setFailedInfo": "Set Failed, Please Check If Config Options Are Correct", - "loadConfigFailed": "Load Config Failed, Please Check If Config File Is Correct", - "loadPicBedListFailed": "Load PicBed List Failed", - "importConfigSuccess": "Import Config Success", - "importConfigFailed": "Import Config Failed", - "resetSuccess": "Reset Success", - "resetFailed": "Reset Failed, Please Check If Config Options Are Correct", - "viewDocFailed": "View Document Failed", - "noConfigs": "No Configs", - "copyAPISucceed": "Copy API Address Succeed", - "copyAPIFailed": "Copy API Address Failed" - }, - "uploaderConfig": { - "title": "PicBed Config", - "selected": "Selected", - "edit": "Edit", - "delete": "Delete", - "addNew": "Add New", - "setAsDefault": "Set as Default PicBed", - "setSuccess": "Set Success", - "deleteTitle": "Notification", - "deleteConfirm": "Are you sure you want to delete this PicBed config?", - "deleteSuccess": "Delete Success" - }, - "toolbox": { - "title": "Toolbox", - "description": "Scan the following items immediately to fix usage issues", - "startScan": "Start Scanning", - "success": "Congratulations, no problems were found", - "startFix": "Start Fixing", - "autoFixFail": "Automatic repair failed, please fix the following problems yourself", - "reScan": "Re scanning", - "checkConfigFileBroken": "Check if the configuration file is damaged", - "openConfigFile": "Open configuration file", - "checkGalleryFileBroken": "Check if the album file is damaged", - "checkProblemWithClipboardPicUpload": "Check if there is a problem with clipboard picture upload", - "openFilePath": "Open file path", - "checkProblemWithProxy": "Check if the proxy settings are normal", - "fixDoneNeedReload": "Repair completed, need to restart to take effect, restart or not", - "notice": "Notice" - }, "gallery": { - "title": "Gallery", - "images": "Images", - "syncDelete": "Delete from Cloud", - "hideFilters": "Filters", - "showFilters": "Filters", - "refresh": "Refresh", - "picBedType": "PicBed Type", - "chooseShowedPicBed": "Choose Showed PicBed", - "selected": "Selected", - "dateRange": "Date Range", - "pasteFormat": "Paste Format", - "urlType": "URL Type", - "sort": "Sort", - "sortBy": { - "name": "Name", - "time": "Date", - "ext": "Extension", - "check": "Checked" - }, - "searchFilename": "Search by Filename", - "searchUrl": "Search by URL", - "copy": "Copy", - "edit": "Edit", - "delete": "Delete", - "selectAll": "Select All", - "cancel": "Cancel", - "noImagesFound": "No Images Found", - "tryAdjustingFilters": "Try Adjusting Filters or Uploading Some Images", - "changeImageUrl": "Change Image URL", "batchEditUrl": "Batch Edit URL", + "cancel": "Cancel", + "canceled": "Canceled", + "changeImageUrl": "Change Image URL", + "chooseShowedPicBed": "Choose Showed PicBed", + "cloudDeleteFailed": "Cloud Delete Failed", + "cloudDeleteSucceed": "Cloud Delete Succeed", + "confirmRemove": "Are you sure you want to delete the selected images?", + "copy": "Copy", + "copyLinkSucceed": "Copy Link Succeed", + "dateRange": "Date Range", + "delete": "Delete", + "edit": "Edit", + "gridView": "Grid", + "haveDuplicate": "There are naming duplicates among the selected images, do you want to continue?", + "hideFilters": "Filters", + "images": "Images", + "inputRegexTip": "Please enter the matching string", + "isAlwaysForceReload": "No Cache", + "listView": "List", + "longUrl": "Long URL", + "noImagesFound": "No Images Found", + "noItemsNeedRename": "No items need to be renamed", + "noMatch": "No matching items found", + "notice": "Notice", + "operationFailed": "Operation Failed", + "operationSucceed": "Operation Succeed", + "pasteFormat": "Paste Format", + "picBedType": "PicBed Type", + "previewHelp": "Scroll to zoom • Drag to pan • Arrow keys to navigate • ESC to close", + "refresh": "Refresh", "regexPattern": "Regex Pattern Matched: {matched} Times", "regexPatternPlaceholder": "For example: ^\\d{4}-\\d{2}-\\d{2}, without the slashes on both sides of the regex", "replacedWith": "The string to be replaced, placeholders from the custom renaming rules can be used", - "longUrl": "Long URL", + "searchFilename": "Search by Filename", + "searchUrl": "Search by URL", + "selectAll": "Select All", + "selected": "Selected", "shortUrl": "Short URL", - "copyLinkSucceed": "Copy Link Succeed", - "notice": "Notice", - "confirmRemove": "Are you sure you want to delete the selected images?", - "cloudDeleteSucceed": "Cloud Delete Succeed", - "cloudDeleteFailed": "Cloud Delete Failed", - "operationSucceed": "Operation Succeed", - "operationFailed": "Operation Failed", - "haveDuplicate": "There are naming duplicates among the selected images, do you want to continue?", - "canceled": "Canceled", - "previewHelp": "Scroll to zoom • Drag to pan • Arrow keys to navigate • ESC to close", - "listView": "List", - "gridView": "Grid", - "isAlwaysForceReload": "No Cache", - "inputRegexTip": "Please enter the matching string", - "noMatch": "No matching items found", - "noItemsNeedRename": "No items need to be renamed" + "showFilters": "Filters", + "sort": "Sort", + "sortBy": { + "check": "Checked", + "ext": "Extension", + "name": "Name", + "time": "Date" + }, + "syncDelete": "Delete from Cloud", + "title": "Gallery", + "tryAdjustingFilters": "Try Adjusting Filters or Uploading Some Images", + "urlType": "URL Type" }, - "tray": { - "openMainWindow": "Open Main Window", - "waitForUpload": "Waiting for Upload", - "uploaded": "Uploaded", - "copySuccess": "Copy Success" + "imageProcess": { + "cancel": "Cancel", + "confirm": "Confirm", + "description": "Configure image processing options, including compression, watermarking, format conversion, etc.", + "general": { + "basicImageProcessing": "Basic Image Processing", + "destinationFormat": "Destination Format", + "formatConversion": "Image Format Conversion", + "isConvert": "Convert Format", + "isRemoveExif": "Remove Exif Information", + "quality": "Compression Quality (1-100)", + "skipProcessExtList": "Skip Processed File Extensions", + "skipProcessExtListLabel": "Skip Processed Extensions", + "skipProcessExtListPlaceholder": "Enter file extensions to skip processing, separated by commas (e.g.: jpg,png,gif)", + "specificFormatConversion": "Specific Format Conversion, please fill in JSON format, such as: {'{'}\"png\": \"jpg\"{'}'}" + }, + "generalSettings": "General", + "perPicBed": { + "description": "Configure settings for each PicBed individually", + "title": "Per-PicBed Settings" + }, + "title": "Image Processing Settings", + "transform": { + "description": "Adjust image size, rotation, flipping, etc.", + "isFlip": "Vertical Flip", + "isFlop": "Horizontal Flip", + "isResize": "Enable Resize", + "isResizeByPercent": "Enable Resize by Percentage", + "isResizeByPercentHint": "Higher priority", + "isRotate": "Enable Rotation", + "percentageResize": "Resize by Percentage", + "resizeDescription": "Set image scaling parameters", + "resizeHeight": "Resize Height (0 means scale by width)", + "resizePercent": "Resize Percentage (Enter 50 for 50%)", + "resizeTitle": "Resize", + "resizeWidth": "Resize Width (0 means scale by height)", + "rotationDegree": "Rotation Angle", + "rotationDescription": "Set image rotation parameters", + "rotationTitle": "Rotation Settings", + "skipResizeOfSmallImgHeight": "Skip resizing when image is smaller than set", + "title": "Transform Settings" + }, + "transformSettings": "Transform", + "watermark": { + "color": "Watermark Color, manually enter or use color picker", + "degree": "Watermark Rotation Angle", + "description": "Add text or image watermark to the image", + "image": "Image", + "imageOpacity": "Watermark Opacity", + "imagePath": "Watermark Image Path (Leave empty to use default image)", + "imagePathPlaceholder": "Optional, please enter path", + "inputText": "Watermark Text", + "inputTextPlaceholder": "Please enter watermark text", + "isAdd": "Enable or Disable Watermark", + "isFullScreen": "Enable Full Screen Watermark", + "position": "Watermark Position", + "positionOptions": { + "bottom": "Bottom", + "bottomLeft": "Bottom Left", + "bottomRight": "Bottom Right", + "center": "Center", + "left": "Left", + "right": "Right", + "top": "Top", + "topLeft": "Top Left", + "topRight": "Top Right" + }, + "scaleRatio": "Watermark Scale Ratio", + "text": "Text", + "textFontPath": "Watermark Font Path (Automatically downloaded before first use)", + "textFontPathPlaceholder": "Optional, please enter path", + "title": "Watermark Settings", + "type": "Watermark Type" + }, + "watermarkSettings": "Watermark" + }, + "inputBox": { + "title": "Input Box" }, "manage": { - "main": { - "openPicBedUrl": "Open PicBed official site", - "newBucket": "Create bucket", - "loading": "Loading...", - "backToHome": "Home", - "switchPicBed": "Switch", - "settings": "Settings", - "bucket": "Bucket", - "gallery": "Gallery", - "repo": "Repo", - "createSuccess": "Created successfully", - "createFailed": "Creation failed" - }, - "empty": { - "noData": "No data", - "noDataDesc": "Please create a bucket or upload images first" - }, - "setting": { - "clearCache": "Clear file list cache database. Used {size}, available {percent}%", - "clearCacheMsg": "Are you sure you want to clear the cache?", - "isAutoRefreshTitle": "Automatically refresh the file list when entering a new directory", - "isAutoRefreshTips": "Only works in non-pagination mode. After the first load, data is cached to speed up subsequent loads", - "isShowThumbnailTitle": "Show images as originals instead of default file-type icons (bucket must be publicly accessible)", - "isUsePreSignedUrlTitle": "Use pre-signed URL to preview images", - "isForceCustomUrlHttpsTitle": "Force HTTPS for custom domains", - "isForceCustomUrlHttpsTips": "When enabled, copy-link and similar actions will automatically add the https prefix to the custom domain", - "isEncodeUrlTitle": "URL-encode when copying links", - "isEncodeUrlTips": "Enable depending on the platform", - "isUploadKeepDirStructureTitle": "Keep directory structure on upload", - "isUploadKeepDirStructureTips": "When off, all files will be flattened into the target directory", - "isIgnoreCaseTitle": "Ignore case when searching files", - "isIgnoreCaseTips": "Recommended to enable", - "timestampRenameTitle": "Timestamp rename on upload (highest priority)", - "timestampRenameTips": "When enabled, uploaded files will be renamed to a timestamp", - "randomStringRenameTitle": "Random string rename on upload (medium priority)", - "randomStringRenameTips": "20 random characters", - "customRenameTitle": "Custom rename on upload (low priority)", - "customRenameTips": "Provide a naming pattern after enabling", - "customRenameTableTitle": "Reference table for custom renaming format", - "customRenameTablePlaceholder": "Please enter a custom renaming format", - "placeholder": "Placeholder", - "description": "Description", - "copySuccess": "Copied {name}", - "download": "Download", - "file": "File", - "folder": "Folder", - "keepDirStructure": "Keep directory structure", - "keepDirStructureDesc": "When enabled, downloads keep the original directory structure", - "clearSuccess": "Cache cleared successfully", - "clearFailed": "Failed to clear cache", - "notice": "Notifications", - "maxDownLoadFileLimit": "Maximum concurrent downloads", - "maxDownLoadFileLimitDesc": "Adjust based on network conditions", - "preSignedUrlExpire": "Pre-signed URL expiration (seconds)", - "preSignedUrlExpireDesc": "Adjust based on actual needs", - "copyFormat": { - "title": "Copy format", - "markdown": "Markdown", - "rawurl": "Raw URL", - "markdown-with-link": "Markdown (with link)", - "html": "HTML format", - "bbcode": "BBCode format", - "custom": "Custom format", - "customTitle": "Custom link format ($url is the link, $fileName is the file name)", - "customTips": "Fill in the custom format as needed" - }, - "selectDownloadFolderTitle": "Choose download folder", - "selectDownloadFolderTips": "Select download directory", - "defaultDownloadFolder": "System default download folder", - "browse": "Browse" - }, "bucket": { - "selectCustomDomain": "Select Custom Domain", - "inputCustomDomain": "Enter Custom Domain", - "uploadFiles": "Upload Files", - "uploadFromUrl": "Upload from URL", - "createFolder": "Create Folder", - "downloadPage": "Download Page", "batchRename": "Batch Rename", - "copyFileIno": "Copy File Info", - "forceRefreshFileList": "Force Refresh File List", - "searchPlaceholder": "Search File Name", - "rootFolder": "Root Folder", - "fileNum": "File Count: {num}", - "pageFileSize": "Total Size: {size}", - "selectAll": "Select All", "cancel": "Cancel", - "reverseSelect": "Reverse Select", + "canceled": "Canceled", + "clear": "Clear", + "clearAll": "Clear All Tasks", + "clearFinishedTasks": "Clear Finished Tasks", + "clickUpload": "Or: Click to select files", + "copyDownloadTask": "Copy Download Task Information", + "copyFileInfoInJson": "Copy File Information as JSON", + "copyFileIno": "Copy File Info", + "copySuccess": "Copy success", + "copyUploadTask": "Copy Upload Task Information", + "createFailed": "Create failed", + "createFolder": "Create Folder", + "createSuccess": "Create success, please refresh", + "deleteFailed": "Delete failed", + "deleteMsg": "This will permanently delete, are you sure?", + "deleteMultiMsg": "Delete success {success} items, failed {failed} items", + "deleteSuccess": "Delete success", + "deletingMsg": "Deleting, please wait...", "downloadBtn": "Download {num}", + "downloadFolderNotice": "Are you sure you want to download this folder?", + "downloading": "Downloading", + "downloadPage": "Download Page", + "dragUpload": "Drag and drop upload supports directories", + "enterFullScreen": "Enter Full Screen (F11)", + "excludeExt": "Exclude file extensions when replacing", + "exitFullScreen": "Exit Full Screen (F11)", + "failed": "Failed", + "fileDupNotice": "Detected {number} duplicate file names, do you want to continue?", + "fileInfo": "File Information", + "fileNum": "File Count: {num}", + "forceRefreshFileList": "Force Refresh File List", + "getDownloadListFailed": "Get download list failed", + "getDownloadListSuccess": "Get download list success", + "getFileListFailed": "Get file list failed", + "getFileListSuccess": "Get file list success", + "getInBackground": "Getting file list in background, please do not switch pages", + "includeExt": "Include file extensions when replacing", + "inputCustomDomain": "Enter Custom Domain", + "inputFolderTitle": "Please enter folder name", + "inputPatternMsg": "Please enter matching string", + "inputValidUrlMsg": "Please enter a valid URL", + "isLoadingMsg": "Loading, please wait...", + "keepDirStructure": "Keep directory structure", + "lastPageMsg": "Already on the last page", + "linkFormat": { + "bbcode": "BBCode", + "custom": "Custom", + "html": "HTML", + "markdown": "Markdown", + "markdown-with-link": "Markdown (with link)", + "presign": "Pre-signed Link", + "url": "Url" + }, + "loading": "Loading, click to cancel", + "loadingFailed": "Loading failed", + "matchedPattern": "Matching string or regular expression - {num} matched", + "noFileNeedRename": "No files need to be renamed", + "noKeepDirStructure": "Do not keep directory structure", + "noMatchedFile": "No matching files found", + "noNeedToRename": "No need to rename", + "notice": "Notice", + "openDownloadFolder": "Open Download Folder", + "pageFileSize": "Total Size: {size}", + "partFileListFailed": "Part file list failed", + "play": "Play", + "prepareDownload": "Preparing to download, click to cancel", + "preview": "Preview", + "readingDir": "Reading, please wait", + "regexPatternTips": "Regular expressions do not need to add /", + "regexPlaceholder": "Please enter a regular expression or matching string", "removeBtn": "Remove {num}", + "renameFailed": "Rename failed", + "renameFile": "Rename File", + "renameResultMsg": "Rename success {success} items, failed {failed} items", + "renameSuccess": "Rename success", + "replaceInput": "The string to replace can use placeholders in custom renaming", + "reverseSelect": "Reverse Select", + "rootFolder": "Root Folder", + "searchPlaceholder": "Search File Name", + "selectAll": "Select All", + "selectCustomDomain": "Select Custom Domain", + "selectFileMsg": "Please select a file", "sort": { - "title": "Sort", + "check": "Selection Status", + "ext": "Type", + "init": "Initialization", "name": "File Name", "size": "Size", "time": "Time", - "ext": "Type", - "check": "Selection Status", - "init": "Initialization" + "title": "Sort" }, - "enterFullScreen": "Enter Full Screen (F11)", - "exitFullScreen": "Exit Full Screen (F11)", - "linkFormat": { - "url": "Url", - "markdown": "Markdown", - "markdown-with-link": "Markdown (with link)", - "html": "HTML", - "bbcode": "BBCode", - "custom": "Custom", - "presign": "Pre-signed Link" - }, - "urlUploadTitle": "Please enter URL, separated by new lines", - "fileInfo": "File Information", - "copyFileInfoInJson": "Copy File Information as JSON", - "renameFile": "Rename File", - "matchedPattern": "Matching string or regular expression - {num} matched", - "regexPatternTips": "Regular expressions do not need to add /", - "regexPlaceholder": "Please enter a regular expression or matching string", - "replaceInput": "The string to replace can use placeholders in custom renaming", - "excludeExt": "Exclude file extensions when replacing", - "includeExt": "Include file extensions when replacing", - "loading": "Loading, click to cancel", - "prepareDownload": "Preparing to download, click to cancel", - "keepDirStructure": "Keep directory structure", - "noKeepDirStructure": "Do not keep directory structure", - "uploadFile": "Upload File", - "dragUpload": "Drag and drop upload supports directories", - "clickUpload": "Or: Click to select files", - "readingDir": "Reading, please wait", - "upload": "Upload", - "clear": "Clear", - "uploading": "Uploading", - "success": "Success", - "failed": "Failed", - "copyUploadTask": "Copy Upload Task Information", - "clearFinishedTasks": "Clear Finished Tasks", - "clearAll": "Clear All Tasks", - "downloading": "Downloading", - "copyDownloadTask": "Copy Download Task Information", - "openDownloadFolder": "Open Download Folder", - "preview": "Preview", - "play": "Play", - "notice": "Notice", - "downloadFolderNotice": "Are you sure you want to download this folder?", - "getDownloadListSuccess": "Get download list success", - "getDownloadListFailed": "Get download list failed", - "canceled": "Canceled", - "copySuccess": "Copy success", - "deleteSuccess": "Delete success", - "deleteFailed": "Delete failed", - "deleteMultiMsg": "Delete success {success} items, failed {failed} items", "startLoadingFile": "Start loading file", - "loadingFailed": "Loading failed", - "lastPageMsg": "Already on the last page", - "getFileListSuccess": "Get file list success", - "getFileListFailed": "Get file list failed", - "partFileListFailed": "Part file list failed", - "getInBackground": "Getting file list in background, please do not switch pages", - "isLoadingMsg": "Loading, please wait...", - "inputFolderTitle": "Please enter folder name", - "createSuccess": "Create success, please refresh", - "createFailed": "Create failed", - "inputValidUrlMsg": "Please enter a valid URL", "startUploadMsg": "Start background download, will automatically upload after success", - "inputPatternMsg": "Please enter matching string", - "noMatchedFile": "No matching files found", - "noFileNeedRename": "No files need to be renamed", - "fileDupNotice": "Detected {number} duplicate file names, do you want to continue?", - "renameResultMsg": "Rename success {success} items, failed {failed} items", - "selectFileMsg": "Please select a file", + "stopGetDownloadListMsg": "Are you sure you want to stop getting download files?", "stopGetFileListMsg": "Are you sure you want to stop getting file list?", "stopSuccessMsg": "Stop success", - "stopGetDownloadListMsg": "Are you sure you want to stop getting download files?", - "willDeleteMsg": "Are you sure you want to delete {num} items?", - "deleteMsg": "This will permanently delete, are you sure?", - "deletingMsg": "Deleting, please wait...", - "noNeedToRename": "No need to rename", - "renameSuccess": "Rename success", - "renameFailed": "Rename failed" - }, - "newBucket": { - "bucketDesc": "Bucket Name", - "bucketPlaceholder": "Please enter bucket name", - "bucketNoEmpty": "Bucket name cannot be empty", - "region": "Region", - "acl": { - "title": "Access Control", - "private": "Private", - "publicRead": "Public Read", - "publicReadWrite": "Public Read Write", - "authenticatedRead": "Authenticated Read" - }, - "tcyun": { - "name": "Tencent Cloud", - "bucketLengthMsg": "Bucket name length cannot exceed 23 characters", - "bucketCharMsg": "Bucket name can only contain lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen" - }, - "aliyun": { - "name": "Aliyun", - "bucketLengthMsg": "Bucket name length must be between 3 and 63 characters", - "bucketCharMsg": "Bucket name can only contain lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen" - }, - "qiniu": { - "name": "Qiniu", - "bucketLengthMsg": "Bucket name length must be between 3 and 63 characters", - "bucketCharMsg": "Bucket name can only contain lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen", - "publicAccess": "Public Access" - }, - "s3": { - "name": "S3" - } - }, - "login": { - "title": "Image Host Management", - "savedConfigs": "Saved Configurations", - "refresh": "Refresh", - "noConfigs": "No configurations found", - "noConfigsDesc": "Please check your configuration file or reload the page", - "viewDetails": "View details", - "enter": "Enter", - "delete": "Delete", - "selectPlaceholder": "Please select", - "import": "Import", - "save": "Save", - "reset": "Reset", - "configTabTitle": "Existing configurations, click to copy", - "noRequiredMsg": "Please fill in the required fields", - "aliasMsg": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens", - "itemsPerPageMsg": "Items per page must be an integer between 20 and 1000", - "configChangeMsg": "Configuration changed", - "configSaveMsg": "Configuration saved", - "deleteConfigSuccessMsg": "Configuration deleted successfully", - "deleteConfigFailedMsg": "Failed to delete configuration", - "copySuccess": "Copied: {text}", - "importSuccess": "Import successful", - "tips": "Tips", - "confirmDeleteConfig": "Are you sure you want to delete this configuration?" + "success": "Success", + "upload": "Upload", + "uploadFile": "Upload File", + "uploadFiles": "Upload Files", + "uploadFromUrl": "Upload from URL", + "uploading": "Uploading", + "urlUploadTitle": "Please enter URL, separated by new lines", + "willDeleteMsg": "Are you sure you want to delete {num} items?" }, "constant": { - "pleaseInput": "Please enter: {name}", - "inputItemsPerPage": "Enter the number of items per page", - "itemsPPBeNumber": "Items per page must be a number", - "itemsPPBeNumberLimit": "Items per page must be between 20 and 1000", - "inputAlias": "Enter an alias, the unique identifier of this configuration", - "aliasRuleMsg": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens", - "aliasTip": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens", - "itemsPPTip": "Items per page must be between 20 and 1000", - "pagingTip": "When pagination is off, the directory list will use database caching to improve performance", - "bucketNameTip": "Comma-separated, e.g., bucket1,bucket2; corresponds one-to-one with the starting directories", - "baseDirTip": "Comma-separated, e.g., /dir1,/dir2; corresponds one-to-one with the buckets", - "isAutoCustomUrlTip": "When enabled, automatically fetches the domain bound to the bucket", - "aliasDesc": "Configuration alias", - "aliasPlaceholder": "The unique identifier for this configuration", - "pagingDesc": "Enable pagination", - "referText": "For configuration tutorial, see: ", "accessKeyDesc": "Access Key, available in the console", - "accessKeyPlaceholder": "Please enter Access Key", "accessKeyIdDesc": "Access Key ID, available in the console", "accessKeyIdPlaceholder": "Please enter Access Key ID", - "secretIdDesc": "Secret ID, available in the console", - "secretIdPlaceholder": "Please enter Secret ID", - "secretKeyDesc": "Secret Key, available in the console", - "secretKeyPlaceholder": "Please enter Secret Key", + "accessKeyPlaceholder": "Please enter Access Key", "accessKeySecretDesc": "Access Key Secret, available in the console", "accessKeySecretPlaceholder": "Please enter Access Key Secret", - "secretKeyIdDesc": "Secret Key, available in the console", - "secretKeyIdPlaceholder": "Please enter Secret Key", - "bucketDesc": "Bucket name, optional", - "bucketPlaceholder": "Comma-separated, e.g., bucket1,bucket2", - "baseDirDesc": "Starting directory, optional", - "baseDirPlaceholder": "Comma-separated, e.g., /dir1,/dir2", - "isAutoGetCustomUrl": "Automatically get bound domain", - "isEnablePaging": "Enable pagination", - "itemsPerPage": "Items per page", - "userNameDesc": "Username", - "userNamePlaceholder": "Please enter username", - "passwordDesc": "Password", - "passwordPlaceholder": "Please enter password", - "proxyDesc": "Proxy URL", - "proxyPlaceholder": "e.g., http://127.0.0.1:7890", - "proxyTips": "Some image hosts may require a proxy to work properly", - "explain": "You can set multiple space names and starting directories using commas. Order must match; empty or missing items use default values", - "specialDesc": "Special configuration", - "specialPlaceholder": "Please enter special configuration", - "specialTips": "This setting cannot be modified and is only for internal compatibility handling", - "smms": { - "tokenDesc": "SM.MS Token, available in your SM.MS profile", - "tokenPlaceholder": "Please enter SM.MS Token", - "explain": "For mainland China, please use the backup domain https://sm.ms and avoid sending too many requests in a short time" - }, - "qiniu": { - "name": "Qiniu Cloud" - }, - "github": { - "tokenDesc": "GitHub Token, available in GitHub settings", - "tokenPlaceholder": "Please enter GitHub Token", - "tokenTips": "Provide a token with full repo scope, otherwise some features may not work", - "cdnUrlDesc": "CDN acceleration domain", - "cdnUrlPlaceholder": "Supports {'{'}username{'}'}, {'{'}repo{'}'}, {'{'}branch{'}'}, and {'{'}path{'}'} as placeholders to adapt to different repositories and branches", - "cdnUrlTips": "For example: `https://cdn.staticaly.com/gh/{'{'}username{'}'}/{'{'}repo{'}'}{'@'}{'{'}branch{'}'}/{'{'}path{'}'}`", - "protocolRuleMsg": "Must start with http:// or https://", - "bracketRuleMsg": "Braces must come in pairs", - "explain": "API calls are limited per hour; uploading files larger than 100 MB is not supported" - }, + "aliasDesc": "Configuration alias", + "aliasPlaceholder": "The unique identifier for this configuration", + "aliasRuleMsg": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens", + "aliasTip": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens", "aliyun": { "name": "Alibaba Cloud" }, - "tcyun": { - "name": "Tencent Cloud", - "appIdDesc": "App ID, available in the Tencent Cloud console", - "appIdPlaceholder": "Please enter App ID", - "appIdTips": "e.g., 1250000000" - }, - "upyun": { - "name": "UPYUN", - "bucketDesc": "Service name", - "bucketPlaceholder": "Equivalent to the bucket name in other object storage", - "operatorNameDesc": "Operator", - "operatorNamePlaceholder": "Use an operator with full permissions", - "operatorPassDesc": "Operator password", - "operatorPassPlaceholder": "Please enter operator password", - "baseDirDesc": "Starting directory", - "baseDirPlaceholder": "Please enter starting directory", - "accelerationUrlDesc": "Acceleration domain", - "accelerationUrlPlaceholder": "Please enter acceleration domain", - "notEmpty": "Acceleration domain cannot be empty", + "baseDirDesc": "Starting directory, optional", + "baseDirPlaceholder": "Comma-separated, e.g., /dir1,/dir2", + "baseDirTip": "Comma-separated, e.g., /dir1,/dir2; corresponds one-to-one with the buckets", + "bucketDesc": "Bucket name, optional", + "bucketNameTip": "Comma-separated, e.g., bucket1,bucket2; corresponds one-to-one with the starting directories", + "bucketPlaceholder": "Comma-separated, e.g., bucket1,bucket2", + "explain": "You can set multiple space names and starting directories using commas. Order must match; empty or missing items use default values", + "github": { + "bracketRuleMsg": "Braces must come in pairs", + "cdnUrlDesc": "CDN acceleration domain", + "cdnUrlPlaceholder": "Supports {'{'}username{'}'}, {'{'}repo{'}'}, {'{'}branch{'}'}, and {'{'}path{'}'} as placeholders to adapt to different repositories and branches", + "cdnUrlTips": "For example: `https://cdn.staticaly.com/gh/{'{'}username{'}'}/{'{'}repo{'}'}{'@'}{'{'}branch{'}'}/{'{'}path{'}'}`", + "explain": "API calls are limited per hour; uploading files larger than 100 MB is not supported", "protocolRuleMsg": "Must start with http:// or https://", - "antiLeechTokenDesc": "Anti-leech token", - "antiLeechTokenPlaceholder": "Please enter anti-leech token", - "antiLeechTokenTooltip": "Leave blank to disable anti-leech by default", - "antiLeechExp": "Anti-leech expiration time", - "explain": "The acceleration domain is required; otherwise it will not work properly" + "tokenDesc": "GitHub Token, available in GitHub settings", + "tokenPlaceholder": "Please enter GitHub Token", + "tokenTips": "Provide a token with full repo scope, otherwise some features may not work" }, "imgur": { "accessTokenDesc": "access token", @@ -858,86 +310,634 @@ "accessTokenTips": "Not the clientID; please follow the guide to obtain it", "explain": "Use a proxy in mainland China. API calls are rate-limited; please mind the frequency" }, - "s3": { - "endpointDesc": "endpoint", - "endpointPlaceholder": "e.g., s3.us-east-1.amazonaws.com", - "endpointTips": "Leave blank to use AWS S3 by default", - "enableHttps": "Enable HTTPS", - "enableHttpsTip": "When enabled, all requests use HTTPS", - "enableS3PathStyle": "Enable S3 path style", - "enableS3PathStyleTip": "Enable when using services like MinIO", - "aclDesc": "Upload file permission", - "acl": { - "private": "Private", - "publicRead": "Public read", - "publicReadWrite": "Public read/write", - "authenticatedRead": "Authenticated read", - "bucketOwnerRead": "Bucket owner read", - "bucketOwnerFullControl": "Bucket owner full control", - "awsExecRead": "AWS Exec Read" - }, - "aclTips": "Choose the appropriate permission setting based on your needs", - "enableDogeSupport": "Enable Doge support", - "enableDogeSupportTip": "When enabled, all requests will use the Doge API" - }, - "webdav": { - "hostDesc": "Address", - "hostPlaceholder": "e.g., https://example.com/dav", - "hostTips": "Enter the WebDAV URL", - "baseDirDesc": "Starting directory", - "baseDirPlaceholder": "e.g., /dir1", - "customUrlDesc": "Custom URL", - "customUrlPlaceholder": "e.g., https://example.com/custom", - "customUrlTips": "Provide a custom URL if the public URL and API endpoint differ", - "protocolRuleMsg": "Must start with http:// or https://", - "webPathDesc": "Base path for URL joining", - "webPathPlaceholder": "e.g., /dir2", - "webPathTips": "Used to assemble the public URL", - "enableHttpsDesc": "Enable HTTPS", - "enableHttpsTips": "When enabled, all requests use HTTPS", - "authTypeDesc": "Authentication type", - "explain": "WebDAV implementations vary by platform; choose according to your actual setup" - }, + "inputAlias": "Enter an alias, the unique identifier of this configuration", + "inputItemsPerPage": "Enter the number of items per page", + "isAutoCustomUrlTip": "When enabled, automatically fetches the domain bound to the bucket", + "isAutoGetCustomUrl": "Automatically get bound domain", + "isEnablePaging": "Enable pagination", + "itemsPerPage": "Items per page", + "itemsPPBeNumber": "Items per page must be a number", + "itemsPPBeNumberLimit": "Items per page must be between 20 and 1000", + "itemsPPTip": "Items per page must be between 20 and 1000", "local": { - "name": "Local storage", "baseDirDesc": "Starting directory", "baseDirPlaceholder": "e.g., /dir1", "baseDirRuleMsg": "Starting directory cannot be empty", "customUrlDesc": "Custom domain", "customUrlPlaceholder": "e.g., https://example.com", - "customUrlTooltip": "Provide if your local path is accessible over the network", "customUrlRuleMsg": "Must start with http:// or https://", + "customUrlTooltip": "Provide if your local path is accessible over the network", + "explain": "Local storage configuration", + "name": "Local storage", "webPathDesc": "Base path for URL joining", "webPathPlaceholder": "e.g., /dir2", - "webPathTips": "Used to assemble the public URL", - "explain": "Local storage configuration" + "webPathTips": "Used to assemble the public URL" }, + "pagingDesc": "Enable pagination", + "pagingTip": "When pagination is off, the directory list will use database caching to improve performance", + "passwordDesc": "Password", + "passwordPlaceholder": "Please enter password", + "pleaseInput": "Please enter: {name}", + "proxyDesc": "Proxy URL", + "proxyPlaceholder": "e.g., http://127.0.0.1:7890", + "proxyTips": "Some image hosts may require a proxy to work properly", + "qiniu": { + "name": "Qiniu Cloud" + }, + "referText": "For configuration tutorial, see: ", + "s3": { + "acl": { + "authenticatedRead": "Authenticated read", + "awsExecRead": "AWS Exec Read", + "bucketOwnerFullControl": "Bucket owner full control", + "bucketOwnerRead": "Bucket owner read", + "private": "Private", + "publicRead": "Public read", + "publicReadWrite": "Public read/write" + }, + "aclDesc": "Upload file permission", + "aclTips": "Choose the appropriate permission setting based on your needs", + "enableDogeSupport": "Enable Doge support", + "enableDogeSupportTip": "When enabled, all requests will use the Doge API", + "enableHttps": "Enable HTTPS", + "enableHttpsTip": "When enabled, all requests use HTTPS", + "enableS3PathStyle": "Enable S3 path style", + "enableS3PathStyleTip": "Enable when using services like MinIO", + "endpointDesc": "endpoint", + "endpointPlaceholder": "e.g., s3.us-east-1.amazonaws.com", + "endpointTips": "Leave blank to use AWS S3 by default" + }, + "secretIdDesc": "Secret ID, available in the console", + "secretIdPlaceholder": "Please enter Secret ID", + "secretKeyDesc": "Secret Key, available in the console", + "secretKeyIdDesc": "Secret Key, available in the console", + "secretKeyIdPlaceholder": "Please enter Secret Key", + "secretKeyPlaceholder": "Please enter Secret Key", "sftp": { - "hostDesc": "SSH host", - "hostPlaceholder": "e.g., 192.168.1.1", - "portDesc": "SSH port", - "portPlaceholder": "e.g., 22", - "privateKeyDesc": "Private key", - "privateKeyPlaceholder": "Please enter private key", - "passphraseDesc": "Private key passphrase", - "passphrasePlaceholder": "Please enter private key passphrase", - "fileModeDesc": "File permission mode", - "fileModePlaceholder": "e.g., 0644", - "dirModeDesc": "Directory permission mode", - "dirModePlaceholder": "e.g., 0755", "baseDirDesc": "Starting directory", "baseDirPlaceholder": "e.g., /dir1", "baseDirTips": "Starting directory cannot be empty", "customUrlDesc": "Custom domain", "customUrlPlaceholder": "e.g., https://example.com", "customUrlTips": "Provide a custom URL if the public URL and API endpoint differ", + "dirModeDesc": "Directory permission mode", + "dirModePlaceholder": "e.g., 0755", + "explain": "SFTP configuration", + "fileModeDesc": "File permission mode", + "fileModePlaceholder": "e.g., 0644", + "hostDesc": "SSH host", + "hostPlaceholder": "e.g., 192.168.1.1", + "passphraseDesc": "Private key passphrase", + "passphrasePlaceholder": "Please enter private key passphrase", + "portDesc": "SSH port", + "portPlaceholder": "e.g., 22", + "privateKeyDesc": "Private key", + "privateKeyPlaceholder": "Please enter private key", "protocolRuleMsg": "Must start with http:// or https://", "webPathDesc": "Base path for URL joining", "webPathPlaceholder": "e.g., /dir2", - "webPathTips": "Used to assemble the public URL", - "explain": "SFTP configuration" + "webPathTips": "Used to assemble the public URL" + }, + "smms": { + "explain": "For mainland China, please use the backup domain https://sm.ms and avoid sending too many requests in a short time", + "tokenDesc": "SM.MS Token, available in your SM.MS profile", + "tokenPlaceholder": "Please enter SM.MS Token" + }, + "specialDesc": "Special configuration", + "specialPlaceholder": "Please enter special configuration", + "specialTips": "This setting cannot be modified and is only for internal compatibility handling", + "tcyun": { + "appIdDesc": "App ID, available in the Tencent Cloud console", + "appIdPlaceholder": "Please enter App ID", + "appIdTips": "e.g., 1250000000", + "name": "Tencent Cloud" + }, + "upyun": { + "accelerationUrlDesc": "Acceleration domain", + "accelerationUrlPlaceholder": "Please enter acceleration domain", + "antiLeechExp": "Anti-leech expiration time", + "antiLeechTokenDesc": "Anti-leech token", + "antiLeechTokenPlaceholder": "Please enter anti-leech token", + "antiLeechTokenTooltip": "Leave blank to disable anti-leech by default", + "baseDirDesc": "Starting directory", + "baseDirPlaceholder": "Please enter starting directory", + "bucketDesc": "Service name", + "bucketPlaceholder": "Equivalent to the bucket name in other object storage", + "explain": "The acceleration domain is required; otherwise it will not work properly", + "name": "UPYUN", + "notEmpty": "Acceleration domain cannot be empty", + "operatorNameDesc": "Operator", + "operatorNamePlaceholder": "Use an operator with full permissions", + "operatorPassDesc": "Operator password", + "operatorPassPlaceholder": "Please enter operator password", + "protocolRuleMsg": "Must start with http:// or https://" + }, + "userNameDesc": "Username", + "userNamePlaceholder": "Please enter username", + "webdav": { + "authTypeDesc": "Authentication type", + "baseDirDesc": "Starting directory", + "baseDirPlaceholder": "e.g., /dir1", + "customUrlDesc": "Custom URL", + "customUrlPlaceholder": "e.g., https://example.com/custom", + "customUrlTips": "Provide a custom URL if the public URL and API endpoint differ", + "enableHttpsDesc": "Enable HTTPS", + "enableHttpsTips": "When enabled, all requests use HTTPS", + "explain": "WebDAV implementations vary by platform; choose according to your actual setup", + "hostDesc": "Address", + "hostPlaceholder": "e.g., https://example.com/dav", + "hostTips": "Enter the WebDAV URL", + "protocolRuleMsg": "Must start with http:// or https://", + "webPathDesc": "Base path for URL joining", + "webPathPlaceholder": "e.g., /dir2", + "webPathTips": "Used to assemble the public URL" } + }, + "empty": { + "noData": "No data", + "noDataDesc": "Please create a bucket or upload images first" + }, + "login": { + "aliasMsg": "Alias may only contain Chinese characters, letters, numbers, underscores, and hyphens", + "configChangeMsg": "Configuration changed", + "configSaveMsg": "Configuration saved", + "configTabTitle": "Existing configurations, click to copy", + "confirmDeleteConfig": "Are you sure you want to delete this configuration?", + "copySuccess": "Copied: {text}", + "delete": "Delete", + "deleteConfigFailedMsg": "Failed to delete configuration", + "deleteConfigSuccessMsg": "Configuration deleted successfully", + "enter": "Enter", + "import": "Import", + "importSuccess": "Import successful", + "itemsPerPageMsg": "Items per page must be an integer between 20 and 1000", + "noConfigs": "No configurations found", + "noConfigsDesc": "Please check your configuration file or reload the page", + "noRequiredMsg": "Please fill in the required fields", + "refresh": "Refresh", + "reset": "Reset", + "save": "Save", + "savedConfigs": "Saved Configurations", + "selectPlaceholder": "Please select", + "tips": "Tips", + "title": "Image Host Management", + "viewDetails": "View details" + }, + "main": { + "backToHome": "Home", + "bucket": "Bucket", + "createFailed": "Creation failed", + "createSuccess": "Created successfully", + "gallery": "Gallery", + "loading": "Loading...", + "newBucket": "Create bucket", + "openPicBedUrl": "Open PicBed official site", + "repo": "Repo", + "settings": "Settings", + "switchPicBed": "Switch" + }, + "newBucket": { + "acl": { + "authenticatedRead": "Authenticated Read", + "private": "Private", + "publicRead": "Public Read", + "publicReadWrite": "Public Read Write", + "title": "Access Control" + }, + "aliyun": { + "bucketCharMsg": "Bucket name can only contain lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen", + "bucketLengthMsg": "Bucket name length must be between 3 and 63 characters", + "name": "Aliyun" + }, + "bucketDesc": "Bucket Name", + "bucketNoEmpty": "Bucket name cannot be empty", + "bucketPlaceholder": "Please enter bucket name", + "qiniu": { + "bucketCharMsg": "Bucket name can only contain lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen", + "bucketLengthMsg": "Bucket name length must be between 3 and 63 characters", + "name": "Qiniu", + "publicAccess": "Public Access" + }, + "region": "Region", + "s3": { + "name": "S3" + }, + "tcyun": { + "bucketCharMsg": "Bucket name can only contain lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen", + "bucketLengthMsg": "Bucket name length cannot exceed 23 characters", + "name": "Tencent Cloud" + } + }, + "setting": { + "browse": "Browse", + "clearCache": "Clear file list cache database. Used {size}, available {percent}%", + "clearCacheMsg": "Are you sure you want to clear the cache?", + "clearFailed": "Failed to clear cache", + "clearSuccess": "Cache cleared successfully", + "copyFormat": { + "bbcode": "BBCode format", + "custom": "Custom format", + "customTips": "Fill in the custom format as needed", + "customTitle": "Custom link format ($url is the link, $fileName is the file name)", + "html": "HTML format", + "markdown": "Markdown", + "markdown-with-link": "Markdown (with link)", + "rawurl": "Raw URL", + "title": "Copy format" + }, + "copySuccess": "Copied {name}", + "customRenameTablePlaceholder": "Please enter a custom renaming format", + "customRenameTableTitle": "Reference table for custom renaming format", + "customRenameTips": "Provide a naming pattern after enabling", + "customRenameTitle": "Custom rename on upload (low priority)", + "defaultDownloadFolder": "System default download folder", + "description": "Description", + "download": "Download", + "file": "File", + "folder": "Folder", + "isAutoRefreshTips": "Only works in non-pagination mode. After the first load, data is cached to speed up subsequent loads", + "isAutoRefreshTitle": "Automatically refresh the file list when entering a new directory", + "isEncodeUrlTips": "Enable depending on the platform", + "isEncodeUrlTitle": "URL-encode when copying links", + "isForceCustomUrlHttpsTips": "When enabled, copy-link and similar actions will automatically add the https prefix to the custom domain", + "isForceCustomUrlHttpsTitle": "Force HTTPS for custom domains", + "isIgnoreCaseTips": "Recommended to enable", + "isIgnoreCaseTitle": "Ignore case when searching files", + "isShowThumbnailTitle": "Show images as originals instead of default file-type icons (bucket must be publicly accessible)", + "isUploadKeepDirStructureTips": "When off, all files will be flattened into the target directory", + "isUploadKeepDirStructureTitle": "Keep directory structure on upload", + "isUsePreSignedUrlTitle": "Use pre-signed URL to preview images", + "keepDirStructure": "Keep directory structure", + "keepDirStructureDesc": "When enabled, downloads keep the original directory structure", + "maxDownLoadFileLimit": "Maximum concurrent downloads", + "maxDownLoadFileLimitDesc": "Adjust based on network conditions", + "notice": "Notifications", + "placeholder": "Placeholder", + "preSignedUrlExpire": "Pre-signed URL expiration (seconds)", + "preSignedUrlExpireDesc": "Adjust based on actual needs", + "randomStringRenameTips": "20 random characters", + "randomStringRenameTitle": "Random string rename on upload (medium priority)", + "selectDownloadFolderTips": "Select download directory", + "selectDownloadFolderTitle": "Choose download folder", + "timestampRenameTips": "When enabled, uploaded files will be renamed to a timestamp", + "timestampRenameTitle": "Timestamp rename on upload (highest priority)" } + }, + "picBedConfigs": { + "copyAPI": "Copy Upload API", + "copyAPIFailed": "Copy API Address Failed", + "copyAPISucceed": "Copy API Address Succeed", + "importConfigFailed": "Import Config Failed", + "importConfigSuccess": "Import Config Success", + "loadConfigFailed": "Load Config Failed, Please Check If Config File Is Correct", + "loadPicBedListFailed": "Load PicBed List Failed", + "noConfigOptions": "No Config Options", + "noConfigs": "No Configs", + "resetFailed": "Reset Failed, Please Check If Config Options Are Correct", + "resetSuccess": "Reset Success", + "setFailedInfo": "Set Failed, Please Check If Config Options Are Correct", + "setSuccess": "Set Success", + "title": "Config", + "viewDoc": "View Document", + "viewDocFailed": "View Document Failed" + }, + "plugin": { + "browsePlugins": "Browse Plugins", + "configThing": "Config {c}", + "description": "PicList Plugin Management", + "disabled": "Disabled", + "doingSomething": "Doing Something...", + "importLocal": "Import Local Plugin", + "install": "Install", + "installed": "Installed", + "installing": "Installing...", + "installPluginsToGetStarted": "Please install plugins to get started", + "list": "Plugin List", + "loading": "Loading...", + "needRestart": "Need Restart to Take Effect", + "noPluginsFound": "No Plugins Found", + "NoPluginsInstalled": "No Plugins Installed", + "notGuiImplement": "This plugin does not have a GUI implementation, continue?", + "pluginList": "Plugin List", + "restartApp": "Restart Application", + "searchPlaceholder": "Search for PicGo plugins on npm, or click the button above to view the excellent plugin list", + "setResult": "Set Result", + "setSuccess": "Set Success", + "settings": "Settings", + "title": "Plugins", + "tryDifferentSearch": "Try Different Search Keywords", + "updateAll": "Update All Plugins", + "updateSuccess": "Update Success" + }, + "rename": { + "placeholder": "Please enter new file name" + }, + "settings": { + "advanced": { + "chooseLogLevel": "Please select log level", + "enableServer": "Enable Upload API Service", + "enableWebServer": "Enable Web Server", + "guiLogFile": "GUI Log File", + "logFile": "General Log File", + "logFilePath": "Log File Path", + "logFileSize": "Log File Size", + "logging": "Logging", + "logLevel": "Log Level", + "logLevelList": { + "all": "All", + "error": "Error", + "info": "Info", + "none": "No Log", + "success": "Success", + "warn": "Warn" + }, + "manageLogFile": "Manage Log File", + "networkAndProxy": "Network and Proxy", + "pluginInstallMirror": "Plugin Install Mirror", + "pluginInstallProxy": "Plugin Install Proxy", + "serverEncryptionKey": "API Data Encryption Key", + "serverHost": "Listen Address", + "serverKey": "Authentication Key", + "serverKeyPlaceholder": "Please enter the authentication key to prevent API abuse", + "serverPort": "Listen Port", + "serverSettings": "Server Settings", + "serverSettingsNotice": "If you don't know the purpose of the Upload API Service, please read the documentation or do not modify the configuration.", + "setLog": "Set Log", + "setProxyAndMirror": "Set Proxy and Mirror Address", + "title": "Advanced", + "uploadProxy": "Upload Proxy", + "uploadServer": "Upload API Service Settings", + "webServerHost": "Web Server Listen Address", + "webServerNotice": "If you don't know the purpose of the Web Server, please read the documentation or do not modify the configuration.", + "webServerPath": "Web Server Path", + "webServerPlaceholderHost": "Recommended default address: 127.0.0.1", + "webServerPlaceholderPort": "Recommended default port: 37777", + "webServerPort": "Web Server Listen Port", + "webServerSettings": "Web Server Settings" + }, + "clickToOpen": "Click to Open", + "clickToSet": "Click to Set", + "description": "Configure the PicList application", + "docs": "Documentation", + "sync": { + "allConfig": "All Configuration", + "commonConfig": "Common Configuration", + "downloadSettings": "Download Settings", + "fileManagement": "File Management", + "gitea": { + "branch": "Branch Name", + "repo": "Repository Name", + "token": "Access Token", + "username": "Username" + }, + "giteaHost": "Gitea Address", + "gitee": { + "branch": "Gitee Branch Name", + "repo": "Gitee Repository Name", + "token": "Gitee Access Token", + "username": "Gitee Username" + }, + "github": { + "branch": "GitHub Branch Name", + "repo": "Private Repository Name", + "token": "GitHub Access Token", + "username": "GitHub Username" + }, + "manageConfig": "Manage Configuration", + "migrateFromPicGo": "Migrate from PicGo", + "mirgrateContent": "You are about to import configuration files and albums from PicGo, which will overwrite the current configuration files and albums. Do you want to continue?", + "mirgrateFailed": "Import Failed", + "mirgrateSuccess": "Import Successful, Please Restart PicList to Take Effect", + "mirgrateTitle": "Notification", + "openConfigFile": "Open Configuration File", + "openConfigFileDir": "Open Configuration File Directory", + "selectType": "Please select sync type", + "syncConfigNote": "The files to be synced are configuration files", + "syncConfigProxy": "Proxy", + "syncConfiguration": "Sync Configuration", + "syncEndpointConfig": "Sync Endpoint Configuration", + "syncResult": { "failed": "Sync Failed", "success": "Sync Successful" }, + "title": "Sync", + "upDownloadSettings": "Upload and Download Settings", + "uploadSettings": "Upload Settings", + "webdav": { + "authType": "WebDAV Auth Type", + "enableSSL": "Enable SSL/TLS", + "password": "WebDAV Password", + "savePath": "WebDAV Save Path", + "username": "WebDAV Username" + }, + "webdavEndpoint": "WebDAV Endpoint" + }, + "system": { + "autoCloseMainWindow": "Close Main Window when Opening Mini Window", + "autoCloseMiniWindow": "Close Mini Window when Opening Main Window", + "autoLaunch": "Auto Launch", + "chooseLanguage": "Choose Language", + "customMiniIconPath": "Custom Mini Icon Path", + "hideDockHint": "Cannot hide both dock and tray at the same time", + "isCustomMiniIcon": "Custom Mini Icon", + "isHideDock": "Hide Dock Icon", + "languageAndAppearance": "Language and Appearance", + "mainMode": "Main Mode", + "mainWindowHeight": "Main Window Height", + "mainWindowSize": "Set Main Window Size (Requires Restart)", + "mainWindowWidth": "Main Window Width", + "miniMode": "Mini Mode", + "miniWindowOnTop": "Mini Window On Top", + "needRestart": "Requires restart to take effect", + "noTrayMode": "No Tray Mode", + "quietMode": "Quiet Mode", + "rawPicGoSize": "Original PicGo Window Size, 800x450", + "rawPicGoSizeHint": "Not recommended, only for compatibility with old PicGo window size", + "setMainWindowSize": "Set Main Window Size (Requires Restart)", + "setShortCuts": "Set Shortcuts", + "startMode": "Startup Mode", + "startupAndShortcuts": "Startup and Shortcuts", + "title": "General", + "windowBehavior": "Window Behavior" + }, + "title": "Settings", + "update": { + "applicationUpdates": "Application Updates", + "checkUpdate": "Check for Updates", + "clickToCheck": "Click to Check", + "currentVersion": "Current Version: {version}", + "daysAgo": "{days} days ago", + "getting": "Getting...", + "hasNewVersion": "PicList has been updated, please click OK to restart and trigger the update", + "hoursAgo": "{hours} hours ago", + "justNow": "just now", + "lastUpdated": "Last updated", + "latestReleaseNotes": "Latest Release Notes", + "loadingReleaseNotes": "Loading release notes...", + "minutesAgo": "{minutes} minutes ago", + "networkError": "Network error, please check your network connection", + "newestVersion": "Newest Version: {version}", + "noReleaseNotes": "No release notes available", + "openUpdateHelper": "Open Update Helper", + "openUpdateHelperDesc": "Show notification when a new version is available", + "refresh": "Refresh", + "releaseNotes": "Release Notes", + "releaseNotesDescription": "View the latest changes and updates", + "releaseNotesError": "Failed to load release notes. Please check your network connection.", + "retry": "Retry", + "title": "Update" + }, + "upload": { + "advancedRname": "Advanced Rename", + "advancedRnameFormat": "Advanced Rename Format", + "autoCopyUrlAfterUpload": "Auto Copy URL After Upload", + "autoImportInManage": "Auto Import Configuration in Management Page", + "autoImportInManageHint": "After enabling, the management page will automatically import the corresponding image bed configuration", + "autoImportPicBed": "Select the image bed to enable auto import", + "availablePlaceholders": "Available Placeholders", + "c1nToken": "C1N Token", + "cfWorkerHost": "CF Worker Address", + "chooseShowedPicBed": "Please select the image bed to display in the menu", + "clipboardAndNotification": "Clipboard and Notification", + "copySuccess": "Copy Successful: {content}", + "customLinkFormat": "Custom Link Format", + "deleteCloud": "Sync delete cloud files when deleting in album", + "deleteLocalFileAfterUpload": "Delete Local File After Upload", + "enableAdvancedRname": "Enable Advanced Rename", + "enableSecondPicBed": "Enable Second Image Bed Sync Upload", + "enableSecondPicBedHint": "After enabling, it will sync upload to the second image bed for backup", + "enableShortUrl": "Use Short URL", + "enableUploadNotification": "Enable Upload Progress Notification", + "enableUploadResultNotification": "Enable Upload Result Notification", + "encodeOutputUrl": "Escape output (copy) URL", + "extNamePlaceholder": "Use placeholder $extName to represent the position of the file format", + "fileNamePlaceholder": "Use placeholder $fileName to represent the position of the file name", + "galleryPicBedFilter": "Gallery PicBed Filter", + "galleryPicBedFilterDescription": "Choose which picbeds to show in the gallery. If none are selected, all picbeds will be shown.", + "imageProcessing": "Image Processing Settings", + "isAutoListenClipboard": "Automatically listen for clipboard uploads when the software starts.", + "manualRname": "Manual Rename", + "placeholder": { + "categoryFile": "File Related", + "categoryHash": "Hash Related", + "categoryTime": "Time Related", + "date": "Date, 2 Digits", + "filename": "Original File Name", + "hour": "Hour, 2 Digits", + "localFolder": "Local Folder Structure", + "md5": "MD5 Hash", + "md5-16": "MD5 Hash (First 16 Digits)", + "millisecond": "Millisecond, 3 Digits", + "minute": "Minute, 2 Digits", + "month": "Month, 2 Digits", + "randomString": "Random String (number of digits)", + "second": "Second, 2 Digits", + "sha256": "SHA256 Hash", + "sha256-n": "SHA256 Hash (First n Digits)", + "timestamp": "Timestamp, 13 Digits", + "uuid": "Random UUID", + "year2": "Year, 2 Digits", + "year4": "Year, 4 Digits" + }, + "setSecondPicBed": "Set Second Image Bed", + "shortUrlServer": "Short URL Service", + "sinkDomain": "Sink Domain", + "sinkToken": "Sink Token", + "timestampRname": "Timestamp Rename", + "title": "Upload", + "uploadBehavior": "Upload Behavior", + "uploadProcessing": "Upload Processing", + "urlFormatAndLinkType": "URL Format and Link Type", + "urlPlaceholder": "Use placeholder $url to represent the position of the URL", + "useBuiltInClipboardUpload": "Use Built-in Clipboard Upload", + "useBuiltInClipboardUploadHint": "When disabled, the script file will be used to obtain images.", + "yourlsDomain": "Yourls Domain", + "yourlsSignature": "Yourls Signature" + } + }, + "shortKey": { + "bind": "Shortcut Key Binding", + "changeUpload": "Change Upload Shortcut", + "disable": "Disable", + "disabled": "Disabled", + "edit": "Edit", + "enable": "Enable", + "enabled": "Enabled", + "handle": "Action", + "keyBinding": "Key Binding", + "name": "Shortcut Key Name", + "noBinding": "Not Bound", + "pressHint": "Click the input box and press the keys you want to bind", + "pressKeys": "Press the keys to set the shortcut", + "source": "Source", + "status": "Status", + "title": "Shortcut Key" + }, + "toolbox": { + "autoFixFail": "Automatic repair failed, please fix the following problems yourself", + "checkConfigFileBroken": "Check if the configuration file is damaged", + "checkGalleryFileBroken": "Check if the album file is damaged", + "checkProblemWithClipboardPicUpload": "Check if there is a problem with clipboard picture upload", + "checkProblemWithProxy": "Check if the proxy settings are normal", + "description": "Scan the following items immediately to fix usage issues", + "fixDoneNeedReload": "Repair completed, need to restart to take effect, restart or not", + "notice": "Notice", + "openConfigFile": "Open configuration file", + "openFilePath": "Open file path", + "reScan": "Re scanning", + "startFix": "Start Fixing", + "startScan": "Start Scanning", + "success": "Congratulations, no problems were found", + "title": "Toolbox" + }, + "tray": { + "copySuccess": "Copy Success", + "openMainWindow": "Open Main Window", + "uploaded": "Uploaded", + "waitForUpload": "Waiting for Upload" + }, + "upload": { + "changePicBed": "Change PicBed", + "clickToUpload": "Click to Upload", + "clipboardPicture": "Clipboard", + "dragFileToHere": "Drag file to here, or click to upload", + "dragValidPictureOrUrl": "Please drag a valid picture file or URL here", + "httpPrefixTip": "Starts with http:// or https://", + "imageProcessName": "Image Processing", + "inputUrlTip": "Please enter URL(s)", + "inputValidUrl": "Please enter a valid URL", + "invalidUrlsFound": "Invalid URLs found: {urls}", + "linkFormat": "Link Format", + "multipleUrlsHint": "Each URL on a separate line for multiple uploads", + "outputFormat": "Output Format", + "quickUpload": "Quick Upload", + "uploadFailed": "Upload Failed", + "uploadHint": "All formats are supported, but images are recommended", + "uploadingMultipleUrls": "Uploading {count} URLs...", + "uploadViewHint": "Click to open picbeds settings", + "urlType": { "normal": "Long Link", "short": "Short Link", "title": "Link Type" }, + "urlUpload": "URL Upload" + }, + "uploaderConfig": { + "addNew": "Add New", + "delete": "Delete", + "deleteConfirm": "Are you sure you want to delete this PicBed config?", + "deleteSuccess": "Delete Success", + "deleteTitle": "Notification", + "edit": "Edit", + "selected": "Selected", + "setAsDefault": "Set as Default PicBed", + "setSuccess": "Set Success", + "title": "PicBed Config" } - } + }, + "settings": { + "theme": { + "auto": "Auto", + "autoDesc": "Auto Mode", + "dark": "Dark", + "darkDesc": "Dark Mode", + "light": "Light", + "lightDesc": "Light Mode", + "toggle": "Toggle Theme" + } + }, + "titleBar": { "alwaysOnTop": "Always On Top", "close": "Close", "minimize": "Minimize", "miniWindow": "Mini Window" } } diff --git a/src/renderer/i18n/locales/zh-CN.json b/src/renderer/i18n/locales/zh-CN.json index 24aa85ee..92b4d331 100644 --- a/src/renderer/i18n/locales/zh-CN.json +++ b/src/renderer/i18n/locales/zh-CN.json @@ -1,851 +1,308 @@ { "app": { "title": "PicList" }, - "titleBar": { "alwaysOnTop": "置顶", "close": "关闭", "minimize": "最小化", "miniWindow": "迷你窗口" }, "common": { - "confirm": "确认", "cancel": "取消", "close": "关闭", - "reset": "重置", + "confirm": "确认", "import": "导入", + "reset": "重置", "submit": "提交" }, "navigation": { - "upload": "上传", - "manage": "管理", - "gallery": "相册", - "settings": "设置", - "plugins": "插件", - "picbed": "图床", - "close": "关闭", - "copyPicBedConfig": "复制图床设置", - "selected": "已选中", - "moreOptions": "更多选项", - "picBedQrCode": "图床配置二维码", "choosePicBed": "选择图床", - "selectPicBeds": "请选择图床", - "copySuccess": "复制成功", + "close": "关闭", "collapse": "收起侧边栏", - "expand": "展开侧边栏" - }, - "settings": { - "theme": { - "light": "浅色", - "dark": "深色", - "auto": "自动", - "lightDesc": "明亮模式", - "darkDesc": "黑暗模式", - "autoDesc": "自动模式", - "toggle": "切换主题" - } + "copyPicBedConfig": "复制图床设置", + "copySuccess": "复制成功", + "expand": "展开侧边栏", + "gallery": "相册", + "manage": "管理", + "moreOptions": "更多选项", + "picbed": "图床", + "picBedQrCode": "图床配置二维码", + "plugins": "插件", + "selected": "已选中", + "selectPicBeds": "请选择图床", + "settings": "设置", + "upload": "上传" }, "pages": { - "upload": { - "uploadViewHint": "点击打开图床设置", - "imageProcessName": "图片处理", - "changePicBed": "切换图床", - "dragFileToHere": "将文件拖到此处,或单击上传", - "dragValidPictureOrUrl": "请拖入合法的图片文件或者图片URL地址", - "uploadHint": "支持所有文件类型,但推荐仅上传图片", - "uploadFailed": "上传失败", - "quickUpload": "快捷上传", - "clipboardPicture": "剪贴板图片", - "clickToUpload": "点击上传", - "urlUpload": "URL上传", - "inputUrlTip": "请输入URL地址", - "httpPrefixTip": "http://或https://开头", - "multipleUrlsHint": "多个URL请分行输入", - "inputValidUrl": "请输入合法的URL", - "invalidUrlsFound": "发现无效的URL: {urls}", - "uploadingMultipleUrls": "正在上传 {count} 个URL...", - "linkFormat": "链接格式", - "outputFormat": "输出格式", - "urlType": { "title": "链接类型", "normal": "长链接", "short": "短链接" } - }, - "imageProcess": { - "title": "图片处理设置", - "description": "配置图片处理选项,包括压缩、水印、格式转换等", - "generalSettings": "常规", - "watermarkSettings": "水印", - "transformSettings": "变换", - "cancel": "取消", - "confirm": "确认", - "general": { - "skipProcessExtList": "跳过处理的文件扩展名列表", - "skipProcessExtListLabel": "跳过处理的扩展名", - "skipProcessExtListPlaceholder": "输入要跳过处理的文件扩展名,以逗号分隔(例如:jpg,png,gif)", - "basicImageProcessing": "基本图像处理", - "isRemoveExif": "移除 Exif 信息", - "quality": "压缩质量 (1-100)", - "formatConversion": "图片格式转换", - "isConvert": "转换格式", - "destinationFormat": "目标格式", - "specificFormatConversion": "精细化转换格式,请填写 JSON 格式,如: {'{'}\"png\": \"jpg\"{'}'}" - }, - "watermark": { - "title": "水印设置", - "description": "添加文字或图片水印到图片上", - "isAdd": "启用或禁用水印", - "type": "水印类型", - "text": "文字", - "image": "图片", - "isFullScreen": "是否全屏水印", - "degree": "水印旋转角度", - "scaleRatio": "水印占原图比例", - "inputText": "水印文字", - "inputTextPlaceholder": "请输入水印文字", - "textFontPath": "水印字体路径(第一次使用前自动下载)", - "textFontPathPlaceholder": "可选,请输入路径", - "color": "水印颜色,手动输入或取色器", - "imagePath": "水印图片路径(留空使用默认图片)", - "imagePathPlaceholder": "可选,请输入路径", - "position": "水印位置", - "positionOptions": { - "top": "上", - "bottom": "下", - "left": "左", - "right": "右", - "topLeft": "左上", - "topRight": "右上", - "bottomLeft": "左下", - "bottomRight": "右下", - "center": "中" - }, - "imageOpacity": "水印透明度" - }, - "transform": { - "title": "变换设置", - "description": "调整图片大小、旋转、翻转等", - "isFlip": "垂直翻转", - "isFlop": "水平翻转", - "rotationTitle": "旋转设置", - "rotationDescription": "设置图片旋转参数", - "isRotate": "启用旋转", - "rotationDegree": "旋转角度", - "resizeTitle": "调整大小", - "resizeDescription": "设置图片缩放参数", - "isResize": "启用调整大小", - "resizeWidth": "调整宽度 (0 表示按高度等比缩放)", - "resizeHeight": "调整高度 (0 表示按宽度等比缩放)", - "skipResizeOfSmallImgHeight": "当图片小于设定时跳过缩放", - "percentageResize": "按比例调整尺寸", - "isResizeByPercent": "启用按比例调整", - "isResizeByPercentHint": "优先级更高", - "resizePercent": "调整比例 (输入 50 表示 50%)" - }, - "perPicBed": { - "title": "图床独立设置", - "description": "为每个图床单独配置设置" - } - }, - "settings": { - "title": "设置", - "description": "配置 PicList 应用程序", - "docs": "文档", - "clickToSet": "点击设置", - "clickToOpen": "点击打开", - "system": { - "title": "通用", - "languageAndAppearance": "语言和外观", - "chooseLanguage": "选择语言", - "startMode": "启动模式", - "quietMode": "静默模式", - "miniMode": "迷你窗口", - "mainMode": "主窗口", - "noTrayMode": "隐藏托盘", - "windowBehavior": "窗口行为", - "isHideDock": "是否隐藏 Dock 图标", - "hideDockHint": "不支持同时隐藏 dock 和托盘", - "needRestart": "需要重启生效", - "mainWindowSize": "设置主窗口大小(需重启)", - "autoCloseMiniWindow": "打开主窗口时关闭迷你窗口", - "autoCloseMainWindow": "打开迷你窗口时关闭主窗口", - "miniWindowOnTop": "迷你窗口置顶", - "isCustomMiniIcon": "是否自定义迷你窗口图标", - "customMiniIconPath": "自定义迷你窗口图标路径", - "startupAndShortcuts": "启动和快捷键", - "autoLaunch": "开机自启", - "setShortCuts": "设置快捷键", - "setMainWindowSize": "设置主窗口大小(需重启)", - "mainWindowHeight": "主窗口高度", - "mainWindowWidth": "主窗口宽度", - "rawPicGoSize": "原 PicGo 窗口大小, 800x450", - "rawPicGoSizeHint": "不推荐使用, 仅用于兼容旧 PicGo 窗口大小" - }, - "sync": { - "title": "配置/同步", - "syncConfiguration": "同步配置", - "syncEndpointConfig": "同步方案配置", - "upDownloadSettings": "上传下载配置文件", - "uploadSettings": "上传配置", - "downloadSettings": "下载配置", - "syncResult": { "success": "同步成功", "failed": "同步失败" }, - "commonConfig": "通用配置", - "manageConfig": "管理配置", - "allConfig": "所有配置", - "migrateFromPicGo": "从PicGo迁移", - "mirgrateTitle": "通知", - "mirgrateContent": "即将导入PicGo的配置文件和相册, 这将覆盖当前的配置文件和相册, 是否继续?", - "mirgrateSuccess": "导入成功, 请重启PicList生效", - "mirgrateFailed": "导入失败", - "fileManagement": "文件管理", - "openConfigFile": "打开配置文件", - "openConfigFileDir": "打开配置文件目录", - "syncConfigNote": "同步的文件为配置文件", - "selectType": "请选择同步类型", - "giteaHost": "Gitea 地址", - "webdavEndpoint": "WebDAV 端点", - "gitea": { "username": "用户名", "repo": "仓库名", "branch": "分支名", "token": "访问令牌" }, - "github": { - "username": "GitHub 用户名", - "repo": "私有仓库名", - "branch": "GitHub 分支名", - "token": "GitHub 访问令牌" - }, - "gitee": { - "username": "Gitee 用户名", - "repo": "Gitee 仓库名", - "branch": "Gitee 分支名", - "token": "Gitee 访问令牌" - }, - "webdav": { - "username": "WebDAV 用户名", - "password": "WebDAV 密码", - "savePath": "WebDAV 保存路径", - "authType": "WebDAV 认证类型", - "enableSSL": "启用 SSL/TLS" - }, - "syncConfigProxy": "代理" - }, - "upload": { - "title": "上传", - "uploadBehavior": "上传行为", - "autoImportInManage": "管理页面自动导入配置", - "autoImportInManageHint": "启用后,管理页面将自动导入对应图床配置", - "autoImportPicBed": "选择需要开启自动导入的图床", - "enableSecondPicBed": "启用第二图床同步上传", - "enableSecondPicBedHint": "启用后,将同步上传到第二图床,用于备份", - "setSecondPicBed": "设置第二图床", - "uploadProcessing": "上传处理", - "deleteCloud": "相册内删除时同步删除云端文件", - "manualRname": "手动重命名", - "timestampRname": "时间戳重命名", - "advancedRname": "高级重命名", - "enableAdvancedRname": "开启高级重命名", - "advancedRnameFormat": "高级重命名格式", - "availablePlaceholders": "可用占位符", - "copySuccess": "复制成功: {content}", - "placeholder": { - "categoryTime": "时间相关", - "categoryHash": "哈希相关", - "categoryFile": "文件相关", - "year4": "年份,4位数", - "year2": "年份,2位数", - "month": "月份,2位数", - "date": "日期,2位数", - "hour": "小时,2位数", - "minute": "分钟,2位数", - "second": "秒,2位数", - "millisecond": "毫秒,3位数", - "timestamp": "时间戳,13位数", - "md5": "MD5 哈希", - "md5-16": "MD5 哈希(前16位)", - "localFolder": "本地文件夹层级", - "filename": "文件原名", - "randomString": "number位随机字符串", - "uuid": "随机 UUID", - "sha256": "SHA256 哈希", - "sha256-n": "SHA256 哈希(前n位)" - }, - "imageProcessing": "图片预处理设置", - "deleteLocalFileAfterUpload": "上传后删除本地文件", - "clipboardAndNotification": "剪贴板和通知", - "enableUploadNotification": "开启上传进度提示", - "enableUploadResultNotification": "开启上传结果提示", - "autoCopyUrlAfterUpload": "上传后自动复制URL", - "useBuiltInClipboardUpload": "使用系统内置剪贴板上传", - "useBuiltInClipboardUploadHint": "关闭时会使用脚本文件获取图片", - "isAutoListenClipboard": "软件启动时自动监听剪贴板上传", - "urlFormatAndLinkType": "链接格式和类型", - "customLinkFormat": "自定义链接格式", - "urlPlaceholder": "用占位符 $url 来表示 URL 的位置", - "fileNamePlaceholder": "用占位符 $fileName 来表示文件名的位置", - "extNamePlaceholder": "用占位符 $extName 来表示文件格式的位置", - "enableShortUrl": "使用短链接", - "shortUrlServer": "短链接服务", - "c1nToken": "C1N Token", - "yourlsDomain": "Yourls 域名", - "yourlsSignature": "Yourls 密钥", - "cfWorkerHost": "CF Worker 地址", - "sinkDomain": "Sink 域名", - "sinkToken": "Sink Token", - "encodeOutputUrl": "输出(复制) URL 时进行转义", - "chooseShowedPicBed": "请选择显示在菜单的图床", - "galleryPicBedFilter": "相册图床过滤器", - "galleryPicBedFilterDescription": "选择在相册中显示的图床类型。如果未选择任何图床,将显示所有图床。" - }, - "advanced": { - "title": "高级", - "logging": "日志", - "logFilePath": "日志文件路径", - "setLog": "设置日志", - "logFile": "常规日志文件", - "guiLogFile": "GUI 日志文件", - "manageLogFile": "管理日志文件", - "logLevel": "日志记录等级", - "chooseLogLevel": "请选择日志记录等级", - "logFileSize": "日志文件大小", - "networkAndProxy": "网络与代理", - "setProxyAndMirror": "设置代理和镜像地址", - "uploadProxy": "上传代理", - "pluginInstallProxy": "插件安装代理", - "pluginInstallMirror": "插件安装镜像", - "serverSettings": "服务器设置", - "enableServer": "是否开启上传API服务", - "uploadServer": "上传API服务设置", - "serverSettingsNotice": "如果你不知道上传API服务的作用,请阅读文档,或者不用修改配置。", - "serverHost": "监听地址", - "serverPort": "监听端口", - "serverKey": "鉴权密钥", - "serverKeyPlaceholder": "请输入鉴权密钥,用于防止接口滥用", - "webServerSettings": "Web 服务设置", - "webServerNotice": "如果你不知道 Web 服务的作用,请阅读文档,或者不用修改配置。", - "enableWebServer": "是否开启 Web 服务", - "webServerHost": "Web 服务监听地址", - "webServerPort": "Web 服务监听端口", - "webServerPath": "Web 服务路径", - "webServerPlaceholderHost": "推荐默认地址: 127.0.0.1", - "webServerPlaceholderPort": "推荐默认端口: 37777", - "serverEncryptionKey": "接口数据加密密钥", - "logLevelList": { - "all": "全部", - "success": "成功", - "info": "信息", - "warn": "警告", - "error": "错误", - "none": "不记录日志" - } - }, - "update": { - "title": "更新", - "applicationUpdates": "应用程序更新", - "checkUpdate": "检查更新", - "clickToCheck": "点击检查", - "openUpdateHelper": "打开更新提醒", - "openUpdateHelperDesc": "当有新版本时显示通知", - "currentVersion": "当前版本: {version}", - "newestVersion": "最新版本", - "getting": "正在获取中...", - "hasNewVersion": "PicList 更新啦,请点击确定重启触发更新", - "networkError": "网络错误,请检查网络连接", - "releaseNotes": "版本说明", - "releaseNotesDescription": "查看最新的更改和更新内容", - "latestReleaseNotes": "最新版本说明", - "refresh": "刷新", - "retry": "重试", - "loadingReleaseNotes": "正在加载版本说明...", - "releaseNotesError": "加载版本说明失败,请检查网络连接。", - "noReleaseNotes": "暂无版本说明", - "lastUpdated": "最后更新", - "justNow": "刚刚", - "minutesAgo": "{minutes} 分钟前", - "hoursAgo": "{hours} 小时前", - "daysAgo": "{days} 天前" - } - }, - "plugin": { - "title": "插件", - "description": "PicList 插件管理页面", - "importLocal": "导入本地插件", - "updateAll": "更新全部插件", - "list": "插件列表", - "searchPlaceholder": "搜索 npm 上的 PicGo 插件,或者点击上方按钮查看优秀插件列表", - "needRestart": "需要重启生效", - "restartApp": "重启应用", - "loading": "加载中...", - "install": "安装", - "installing": "安装中", - "installed": "已安装", - "doingSomething": "进行中", - "settings": "设置", - "disabled": "已禁用", - "noPluginsFound": "未找到插件", - "tryDifferentSearch": "尝试不同的搜索关键词", - "NoPluginsInstalled": "暂无已安装插件", - "installPluginsToGetStarted": "请先安装插件以开始使用", - "browsePlugins": "浏览插件", - "configThing": "配置 {c}", - "pluginList": "插件列表", - "notGuiImplement": "该插件未对可视化界面进行优化, 是否继续安装?", - "updateSuccess": "插件更新成功", - "setResult": "设置结果", - "setSuccess": "设置成功" - }, - "inputBox": { - "title": "输入框" - }, "configForm": { "configName": "配置名", "configNamePlaceholder": "请输入配置名称" }, - "rename": { - "placeholder": "请输入新的文件名" - }, - "shortKey": { - "title": "快捷键", - "name": "快捷键名称", - "bind": "快捷键绑定", - "status": "状态", - "source": "来源", - "handle": "操作", - "noBinding": "未绑定", - "enable": "启用", - "disable": "禁用", - "enabled": "已启用", - "disabled": "已禁用", - "edit": "编辑", - "changeUpload": "修改上传快捷键", - "keyBinding": "按键绑定", - "pressKeys": "按下要设置的快捷键", - "pressHint": "点击输入框并按下你想要绑定的按键" - }, - "picBedConfigs": { - "title": "配置", - "viewDoc": "查看文档", - "copyAPI": "复制上传API", - "noConfigOptions": "暂无配置项", - "setSuccess": "设置成功", - "setFailedInfo": "设置失败, 请检查配置项是否正确", - "loadConfigFailed": "加载配置失败, 请检查配置文件是否正确", - "loadPicBedListFailed": "加载图床列表失败", - "importConfigSuccess": "导入配置成功", - "importConfigFailed": "导入配置失败", - "resetSuccess": "重置成功", - "resetFailed": "重置失败, 请检查配置项是否正确", - "viewDocFailed": "查看文档失败", - "noConfigs": "配置为空", - "copyAPISucceed": "复制API地址成功", - "copyAPIFailed": "复制API地址失败" - }, - "uploaderConfig": { - "title": "图床配置", - "selected": "已选中", - "edit": "编辑", - "delete": "删除", - "addNew": "新增", - "setAsDefault": "设为默认图床", - "setSuccess": "设置成功", - "deleteTitle": "通知", - "deleteConfirm": "确认删除图床配置吗?", - "deleteSuccess": "删除成功" - }, - "toolbox": { - "title": "工具箱", - "description": "立即扫描以下项目,修复使用问题", - "startScan": "开始扫描", - "success": "恭喜你,没有检查出问题", - "startFix": "开始修复", - "autoFixFail": "自动修复失败,请自行修复以下问题", - "reScan": "重新扫描", - "checkConfigFileBroken": "检查配置文件是否损坏", - "openConfigFile": "打开配置文件", - "checkGalleryFileBroken": "检查相册文件是否损坏", - "checkProblemWithClipboardPicUpload": "检查剪贴板图片上传是否存在问题", - "openFilePath": "打开文件路径", - "checkProblemWithProxy": "检查代理设置是否正常", - "fixDoneNeedReload": "修复完成,需要重启生效,是否重启", - "notice": "通知" - }, "gallery": { - "title": "相册", - "images": "图片", - "syncDelete": "删除云端", - "hideFilters": "过滤器", - "showFilters": "过滤器", - "refresh": "刷新", - "picBedType": "图床类型", - "chooseShowedPicBed": "请选择显示的图床", - "selected": "已选择", - "dateRange": "日期范围", - "pasteFormat": "粘贴格式", - "urlType": "链接类型", - "sort": "排序", - "sortBy": { - "name": "名称", - "time": "日期", - "ext": "后缀", - "check": "已选中" - }, - "searchFilename": "搜索文件名", - "searchUrl": "搜索URL", - "copy": "复制", - "edit": "编辑", - "delete": "删除", - "selectAll": "全选", - "cancel": "取消", - "noImagesFound": "未找到图片", - "tryAdjustingFilters": "尝试调整过滤器或上传一些图片", - "changeImageUrl": "修改图片URL", "batchEditUrl": "批量修改URL", + "cancel": "取消", + "canceled": "已取消", + "changeImageUrl": "修改图片URL", + "chooseShowedPicBed": "请选择显示的图床", + "cloudDeleteFailed": "云端删除失败", + "cloudDeleteSucceed": "云端删除成功", + "confirmRemove": "确认删除选中的图片吗?", + "copy": "复制", + "copyLinkSucceed": "复制链接成功", + "dateRange": "日期范围", + "delete": "删除", + "edit": "编辑", + "gridView": "网格", + "haveDuplicate": "已选中的图片中有命名重复, 是否继续?", + "hideFilters": "过滤器", + "images": "图片", + "inputRegexTip": "请输入匹配字符串", + "isAlwaysForceReload": "禁用缓存", + "listView": "列表", + "longUrl": "长链接", + "noImagesFound": "未找到图片", + "noItemsNeedRename": "没有需要重命名的项目", + "noMatch": "未找到匹配项", + "notice": "通知", + "operationFailed": "操作失败", + "operationSucceed": "操作成功", + "pasteFormat": "粘贴格式", + "picBedType": "图床类型", + "previewHelp": "滚轮缩放 • 拖拽平移 • 方向键导航 • ESC关闭", + "refresh": "刷新", "regexPattern": "进行替换时匹配的字符串或js正则表达式 匹配到: {matched} 个", "regexPatternPlaceholder": "例如:^\\d{4}-\\d{2}-\\d{2}, 不包含正则两边的斜杠", "replacedWith": "需要替换的字符串,可使用自定义重命名规则中的占位符", - "longUrl": "长链接", + "searchFilename": "搜索文件名", + "searchUrl": "搜索URL", + "selectAll": "全选", + "selected": "已选择", "shortUrl": "短链接", - "copyLinkSucceed": "复制链接成功", - "notice": "通知", - "confirmRemove": "确认删除选中的图片吗?", - "cloudDeleteSucceed": "云端删除成功", - "cloudDeleteFailed": "云端删除失败", - "operationSucceed": "操作成功", - "operationFailed": "操作失败", - "haveDuplicate": "已选中的图片中有命名重复, 是否继续?", - "canceled": "已取消", - "previewHelp": "滚轮缩放 • 拖拽平移 • 方向键导航 • ESC关闭", - "listView": "列表", - "gridView": "网格", - "isAlwaysForceReload": "禁用缓存", - "inputRegexTip": "请输入匹配字符串", - "noMatch": "未找到匹配项", - "noItemsNeedRename": "没有需要重命名的项目" + "showFilters": "过滤器", + "sort": "排序", + "sortBy": { + "check": "已选中", + "ext": "后缀", + "name": "名称", + "time": "日期" + }, + "syncDelete": "删除云端", + "title": "相册", + "tryAdjustingFilters": "尝试调整过滤器或上传一些图片", + "urlType": "链接类型" }, - "tray": { - "openMainWindow": "打开主窗口", - "waitForUpload": "等待上传", - "uploaded": "已上传", - "copySuccess": "复制成功" + "imageProcess": { + "cancel": "取消", + "confirm": "确认", + "description": "配置图片处理选项,包括压缩、水印、格式转换等", + "general": { + "basicImageProcessing": "基本图像处理", + "destinationFormat": "目标格式", + "formatConversion": "图片格式转换", + "isConvert": "转换格式", + "isRemoveExif": "移除 Exif 信息", + "quality": "压缩质量 (1-100)", + "skipProcessExtList": "跳过处理的文件扩展名列表", + "skipProcessExtListLabel": "跳过处理的扩展名", + "skipProcessExtListPlaceholder": "输入要跳过处理的文件扩展名,以逗号分隔(例如:jpg,png,gif)", + "specificFormatConversion": "精细化转换格式,请填写 JSON 格式,如: {'{'}\"png\": \"jpg\"{'}'}" + }, + "generalSettings": "常规", + "perPicBed": { + "description": "为每个图床单独配置设置", + "title": "图床独立设置" + }, + "title": "图片处理设置", + "transform": { + "description": "调整图片大小、旋转、翻转等", + "isFlip": "垂直翻转", + "isFlop": "水平翻转", + "isResize": "启用调整大小", + "isResizeByPercent": "启用按比例调整", + "isResizeByPercentHint": "优先级更高", + "isRotate": "启用旋转", + "percentageResize": "按比例调整尺寸", + "resizeDescription": "设置图片缩放参数", + "resizeHeight": "调整高度 (0 表示按宽度等比缩放)", + "resizePercent": "调整比例 (输入 50 表示 50%)", + "resizeTitle": "调整大小", + "resizeWidth": "调整宽度 (0 表示按高度等比缩放)", + "rotationDegree": "旋转角度", + "rotationDescription": "设置图片旋转参数", + "rotationTitle": "旋转设置", + "skipResizeOfSmallImgHeight": "当图片小于设定时跳过缩放", + "title": "变换设置" + }, + "transformSettings": "变换", + "watermark": { + "color": "水印颜色,手动输入或取色器", + "degree": "水印旋转角度", + "description": "添加文字或图片水印到图片上", + "image": "图片", + "imageOpacity": "水印透明度", + "imagePath": "水印图片路径(留空使用默认图片)", + "imagePathPlaceholder": "可选,请输入路径", + "inputText": "水印文字", + "inputTextPlaceholder": "请输入水印文字", + "isAdd": "启用或禁用水印", + "isFullScreen": "是否全屏水印", + "position": "水印位置", + "positionOptions": { + "bottom": "下", + "bottomLeft": "左下", + "bottomRight": "右下", + "center": "中", + "left": "左", + "right": "右", + "top": "上", + "topLeft": "左上", + "topRight": "右上" + }, + "scaleRatio": "水印占原图比例", + "text": "文字", + "textFontPath": "水印字体路径(第一次使用前自动下载)", + "textFontPathPlaceholder": "可选,请输入路径", + "title": "水印设置", + "type": "水印类型" + }, + "watermarkSettings": "水印" + }, + "inputBox": { + "title": "输入框" }, "manage": { - "main": { - "openPicBedUrl": "打开图床官网", - "newBucket": "新建存储桶", - "loading": "加载中...", - "backToHome": "首页", - "switchPicBed": "切换", - "settings": "设置", - "bucket": "存储桶", - "gallery": "相册", - "repo": "仓库", - "createSuccess": "创建成功", - "createFailed": "创建失败" - }, - "empty": { - "noData": "暂无数据", - "noDataDesc": "请先创建存储桶或上传图片" - }, - "setting": { - "clearCache": "清空文件列表缓存数据库,已使用 {size} 可用 {percent}%", - "clearCacheMsg": "确定要清空缓存吗?", - "isAutoRefreshTitle": "每次进入新目录时,是否自动刷新文件列表", - "isAutoRefreshTips": "仅对不分页模式有效,默认在加载过一次后自动缓存到数据库来加快下次加载速度", - "isShowThumbnailTitle": "图片显示为原图而非默认文件格式图标(需要存储桶可公开访问)", - "isUsePreSignedUrlTitle": "是否使用预签名URL预览图片", - "isForceCustomUrlHttpsTitle": "为自定义域名开启强制HTTPS", - "isForceCustomUrlHttpsTips": "开启后, 复制链接等操作将会自动为自定义域名添加https前缀", - "isEncodeUrlTitle": "复制链接时进行URL编码", - "isEncodeUrlTips": "根据平台选择是否开启", - "isUploadKeepDirStructureTitle": "上传时保持目录结构", - "isUploadKeepDirStructureTips": "关闭后会将所有文件展开到指定目录下", - "isIgnoreCaseTitle": "文件搜索时,是否忽略大小写", - "isIgnoreCaseTips": "建议开启", - "timestampRenameTitle": "上传文件时间戳重命名(最高优先级)", - "timestampRenameTips": "开启后,上传的文件将自动重命名为时间戳", - "randomStringRenameTitle": "上传文件随机字符串重命名(中优先级)", - "randomStringRenameTips": "20位随机字符", - "customRenameTitle": "上传文件自定义重命名(低优先级)", - "customRenameTips": "开启后填写命名格式", - "customRenameTableTitle": "自定义重命名格式参考表", - "customRenameTablePlaceholder": "请输入自定义重命名格式", - "placeholder": "占位符", - "description": "描述", - "copySuccess": "已复制 {name}", - "download": "下载", - "file": "文件", - "folder": "文件夹", - "keepDirStructure": "保持目录结构", - "keepDirStructureDesc": "开启后,下载时会保持原始目录结构", - "clearSuccess": "清空缓存成功", - "clearFailed": "清空缓存失败", - "notice": "通知", - "maxDownLoadFileLimit": "最大并行下载文件数", - "maxDownLoadFileLimitDesc": "建议根据网络情况调整", - "preSignedUrlExpire": "预签名URL过期时间(单位: 秒)", - "preSignedUrlExpireDesc": "建议根据实际需求调整", - "copyFormat": { - "title": "复制格式", - "markdown": "Markdown", - "rawurl": "原始URL", - "markdown-with-link": "Markdown(带链接)", - "html": "HTML格式", - "bbcode": "BBCode格式", - "custom": "自定义格式", - "customTitle": "自定义链接格式($url为链接,$fileName为文件名)", - "customTips": "请根据实际需求填写自定义格式" - }, - "selectDownloadFolderTitle": "选择下载文件夹", - "selectDownloadFolderTips": "选择下载目录", - "defaultDownloadFolder": "系统默认下载文件夹", - "browse": "浏览" - }, "bucket": { - "selectCustomDomain": "选择自定义域名", - "inputCustomDomain": "输入自定义域名", - "uploadFiles": "上传文件", - "uploadFromUrl": "从URL上传", - "createFolder": "创建文件夹", - "downloadPage": "下载页面", "batchRename": "批量重命名", - "copyFileIno": "拷贝文件信息", - "forceRefreshFileList": "强制刷新文件列表", - "searchPlaceholder": "搜索文件名", - "rootFolder": "根目录", - "fileNum": "文件数: {num}", - "pageFileSize": "总大小: {size}", - "selectAll": "全选", "cancel": "取消", - "reverseSelect": "反选", + "canceled": "已取消", + "clear": "清空", + "clearAll": "清空所有任务", + "clearFinishedTasks": "清空已完成任务", + "clickUpload": "或: 点击选择文件", + "copyDownloadTask": "复制下载任务信息", + "copyFileInfoInJson": "复制文件信息为JSON", + "copyFileIno": "拷贝文件信息", + "copySuccess": "复制成功", + "copyUploadTask": "复制上传任务信息", + "createFailed": "创建失败", + "createFolder": "创建文件夹", + "createSuccess": "创建成功,请刷新", + "deleteFailed": "删除失败", + "deleteMsg": "将永久删除,是否继续?", + "deleteMultiMsg": "删除成功 {success} 个, 失败 {failed} 个", + "deleteSuccess": "删除成功", + "deletingMsg": "正在删除中,请稍候...", "downloadBtn": "下载 {num}", + "downloadFolderNotice": "确定要下载该文件夹吗?", + "downloading": "下载中", + "downloadPage": "下载页面", + "dragUpload": "拖拽上传 支持目录", + "enterFullScreen": "进入全屏(F11)", + "excludeExt": "替换时不包含后缀名", + "exitFullScreen": "退出全屏(F11)", + "failed": "失败", + "fileDupNotice": "检测到有 {number} 个文件名重复, 是否继续?", + "fileInfo": "文件信息", + "fileNum": "文件数: {num}", + "forceRefreshFileList": "强制刷新文件列表", + "getDownloadListFailed": "获取下载列表失败", + "getDownloadListSuccess": "获取下载列表成功", + "getFileListFailed": "获取文件列表失败", + "getFileListSuccess": "获取文件列表成功", + "getInBackground": "正在后台获取文件列表,请不要切换页面", + "includeExt": "替换时包含后缀名", + "inputCustomDomain": "输入自定义域名", + "inputFolderTitle": "请输入文件夹名称", + "inputPatternMsg": "请输入匹配字符串", + "inputValidUrlMsg": "请输入有效的URL", + "isLoadingMsg": "正在加载中,请稍候...", + "keepDirStructure": "保持目录结构", + "lastPageMsg": "已是最后一页", + "linkFormat": { + "bbcode": "BBCode", + "custom": "自定义", + "html": "HTML", + "markdown": "Markdown", + "markdown-with-link": "Markdown(带链接)", + "presign": "预签名链接", + "url": "Url" + }, + "loading": "加载中,点击取消", + "loadingFailed": "加载失败", + "matchedPattern": "匹配用字符串或正则表达式 - 已匹配 {num} 个", + "noFileNeedRename": "没有需要重命名的文件", + "noKeepDirStructure": "不保持目录结构", + "noMatchedFile": "未找到匹配文件", + "noNeedToRename": "无需重命名", + "notice": "通知", + "openDownloadFolder": "打开下载文件夹", + "pageFileSize": "总大小: {size}", + "partFileListFailed": "部分文件获取失败", + "play": "播放", + "prepareDownload": "准备下载中,点击取消", + "preview": "预览", + "readingDir": "读取中,请稍候", + "regexPatternTips": "正则表达式不需要加/", + "regexPlaceholder": "请输入正则表达式或匹配字符串", "removeBtn": "删除 {num}", + "renameFailed": "重命名失败", + "renameFile": "重命名文件", + "renameResultMsg": "重命名成功 {success} 个, 失败 {failed} 个", + "renameSuccess": "重命名成功", + "replaceInput": "需要替换为的字符串,可以使用自定义重命名中的占位符", + "reverseSelect": "反选", + "rootFolder": "根目录", + "searchPlaceholder": "搜索文件名", + "selectAll": "全选", + "selectCustomDomain": "选择自定义域名", + "selectFileMsg": "请先选择文件", "sort": { - "title": "排序", + "check": "选中状态", + "ext": "类型", + "init": "初始化", "name": "文件名", "size": "大小", "time": "时间", - "ext": "类型", - "check": "选中状态", - "init": "初始化" + "title": "排序" }, - "enterFullScreen": "进入全屏(F11)", - "exitFullScreen": "退出全屏(F11)", - "linkFormat": { - "url": "Url", - "markdown": "Markdown", - "markdown-with-link": "Markdown(带链接)", - "html": "HTML", - "bbcode": "BBCode", - "custom": "自定义", - "presign": "预签名链接" - }, - "urlUploadTitle": "请输入URL,换行分隔", - "fileInfo": "文件信息", - "copyFileInfoInJson": "复制文件信息为JSON", - "renameFile": "重命名文件", - "matchedPattern": "匹配用字符串或正则表达式 - 已匹配 {num} 个", - "regexPatternTips": "正则表达式不需要加/", - "regexPlaceholder": "请输入正则表达式或匹配字符串", - "replaceInput": "需要替换为的字符串,可以使用自定义重命名中的占位符", - "excludeExt": "替换时不包含后缀名", - "includeExt": "替换时包含后缀名", - "loading": "加载中,点击取消", - "prepareDownload": "准备下载中,点击取消", - "keepDirStructure": "保持目录结构", - "noKeepDirStructure": "不保持目录结构", - "uploadFile": "上传文件", - "dragUpload": "拖拽上传 支持目录", - "clickUpload": "或: 点击选择文件", - "readingDir": "读取中,请稍候", - "upload": "上传", - "clear": "清空", - "uploading": "上传中", - "success": "成功", - "failed": "失败", - "copyUploadTask": "复制上传任务信息", - "clearFinishedTasks": "清空已完成任务", - "clearAll": "清空所有任务", - "downloading": "下载中", - "copyDownloadTask": "复制下载任务信息", - "openDownloadFolder": "打开下载文件夹", - "preview": "预览", - "play": "播放", - "notice": "通知", - "downloadFolderNotice": "确定要下载该文件夹吗?", - "getDownloadListSuccess": "获取下载列表成功", - "getDownloadListFailed": "获取下载列表失败", - "canceled": "已取消", - "copySuccess": "复制成功", - "deleteSuccess": "删除成功", - "deleteFailed": "删除失败", - "deleteMultiMsg": "删除成功 {success} 个, 失败 {failed} 个", "startLoadingFile": "开始加载文件", - "loadingFailed": "加载失败", - "lastPageMsg": "已是最后一页", - "getFileListSuccess": "获取文件列表成功", - "getFileListFailed": "获取文件列表失败", - "partFileListFailed": "部分文件获取失败", - "getInBackground": "正在后台获取文件列表,请不要切换页面", - "isLoadingMsg": "正在加载中,请稍候...", - "inputFolderTitle": "请输入文件夹名称", - "createSuccess": "创建成功,请刷新", - "createFailed": "创建失败", - "inputValidUrlMsg": "请输入有效的URL", "startUploadMsg": "开始后台下载,成功后自动上传", - "inputPatternMsg": "请输入匹配字符串", - "noMatchedFile": "未找到匹配文件", - "noFileNeedRename": "没有需要重命名的文件", - "fileDupNotice": "检测到有 {number} 个文件名重复, 是否继续?", - "renameResultMsg": "重命名成功 {success} 个, 失败 {failed} 个", - "selectFileMsg": "请先选择文件", + "stopGetDownloadListMsg": "是否停止下载文件获取?", "stopGetFileListMsg": "是否停止获取文件列表?", "stopSuccessMsg": "停止成功", - "stopGetDownloadListMsg": "是否停止下载文件获取?", - "willDeleteMsg": "即将删除 {num} 个文件,是否继续?", - "deleteMsg": "将永久删除,是否继续?", - "deletingMsg": "正在删除中,请稍候...", - "noNeedToRename": "无需重命名", - "renameSuccess": "重命名成功", - "renameFailed": "重命名失败" - }, - "newBucket": { - "bucketDesc": "存储桶名", - "bucketPlaceholder": "请输入存储桶名", - "bucketNoEmpty": "存储桶名不能为空", - "region": "区域", - "acl": { - "title": "访问控制", - "private": "私有", - "publicRead": "公共读", - "publicReadWrite": "公共读写", - "authenticatedRead": "已认证读" - }, - "tcyun": { - "name": "腾讯云", - "bucketLengthMsg": "Bucket名称长度不能超过23个字符", - "bucketCharMsg": "Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾" - }, - "aliyun": { - "name": "阿里云", - "bucketLengthMsg": "Bucket名称长度必须在3到63个字符之间", - "bucketCharMsg": "Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾" - }, - "qiniu": { - "name": "七牛云", - "bucketLengthMsg": "Bucket名称长度必须在3到63个字符之间", - "bucketCharMsg": "Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾", - "publicAccess": "公共访问" - }, - "s3": { - "name": "S3" - } - }, - "login": { - "title": "图床管理", - "savedConfigs": "已保存配置", - "refresh": "刷新", - "noConfigs": "未找到配置", - "noConfigsDesc": "请检查您的配置文件或重新加载页面", - "viewDetails": "查看详情", - "enter": "进入", - "delete": "删除", - "selectPlaceholder": "请选择", - "import": "导入", - "save": "保存", - "reset": "重置", - "configTabTitle": "已有配置,单击复制", - "noRequiredMsg": "请填写必填项", - "aliasMsg": "别名只能包含中文、英文、数字、下划线和中划线", - "itemsPerPageMsg": "每页显示项数必须为20-1000之间的整数", - "configChangeMsg": "配置已更改", - "configSaveMsg": "配置已保存", - "deleteConfigSuccessMsg": "删除配置成功", - "deleteConfigFailedMsg": "删除配置失败", - "copySuccess": "复制成功: {text}", - "importSuccess": "导入成功", - "tips": "提示", - "confirmDeleteConfig": "确认删除配置吗?" + "success": "成功", + "upload": "上传", + "uploadFile": "上传文件", + "uploadFiles": "上传文件", + "uploadFromUrl": "从URL上传", + "uploading": "上传中", + "urlUploadTitle": "请输入URL,换行分隔", + "willDeleteMsg": "即将删除 {num} 个文件,是否继续?" }, "constant": { - "pleaseInput": "请输入: {name}", - "inputItemsPerPage": "输入每页显示的项数", - "itemsPPBeNumber": "每页显示的项数必须为数字", - "itemsPPBeNumberLimit": "每页显示的项数必须在20到1000之间", - "inputAlias": "请输入别名,配置的唯一标识", - "aliasRuleMsg": "别名只能包含中文、英文、数字、下划线和中划线", - "aliasTip": "别名只能包含中文、英文、数字、下划线和中划线", - "itemsPPTip": "每页显示的项数必须在20到1000之间", - "pagingTip": "关闭分页时,目录列表将使用数据库缓存以优化性能", - "bucketNameTip": "英文逗号分隔,例如: bucket1,bucket2,与起始目录一一对应", - "baseDirTip": "英文逗号分隔,例如: /dir1,/dir2,与存储桶一一对应", - "isAutoCustomUrlTip": "开启时,将自动获取存储桶绑定的域名", - "aliasDesc": "配置别名", - "aliasPlaceholder": "该配置的唯一标识", - "pagingDesc": "是否开启分页", - "referText": "配置教程请参考:", "accessKeyDesc": "Access Key, 可在控制台获取", - "accessKeyPlaceholder": "请输入 Access Key", "accessKeyIdDesc": "Access Key ID, 可在控制台获取", "accessKeyIdPlaceholder": "请输入 Access Key ID", - "secretIdDesc": "Secret ID, 可在控制台获取", - "secretIdPlaceholder": "请输入 Secret ID", - "secretKeyDesc": "Secret Key, 可在控制台获取", - "secretKeyPlaceholder": "请输入Secret Key", + "accessKeyPlaceholder": "请输入 Access Key", "accessKeySecretDesc": "Access Key Secret, 可在控制台获取", "accessKeySecretPlaceholder": "请输入 Access Key Secret", - "secretKeyIdDesc": "Secret Key, 可在控制台获取", - "secretKeyIdPlaceholder": "请输入 Secret Key", - "bucketDesc": "存储桶名,可选项", - "bucketPlaceholder": "英文逗号分隔,例如:bucket1,bucket2", - "baseDirDesc": "起始目录,可选项", - "baseDirPlaceholder": "英文逗号分隔,例如:/dir1,/dir2", - "isAutoGetCustomUrl": "是否自动获取绑定域名", - "isEnablePaging": "是否开启分页", - "itemsPerPage": "每页显示的项数", - "userNameDesc": "用户名", - "userNamePlaceholder": "请输入用户名", - "passwordDesc": "密码", - "passwordPlaceholder": "请输入密码", - "proxyDesc": "代理地址", - "proxyPlaceholder": "例如:http://127.0.0.1:7890", - "proxyTips": "部分图床可能需要代理才能正常访问", - "explain": "空间名和起始目录配置时可通过英文逗号分隔设置,顺序必须一致,逗号间留空或缺失项使用默认值", - "specialDesc": "特殊配置", - "specialPlaceholder": "请输入特殊配置", - "specialTips": "该配置不可修改,仅用于内部兼容处理", - "smms": { - "tokenDesc": "SM.MS Token, 可在 SM.MS 个人中心获取", - "tokenPlaceholder": "请输入 SM.MS Token", - "explain": "大陆地区请访问备用域名https://sm.ms,不要短时大量请求" - }, - "qiniu": { - "name": "七牛云" - }, - "github": { - "tokenDesc": "GitHub Token, 可在 GitHub 设置中获取", - "tokenPlaceholder": "请输入 GitHub Token", - "tokenTips": "请提供具有完整repo权限的token,否则部分功能可能无法使用", - "cdnUrlDesc": "CDN加速域名", - "cdnUrlPlaceholder": "支持使用{'{'}username{'}'}、{'{'}repo{'}'}、{'{'}branch{'}'}和{'{'}path{'}'}作为替换占位符,用于适配不同仓库和分支", - "cdnUrlTips": "例如:`https://cdn.staticaly.com/gh/{'{'}username{'}'}/{'{'}repo{'}'}{'@'}{'{'}branch{'}'}/{'{'}path{'}'}`", - "protocolRuleMsg": "请以http://或https://开头", - "bracketRuleMsg": "大括号必须成对出现", - "explain": "API调用有每小时上限,不支持上传超过100M的文件" - }, + "aliasDesc": "配置别名", + "aliasPlaceholder": "该配置的唯一标识", + "aliasRuleMsg": "别名只能包含中文、英文、数字、下划线和中划线", + "aliasTip": "别名只能包含中文、英文、数字、下划线和中划线", "aliyun": { "name": "阿里云" }, - "tcyun": { - "name": "腾讯云", - "appIdDesc": "App ID, 可在腾讯云控制台获取", - "appIdPlaceholder": "请输入 App ID", - "appIdTips": "例如:1250000000" - }, - "upyun": { - "name": "又拍云", - "bucketDesc": "服务名", - "bucketPlaceholder": "对应其它对象存储的存储桶名", - "operatorNameDesc": "操作员", - "operatorNamePlaceholder": "使用具有完整权限的操作员", - "operatorPassDesc": "操作员密码", - "operatorPassPlaceholder": "请输入操作员密码", - "baseDirDesc": "起始目录", - "baseDirPlaceholder": "请输入起始目录", - "accelerationUrlDesc": "加速域名", - "accelerationUrlPlaceholder": "请输入加速域名", - "notEmpty": "加速域名不能为空", + "baseDirDesc": "起始目录,可选项", + "baseDirPlaceholder": "英文逗号分隔,例如:/dir1,/dir2", + "baseDirTip": "英文逗号分隔,例如: /dir1,/dir2,与存储桶一一对应", + "bucketDesc": "存储桶名,可选项", + "bucketNameTip": "英文逗号分隔,例如: bucket1,bucket2,与起始目录一一对应", + "bucketPlaceholder": "英文逗号分隔,例如:bucket1,bucket2", + "explain": "空间名和起始目录配置时可通过英文逗号分隔设置,顺序必须一致,逗号间留空或缺失项使用默认值", + "github": { + "bracketRuleMsg": "大括号必须成对出现", + "cdnUrlDesc": "CDN加速域名", + "cdnUrlPlaceholder": "支持使用{'{'}username{'}'}、{'{'}repo{'}'}、{'{'}branch{'}'}和{'{'}path{'}'}作为替换占位符,用于适配不同仓库和分支", + "cdnUrlTips": "例如:`https://cdn.staticaly.com/gh/{'{'}username{'}'}/{'{'}repo{'}'}{'@'}{'{'}branch{'}'}/{'{'}path{'}'}`", + "explain": "API调用有每小时上限,不支持上传超过100M的文件", "protocolRuleMsg": "请以http://或https://开头", - "antiLeechTokenDesc": "反盗链Token", - "antiLeechTokenPlaceholder": "请输入反盗链Token", - "antiLeechTokenTooltip": "如果不填写,默认不启用防盗链", - "antiLeechExp": "反盗链过期时间", - "explain": "务必填写加速域名,否则无法正常使用" + "tokenDesc": "GitHub Token, 可在 GitHub 设置中获取", + "tokenPlaceholder": "请输入 GitHub Token", + "tokenTips": "请提供具有完整repo权限的token,否则部分功能可能无法使用" }, "imgur": { "accessTokenDesc": "access token", @@ -853,86 +310,629 @@ "accessTokenTips": "不是clientID, 请参考教程获取", "explain": "大陆地区请使用代理,API调用存在限制,请注意使用频率" }, - "s3": { - "endpointDesc": "endpoint", - "endpointPlaceholder": "例如:s3.us-east-1.amazonaws.com", - "endpointTips": "不填写默认访问AWS S3", - "enableHttps": "是否启用HTTPS", - "enableHttpsTip": "开启后,所有请求将使用HTTPS", - "enableS3PathStyle": "启用S3 path style", - "enableS3PathStyleTip": "例如使用minio时需要开启", - "aclDesc": "上传文件权限设置", - "acl": { - "private": "私有", - "publicRead": "公共读", - "publicReadWrite": "公共读写", - "authenticatedRead": "认证用户读", - "bucketOwnerRead": "存储桶所有者读", - "bucketOwnerFullControl": "存储桶所有者完全控制", - "awsExecRead": "AWS 执行读" - }, - "aclTips": "请根据实际需求选择合适的权限设置", - "enableDogeSupport": "是否启用Doge支持", - "enableDogeSupportTip": "开启后,所有请求将使用Doge API" - }, - "webdav": { - "hostDesc": "地址", - "hostPlaceholder": "例如:https://example.com/dav", - "hostTips": "请填写webdav协议地址", - "baseDirDesc": "起始目录", - "baseDirPlaceholder": "例如:/dir1", - "customUrlDesc": "自定义URL", - "customUrlPlaceholder": "例如:https://example.com/custom", - "customUrlTips": "如果访问地址和接口地址不一致,请填写自定义URL", - "protocolRuleMsg": "请以http://或https://开头", - "webPathDesc": "网址拼接用起始路径", - "webPathPlaceholder": "例如:/dir2", - "webPathTips": "用于拼接访问网址", - "enableHttpsDesc": "是否启用HTTPS", - "enableHttpsTips": "开启后,所有请求将使用HTTPS", - "authTypeDesc": "认证类型", - "explain": "不用平台WebDAV协议可能有区别,请根据实际情况选择" - }, + "inputAlias": "请输入别名,配置的唯一标识", + "inputItemsPerPage": "输入每页显示的项数", + "isAutoCustomUrlTip": "开启时,将自动获取存储桶绑定的域名", + "isAutoGetCustomUrl": "是否自动获取绑定域名", + "isEnablePaging": "是否开启分页", + "itemsPerPage": "每页显示的项数", + "itemsPPBeNumber": "每页显示的项数必须为数字", + "itemsPPBeNumberLimit": "每页显示的项数必须在20到1000之间", + "itemsPPTip": "每页显示的项数必须在20到1000之间", "local": { - "name": "本地存储", "baseDirDesc": "起始目录", "baseDirPlaceholder": "例如:/dir1", "baseDirRuleMsg": "起始目录不能为空", "customUrlDesc": "自定义域名", "customUrlPlaceholder": "例如:https://example.com", - "customUrlTooltip": "如果你的本地路径可以通过网络访问,请填写", "customUrlRuleMsg": "请以http://或https://开头", + "customUrlTooltip": "如果你的本地路径可以通过网络访问,请填写", + "explain": "本地存储配置", + "name": "本地存储", "webPathDesc": "网址拼接用起始路径", "webPathPlaceholder": "例如:/dir2", - "webPathTips": "用于拼接访问网址", - "explain": "本地存储配置" + "webPathTips": "用于拼接访问网址" }, + "pagingDesc": "是否开启分页", + "pagingTip": "关闭分页时,目录列表将使用数据库缓存以优化性能", + "passwordDesc": "密码", + "passwordPlaceholder": "请输入密码", + "pleaseInput": "请输入: {name}", + "proxyDesc": "代理地址", + "proxyPlaceholder": "例如:http://127.0.0.1:7890", + "proxyTips": "部分图床可能需要代理才能正常访问", + "qiniu": { + "name": "七牛云" + }, + "referText": "配置教程请参考:", + "s3": { + "acl": { + "authenticatedRead": "认证用户读", + "awsExecRead": "AWS 执行读", + "bucketOwnerFullControl": "存储桶所有者完全控制", + "bucketOwnerRead": "存储桶所有者读", + "private": "私有", + "publicRead": "公共读", + "publicReadWrite": "公共读写" + }, + "aclDesc": "上传文件权限设置", + "aclTips": "请根据实际需求选择合适的权限设置", + "enableDogeSupport": "是否启用Doge支持", + "enableDogeSupportTip": "开启后,所有请求将使用Doge API", + "enableHttps": "是否启用HTTPS", + "enableHttpsTip": "开启后,所有请求将使用HTTPS", + "enableS3PathStyle": "启用S3 path style", + "enableS3PathStyleTip": "例如使用minio时需要开启", + "endpointDesc": "endpoint", + "endpointPlaceholder": "例如:s3.us-east-1.amazonaws.com", + "endpointTips": "不填写默认访问AWS S3" + }, + "secretIdDesc": "Secret ID, 可在控制台获取", + "secretIdPlaceholder": "请输入 Secret ID", + "secretKeyDesc": "Secret Key, 可在控制台获取", + "secretKeyIdDesc": "Secret Key, 可在控制台获取", + "secretKeyIdPlaceholder": "请输入 Secret Key", + "secretKeyPlaceholder": "请输入Secret Key", "sftp": { - "hostDesc": "SSH主机地址", - "hostPlaceholder": "例如:192.168.1.1", - "portDesc": "SSH端口", - "portPlaceholder": "例如:22", - "privateKeyDesc": "私钥", - "privateKeyPlaceholder": "请输入私钥", - "passphraseDesc": "私钥密码", - "passphrasePlaceholder": "请输入私钥密码", - "fileModeDesc": "文件权限设置", - "fileModePlaceholder": "例如:0644", - "dirModeDesc": "目录权限设置", - "dirModePlaceholder": "例如:0755", "baseDirDesc": "起始目录", "baseDirPlaceholder": "例如:/dir1", "baseDirTips": "起始目录不能为空", "customUrlDesc": "自定义域名", "customUrlPlaceholder": "例如:https://example.com", "customUrlTips": "如果访问地址和接口地址不一致,请填写自定义URL", + "dirModeDesc": "目录权限设置", + "dirModePlaceholder": "例如:0755", + "explain": "SFTP配置", + "fileModeDesc": "文件权限设置", + "fileModePlaceholder": "例如:0644", + "hostDesc": "SSH主机地址", + "hostPlaceholder": "例如:192.168.1.1", + "passphraseDesc": "私钥密码", + "passphrasePlaceholder": "请输入私钥密码", + "portDesc": "SSH端口", + "portPlaceholder": "例如:22", + "privateKeyDesc": "私钥", + "privateKeyPlaceholder": "请输入私钥", "protocolRuleMsg": "请以http://或https://开头", "webPathDesc": "网址拼接用起始路径", "webPathPlaceholder": "例如:/dir2", - "webPathTips": "用于拼接访问网址", - "explain": "SFTP配置" + "webPathTips": "用于拼接访问网址" + }, + "smms": { + "explain": "大陆地区请访问备用域名https://sm.ms,不要短时大量请求", + "tokenDesc": "SM.MS Token, 可在 SM.MS 个人中心获取", + "tokenPlaceholder": "请输入 SM.MS Token" + }, + "specialDesc": "特殊配置", + "specialPlaceholder": "请输入特殊配置", + "specialTips": "该配置不可修改,仅用于内部兼容处理", + "tcyun": { + "appIdDesc": "App ID, 可在腾讯云控制台获取", + "appIdPlaceholder": "请输入 App ID", + "appIdTips": "例如:1250000000", + "name": "腾讯云" + }, + "upyun": { + "accelerationUrlDesc": "加速域名", + "accelerationUrlPlaceholder": "请输入加速域名", + "antiLeechExp": "反盗链过期时间", + "antiLeechTokenDesc": "反盗链Token", + "antiLeechTokenPlaceholder": "请输入反盗链Token", + "antiLeechTokenTooltip": "如果不填写,默认不启用防盗链", + "baseDirDesc": "起始目录", + "baseDirPlaceholder": "请输入起始目录", + "bucketDesc": "服务名", + "bucketPlaceholder": "对应其它对象存储的存储桶名", + "explain": "务必填写加速域名,否则无法正常使用", + "name": "又拍云", + "notEmpty": "加速域名不能为空", + "operatorNameDesc": "操作员", + "operatorNamePlaceholder": "使用具有完整权限的操作员", + "operatorPassDesc": "操作员密码", + "operatorPassPlaceholder": "请输入操作员密码", + "protocolRuleMsg": "请以http://或https://开头" + }, + "userNameDesc": "用户名", + "userNamePlaceholder": "请输入用户名", + "webdav": { + "authTypeDesc": "认证类型", + "baseDirDesc": "起始目录", + "baseDirPlaceholder": "例如:/dir1", + "customUrlDesc": "自定义URL", + "customUrlPlaceholder": "例如:https://example.com/custom", + "customUrlTips": "如果访问地址和接口地址不一致,请填写自定义URL", + "enableHttpsDesc": "是否启用HTTPS", + "enableHttpsTips": "开启后,所有请求将使用HTTPS", + "explain": "不用平台WebDAV协议可能有区别,请根据实际情况选择", + "hostDesc": "地址", + "hostPlaceholder": "例如:https://example.com/dav", + "hostTips": "请填写webdav协议地址", + "protocolRuleMsg": "请以http://或https://开头", + "webPathDesc": "网址拼接用起始路径", + "webPathPlaceholder": "例如:/dir2", + "webPathTips": "用于拼接访问网址" } + }, + "empty": { + "noData": "暂无数据", + "noDataDesc": "请先创建存储桶或上传图片" + }, + "login": { + "aliasMsg": "别名只能包含中文、英文、数字、下划线和中划线", + "configChangeMsg": "配置已更改", + "configSaveMsg": "配置已保存", + "configTabTitle": "已有配置,单击复制", + "confirmDeleteConfig": "确认删除配置吗?", + "copySuccess": "复制成功: {text}", + "delete": "删除", + "deleteConfigFailedMsg": "删除配置失败", + "deleteConfigSuccessMsg": "删除配置成功", + "enter": "进入", + "import": "导入", + "importSuccess": "导入成功", + "itemsPerPageMsg": "每页显示项数必须为20-1000之间的整数", + "noConfigs": "未找到配置", + "noConfigsDesc": "请检查您的配置文件或重新加载页面", + "noRequiredMsg": "请填写必填项", + "refresh": "刷新", + "reset": "重置", + "save": "保存", + "savedConfigs": "已保存配置", + "selectPlaceholder": "请选择", + "tips": "提示", + "title": "图床管理", + "viewDetails": "查看详情" + }, + "main": { + "backToHome": "首页", + "bucket": "存储桶", + "createFailed": "创建失败", + "createSuccess": "创建成功", + "gallery": "相册", + "loading": "加载中...", + "newBucket": "新建存储桶", + "openPicBedUrl": "打开图床官网", + "repo": "仓库", + "settings": "设置", + "switchPicBed": "切换" + }, + "newBucket": { + "acl": { + "authenticatedRead": "已认证读", + "private": "私有", + "publicRead": "公共读", + "publicReadWrite": "公共读写", + "title": "访问控制" + }, + "aliyun": { + "bucketCharMsg": "Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾", + "bucketLengthMsg": "Bucket名称长度必须在3到63个字符之间", + "name": "阿里云" + }, + "bucketDesc": "存储桶名", + "bucketNoEmpty": "存储桶名不能为空", + "bucketPlaceholder": "请输入存储桶名", + "qiniu": { + "bucketCharMsg": "Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾", + "bucketLengthMsg": "Bucket名称长度必须在3到63个字符之间", + "name": "七牛云", + "publicAccess": "公共访问" + }, + "region": "区域", + "s3": { + "name": "S3" + }, + "tcyun": { + "bucketCharMsg": "Bucket名称只能包含小写字母、数字和中划线,且不能以中划线开头和结尾", + "bucketLengthMsg": "Bucket名称长度不能超过23个字符", + "name": "腾讯云" + } + }, + "setting": { + "browse": "浏览", + "clearCache": "清空文件列表缓存数据库,已使用 {size} 可用 {percent}%", + "clearCacheMsg": "确定要清空缓存吗?", + "clearFailed": "清空缓存失败", + "clearSuccess": "清空缓存成功", + "copyFormat": { + "bbcode": "BBCode格式", + "custom": "自定义格式", + "customTips": "请根据实际需求填写自定义格式", + "customTitle": "自定义链接格式($url为链接,$fileName为文件名)", + "html": "HTML格式", + "markdown": "Markdown", + "markdown-with-link": "Markdown(带链接)", + "rawurl": "原始URL", + "title": "复制格式" + }, + "copySuccess": "已复制 {name}", + "customRenameTablePlaceholder": "请输入自定义重命名格式", + "customRenameTableTitle": "自定义重命名格式参考表", + "customRenameTips": "开启后填写命名格式", + "customRenameTitle": "上传文件自定义重命名(低优先级)", + "defaultDownloadFolder": "系统默认下载文件夹", + "description": "描述", + "download": "下载", + "file": "文件", + "folder": "文件夹", + "isAutoRefreshTips": "仅对不分页模式有效,默认在加载过一次后自动缓存到数据库来加快下次加载速度", + "isAutoRefreshTitle": "每次进入新目录时,是否自动刷新文件列表", + "isEncodeUrlTips": "根据平台选择是否开启", + "isEncodeUrlTitle": "复制链接时进行URL编码", + "isForceCustomUrlHttpsTips": "开启后, 复制链接等操作将会自动为自定义域名添加https前缀", + "isForceCustomUrlHttpsTitle": "为自定义域名开启强制HTTPS", + "isIgnoreCaseTips": "建议开启", + "isIgnoreCaseTitle": "文件搜索时,是否忽略大小写", + "isShowThumbnailTitle": "图片显示为原图而非默认文件格式图标(需要存储桶可公开访问)", + "isUploadKeepDirStructureTips": "关闭后会将所有文件展开到指定目录下", + "isUploadKeepDirStructureTitle": "上传时保持目录结构", + "isUsePreSignedUrlTitle": "是否使用预签名URL预览图片", + "keepDirStructure": "保持目录结构", + "keepDirStructureDesc": "开启后,下载时会保持原始目录结构", + "maxDownLoadFileLimit": "最大并行下载文件数", + "maxDownLoadFileLimitDesc": "建议根据网络情况调整", + "notice": "通知", + "placeholder": "占位符", + "preSignedUrlExpire": "预签名URL过期时间(单位: 秒)", + "preSignedUrlExpireDesc": "建议根据实际需求调整", + "randomStringRenameTips": "20位随机字符", + "randomStringRenameTitle": "上传文件随机字符串重命名(中优先级)", + "selectDownloadFolderTips": "选择下载目录", + "selectDownloadFolderTitle": "选择下载文件夹", + "timestampRenameTips": "开启后,上传的文件将自动重命名为时间戳", + "timestampRenameTitle": "上传文件时间戳重命名(最高优先级)" } + }, + "picBedConfigs": { + "copyAPI": "复制上传API", + "copyAPIFailed": "复制API地址失败", + "copyAPISucceed": "复制API地址成功", + "importConfigFailed": "导入配置失败", + "importConfigSuccess": "导入配置成功", + "loadConfigFailed": "加载配置失败, 请检查配置文件是否正确", + "loadPicBedListFailed": "加载图床列表失败", + "noConfigOptions": "暂无配置项", + "noConfigs": "配置为空", + "resetFailed": "重置失败, 请检查配置项是否正确", + "resetSuccess": "重置成功", + "setFailedInfo": "设置失败, 请检查配置项是否正确", + "setSuccess": "设置成功", + "title": "配置", + "viewDoc": "查看文档", + "viewDocFailed": "查看文档失败" + }, + "plugin": { + "browsePlugins": "浏览插件", + "configThing": "配置 {c}", + "description": "PicList 插件管理页面", + "disabled": "已禁用", + "doingSomething": "进行中", + "importLocal": "导入本地插件", + "install": "安装", + "installed": "已安装", + "installing": "安装中", + "installPluginsToGetStarted": "请先安装插件以开始使用", + "list": "插件列表", + "loading": "加载中...", + "needRestart": "需要重启生效", + "noPluginsFound": "未找到插件", + "NoPluginsInstalled": "暂无已安装插件", + "notGuiImplement": "该插件未对可视化界面进行优化, 是否继续安装?", + "pluginList": "插件列表", + "restartApp": "重启应用", + "searchPlaceholder": "搜索 npm 上的 PicGo 插件,或者点击上方按钮查看优秀插件列表", + "setResult": "设置结果", + "setSuccess": "设置成功", + "settings": "设置", + "title": "插件", + "tryDifferentSearch": "尝试不同的搜索关键词", + "updateAll": "更新全部插件", + "updateSuccess": "插件更新成功" + }, + "rename": { + "placeholder": "请输入新的文件名" + }, + "settings": { + "advanced": { + "chooseLogLevel": "请选择日志记录等级", + "enableServer": "是否开启上传API服务", + "enableWebServer": "是否开启 Web 服务", + "guiLogFile": "GUI 日志文件", + "logFile": "常规日志文件", + "logFilePath": "日志文件路径", + "logFileSize": "日志文件大小", + "logging": "日志", + "logLevel": "日志记录等级", + "logLevelList": { + "all": "全部", + "error": "错误", + "info": "信息", + "none": "不记录日志", + "success": "成功", + "warn": "警告" + }, + "manageLogFile": "管理日志文件", + "networkAndProxy": "网络与代理", + "pluginInstallMirror": "插件安装镜像", + "pluginInstallProxy": "插件安装代理", + "serverEncryptionKey": "接口数据加密密钥", + "serverHost": "监听地址", + "serverKey": "鉴权密钥", + "serverKeyPlaceholder": "请输入鉴权密钥,用于防止接口滥用", + "serverPort": "监听端口", + "serverSettings": "服务器设置", + "serverSettingsNotice": "如果你不知道上传API服务的作用,请阅读文档,或者不用修改配置。", + "setLog": "设置日志", + "setProxyAndMirror": "设置代理和镜像地址", + "title": "高级", + "uploadProxy": "上传代理", + "uploadServer": "上传API服务设置", + "webServerHost": "Web 服务监听地址", + "webServerNotice": "如果你不知道 Web 服务的作用,请阅读文档,或者不用修改配置。", + "webServerPath": "Web 服务路径", + "webServerPlaceholderHost": "推荐默认地址: 127.0.0.1", + "webServerPlaceholderPort": "推荐默认端口: 37777", + "webServerPort": "Web 服务监听端口", + "webServerSettings": "Web 服务设置" + }, + "clickToOpen": "点击打开", + "clickToSet": "点击设置", + "description": "配置 PicList 应用程序", + "docs": "文档", + "sync": { + "allConfig": "所有配置", + "commonConfig": "通用配置", + "downloadSettings": "下载配置", + "fileManagement": "文件管理", + "gitea": { "branch": "分支名", "repo": "仓库名", "token": "访问令牌", "username": "用户名" }, + "giteaHost": "Gitea 地址", + "gitee": { + "branch": "Gitee 分支名", + "repo": "Gitee 仓库名", + "token": "Gitee 访问令牌", + "username": "Gitee 用户名" + }, + "github": { + "branch": "GitHub 分支名", + "repo": "私有仓库名", + "token": "GitHub 访问令牌", + "username": "GitHub 用户名" + }, + "manageConfig": "管理配置", + "migrateFromPicGo": "从PicGo迁移", + "mirgrateContent": "即将导入PicGo的配置文件和相册, 这将覆盖当前的配置文件和相册, 是否继续?", + "mirgrateFailed": "导入失败", + "mirgrateSuccess": "导入成功, 请重启PicList生效", + "mirgrateTitle": "通知", + "openConfigFile": "打开配置文件", + "openConfigFileDir": "打开配置文件目录", + "selectType": "请选择同步类型", + "syncConfigNote": "同步的文件为配置文件", + "syncConfigProxy": "代理", + "syncConfiguration": "同步配置", + "syncEndpointConfig": "同步方案配置", + "syncResult": { "failed": "同步失败", "success": "同步成功" }, + "title": "配置/同步", + "upDownloadSettings": "上传下载配置文件", + "uploadSettings": "上传配置", + "webdav": { + "authType": "WebDAV 认证类型", + "enableSSL": "启用 SSL/TLS", + "password": "WebDAV 密码", + "savePath": "WebDAV 保存路径", + "username": "WebDAV 用户名" + }, + "webdavEndpoint": "WebDAV 端点" + }, + "system": { + "autoCloseMainWindow": "打开迷你窗口时关闭主窗口", + "autoCloseMiniWindow": "打开主窗口时关闭迷你窗口", + "autoLaunch": "开机自启", + "chooseLanguage": "选择语言", + "customMiniIconPath": "自定义迷你窗口图标路径", + "hideDockHint": "不支持同时隐藏 dock 和托盘", + "isCustomMiniIcon": "是否自定义迷你窗口图标", + "isHideDock": "是否隐藏 Dock 图标", + "languageAndAppearance": "语言和外观", + "mainMode": "主窗口", + "mainWindowHeight": "主窗口高度", + "mainWindowSize": "设置主窗口大小(需重启)", + "mainWindowWidth": "主窗口宽度", + "miniMode": "迷你窗口", + "miniWindowOnTop": "迷你窗口置顶", + "needRestart": "需要重启生效", + "noTrayMode": "隐藏托盘", + "quietMode": "静默模式", + "rawPicGoSize": "原 PicGo 窗口大小, 800x450", + "rawPicGoSizeHint": "不推荐使用, 仅用于兼容旧 PicGo 窗口大小", + "setMainWindowSize": "设置主窗口大小(需重启)", + "setShortCuts": "设置快捷键", + "startMode": "启动模式", + "startupAndShortcuts": "启动和快捷键", + "title": "通用", + "windowBehavior": "窗口行为" + }, + "title": "设置", + "update": { + "applicationUpdates": "应用程序更新", + "checkUpdate": "检查更新", + "clickToCheck": "点击检查", + "currentVersion": "当前版本: {version}", + "daysAgo": "{days} 天前", + "getting": "正在获取中...", + "hasNewVersion": "PicList 更新啦,请点击确定重启触发更新", + "hoursAgo": "{hours} 小时前", + "justNow": "刚刚", + "lastUpdated": "最后更新", + "latestReleaseNotes": "最新版本说明", + "loadingReleaseNotes": "正在加载版本说明...", + "minutesAgo": "{minutes} 分钟前", + "networkError": "网络错误,请检查网络连接", + "newestVersion": "最新版本", + "noReleaseNotes": "暂无版本说明", + "openUpdateHelper": "打开更新提醒", + "openUpdateHelperDesc": "当有新版本时显示通知", + "refresh": "刷新", + "releaseNotes": "版本说明", + "releaseNotesDescription": "查看最新的更改和更新内容", + "releaseNotesError": "加载版本说明失败,请检查网络连接。", + "retry": "重试", + "title": "更新" + }, + "upload": { + "advancedRname": "高级重命名", + "advancedRnameFormat": "高级重命名格式", + "autoCopyUrlAfterUpload": "上传后自动复制URL", + "autoImportInManage": "管理页面自动导入配置", + "autoImportInManageHint": "启用后,管理页面将自动导入对应图床配置", + "autoImportPicBed": "选择需要开启自动导入的图床", + "availablePlaceholders": "可用占位符", + "c1nToken": "C1N Token", + "cfWorkerHost": "CF Worker 地址", + "chooseShowedPicBed": "请选择显示在菜单的图床", + "clipboardAndNotification": "剪贴板和通知", + "copySuccess": "复制成功: {content}", + "customLinkFormat": "自定义链接格式", + "deleteCloud": "相册内删除时同步删除云端文件", + "deleteLocalFileAfterUpload": "上传后删除本地文件", + "enableAdvancedRname": "开启高级重命名", + "enableSecondPicBed": "启用第二图床同步上传", + "enableSecondPicBedHint": "启用后,将同步上传到第二图床,用于备份", + "enableShortUrl": "使用短链接", + "enableUploadNotification": "开启上传进度提示", + "enableUploadResultNotification": "开启上传结果提示", + "encodeOutputUrl": "输出(复制) URL 时进行转义", + "extNamePlaceholder": "用占位符 $extName 来表示文件格式的位置", + "fileNamePlaceholder": "用占位符 $fileName 来表示文件名的位置", + "galleryPicBedFilter": "相册图床过滤器", + "galleryPicBedFilterDescription": "选择在相册中显示的图床类型。如果未选择任何图床,将显示所有图床。", + "imageProcessing": "图片预处理设置", + "isAutoListenClipboard": "软件启动时自动监听剪贴板上传", + "manualRname": "手动重命名", + "placeholder": { + "categoryFile": "文件相关", + "categoryHash": "哈希相关", + "categoryTime": "时间相关", + "date": "日期,2位数", + "filename": "文件原名", + "hour": "小时,2位数", + "localFolder": "本地文件夹层级", + "md5": "MD5 哈希", + "md5-16": "MD5 哈希(前16位)", + "millisecond": "毫秒,3位数", + "minute": "分钟,2位数", + "month": "月份,2位数", + "randomString": "number位随机字符串", + "second": "秒,2位数", + "sha256": "SHA256 哈希", + "sha256-n": "SHA256 哈希(前n位)", + "timestamp": "时间戳,13位数", + "uuid": "随机 UUID", + "year2": "年份,2位数", + "year4": "年份,4位数" + }, + "setSecondPicBed": "设置第二图床", + "shortUrlServer": "短链接服务", + "sinkDomain": "Sink 域名", + "sinkToken": "Sink Token", + "timestampRname": "时间戳重命名", + "title": "上传", + "uploadBehavior": "上传行为", + "uploadProcessing": "上传处理", + "urlFormatAndLinkType": "链接格式和类型", + "urlPlaceholder": "用占位符 $url 来表示 URL 的位置", + "useBuiltInClipboardUpload": "使用系统内置剪贴板上传", + "useBuiltInClipboardUploadHint": "关闭时会使用脚本文件获取图片", + "yourlsDomain": "Yourls 域名", + "yourlsSignature": "Yourls 密钥" + } + }, + "shortKey": { + "bind": "快捷键绑定", + "changeUpload": "修改上传快捷键", + "disable": "禁用", + "disabled": "已禁用", + "edit": "编辑", + "enable": "启用", + "enabled": "已启用", + "handle": "操作", + "keyBinding": "按键绑定", + "name": "快捷键名称", + "noBinding": "未绑定", + "pressHint": "点击输入框并按下你想要绑定的按键", + "pressKeys": "按下要设置的快捷键", + "source": "来源", + "status": "状态", + "title": "快捷键" + }, + "toolbox": { + "autoFixFail": "自动修复失败,请自行修复以下问题", + "checkConfigFileBroken": "检查配置文件是否损坏", + "checkGalleryFileBroken": "检查相册文件是否损坏", + "checkProblemWithClipboardPicUpload": "检查剪贴板图片上传是否存在问题", + "checkProblemWithProxy": "检查代理设置是否正常", + "description": "立即扫描以下项目,修复使用问题", + "fixDoneNeedReload": "修复完成,需要重启生效,是否重启", + "notice": "通知", + "openConfigFile": "打开配置文件", + "openFilePath": "打开文件路径", + "reScan": "重新扫描", + "startFix": "开始修复", + "startScan": "开始扫描", + "success": "恭喜你,没有检查出问题", + "title": "工具箱" + }, + "tray": { + "copySuccess": "复制成功", + "openMainWindow": "打开主窗口", + "uploaded": "已上传", + "waitForUpload": "等待上传" + }, + "upload": { + "changePicBed": "切换图床", + "clickToUpload": "点击上传", + "clipboardPicture": "剪贴板图片", + "dragFileToHere": "将文件拖到此处,或单击上传", + "dragValidPictureOrUrl": "请拖入合法的图片文件或者图片URL地址", + "httpPrefixTip": "http://或https://开头", + "imageProcessName": "图片处理", + "inputUrlTip": "请输入URL地址", + "inputValidUrl": "请输入合法的URL", + "invalidUrlsFound": "发现无效的URL: {urls}", + "linkFormat": "链接格式", + "multipleUrlsHint": "多个URL请分行输入", + "outputFormat": "输出格式", + "quickUpload": "快捷上传", + "uploadFailed": "上传失败", + "uploadHint": "支持所有文件类型,但推荐仅上传图片", + "uploadingMultipleUrls": "正在上传 {count} 个URL...", + "uploadViewHint": "点击打开图床设置", + "urlType": { "normal": "长链接", "short": "短链接", "title": "链接类型" }, + "urlUpload": "URL上传" + }, + "uploaderConfig": { + "addNew": "新增", + "delete": "删除", + "deleteConfirm": "确认删除图床配置吗?", + "deleteSuccess": "删除成功", + "deleteTitle": "通知", + "edit": "编辑", + "selected": "已选中", + "setAsDefault": "设为默认图床", + "setSuccess": "设置成功", + "title": "图床配置" } - } + }, + "settings": { + "theme": { + "auto": "自动", + "autoDesc": "自动模式", + "dark": "深色", + "darkDesc": "黑暗模式", + "light": "浅色", + "lightDesc": "明亮模式", + "toggle": "切换主题" + } + }, + "titleBar": { "alwaysOnTop": "置顶", "close": "关闭", "minimize": "最小化", "miniWindow": "迷你窗口" } } diff --git a/src/renderer/i18n/locales/zh-TW.json b/src/renderer/i18n/locales/zh-TW.json index 5fa21941..f78989cf 100644 --- a/src/renderer/i18n/locales/zh-TW.json +++ b/src/renderer/i18n/locales/zh-TW.json @@ -1,851 +1,308 @@ { "app": { "title": "PicList" }, - "titleBar": { "alwaysOnTop": "置頂", "close": "關閉", "minimize": "最小化", "miniWindow": "迷你視窗" }, "common": { - "confirm": "確認", "cancel": "取消", "close": "關閉", - "reset": "重置", + "confirm": "確認", "import": "匯入", + "reset": "重置", "submit": "提交" }, "navigation": { - "upload": "上傳", - "manage": "管理", - "gallery": "相簿", - "settings": "設定", - "plugins": "插件", - "picbed": "圖床", - "close": "關閉", - "copyPicBedConfig": "複製圖床設定", - "selected": "已選中", - "moreOptions": "更多選項", - "picBedQrCode": "圖床配置 QRCODE", "choosePicBed": "選擇圖床", - "selectPicBeds": "請選擇圖床", - "copySuccess": "複製成功", + "close": "關閉", "collapse": "收起側邊欄", - "expand": "展開側邊欄" - }, - "settings": { - "theme": { - "light": "淺色", - "dark": "深色", - "auto": "自動", - "lightDesc": "明亮模式", - "darkDesc": "黑暗模式", - "autoDesc": "自動模式", - "toggle": "切換主題" - } + "copyPicBedConfig": "複製圖床設定", + "copySuccess": "複製成功", + "expand": "展開側邊欄", + "gallery": "相簿", + "manage": "管理", + "moreOptions": "更多選項", + "picbed": "圖床", + "picBedQrCode": "圖床配置 QRCODE", + "plugins": "插件", + "selected": "已選中", + "selectPicBeds": "請選擇圖床", + "settings": "設定", + "upload": "上傳" }, "pages": { - "upload": { - "uploadViewHint": "點擊打開圖床設定", - "imageProcessName": "圖片處理", - "changePicBed": "切換圖床", - "dragFileToHere": "將文件拖到此處,或單擊上傳", - "dragValidPictureOrUrl": "請拖入合法的圖片文件或者圖片URL地址", - "uploadHint": "支持所有文件類型,但推薦僅上傳圖片", - "uploadFailed": "上傳失敗", - "quickUpload": "快捷上傳", - "clipboardPicture": "剪貼板圖片", - "clickToUpload": "點擊上傳", - "urlUpload": "URL上傳", - "inputUrlTip": "請輸入URL地址", - "httpPrefixTip": "以http://或https://開頭", - "multipleUrlsHint": "多個URL請分行輸入", - "inputValidUrl": "請輸入合法的URL", - "invalidUrlsFound": "發現無效的URL: {urls}", - "uploadingMultipleUrls": "正在上傳 {count} 個URL...", - "linkFormat": "連結格式", - "outputFormat": "輸出格式", - "urlType": { "title": "連結類型", "normal": "長連結", "short": "短連結" } - }, - "imageProcess": { - "title": "圖片處理設置", - "description": "配置圖片處理選項,包括壓縮、水印、格式轉換等", - "generalSettings": "常規", - "watermarkSettings": "水印", - "transformSettings": "變換", - "cancel": "取消", - "confirm": "確認", - "general": { - "skipProcessExtList": "跳過處理的文件擴展名列表", - "skipProcessExtListLabel": "跳過處理的擴展名", - "skipProcessExtListPlaceholder": "輸入要跳過處理的文件擴展名,以逗號分隔(例如:jpg,png,gif)", - "basicImageProcessing": "基本圖像處理", - "isRemoveExif": "移除 Exif 信息", - "quality": "壓縮質量 (1-100)", - "formatConversion": "圖片格式轉換", - "isConvert": "轉換格式", - "destinationFormat": "目標格式", - "specificFormatConversion": "精細化轉換格式,請填寫 JSON 格式,如: {'{'}\"png\": \"jpg\"{'}'}" - }, - "watermark": { - "title": "水印設置", - "description": "添加文字或圖片水印到圖片上", - "isAdd": "啟用或禁用水印", - "type": "水印類型", - "text": "文字", - "image": "圖片", - "isFullScreen": "是否全屏水印", - "degree": "水印旋轉角度", - "scaleRatio": "水印占原圖比例", - "inputText": "水印文字", - "inputTextPlaceholder": "請輸入水印文字", - "textFontPath": "水印字體路徑(第一次使用前自動下載)", - "textFontPathPlaceholder": "可選,請輸入路徑", - "color": "水印顏色,手動輸入或取色器", - "imagePath": "水印圖片路徑(留空使用默認圖片)", - "imagePathPlaceholder": "可選,請輸入路徑", - "position": "水印位置", - "positionOptions": { - "top": "上", - "bottom": "下", - "left": "左", - "right": "右", - "topLeft": "左上", - "topRight": "右上", - "bottomLeft": "左下", - "bottomRight": "右下", - "center": "中" - }, - "imageOpacity": "水印透明度" - }, - "transform": { - "title": "變換設置", - "description": "調整圖片大小、旋轉、翻轉等", - "isFlip": "垂直翻轉", - "isFlop": "水平翻轉", - "rotationTitle": "旋轉設置", - "rotationDescription": "設置圖片旋轉參數", - "isRotate": "啟用旋轉", - "rotationDegree": "旋轉角度", - "resizeTitle": "調整大小", - "resizeDescription": "設置圖片縮放參數", - "isResize": "啟用調整大小", - "resizeWidth": "調整寬度 (0 表示按高度等比縮放)", - "resizeHeight": "調整高度 (0 表示按寬度等比縮放)", - "skipResizeOfSmallImgHeight": "當圖片小於設定時跳過縮放", - "percentageResize": "按比例調整尺寸", - "isResizeByPercent": "啟用按比例調整", - "isResizeByPercentHint": "優先級更高", - "resizePercent": "調整比例 (輸入 50 表示 50%)" - }, - "perPicBed": { - "title": "圖床獨立設置", - "description": "為每個圖床單獨配置設置" - } - }, - "settings": { - "title": "設定", - "description": "配置 PicList 應用程序", - "docs": "文檔", - "clickToSet": "點擊設置", - "clickToOpen": "點擊打開", - "system": { - "title": "通用", - "languageAndAppearance": "語言和外觀", - "chooseLanguage": "選擇語言", - "startMode": "啟動模式", - "quietMode": "靜默模式", - "miniMode": "迷你窗口", - "mainMode": "主窗口", - "noTrayMode": "隱藏托盤", - "windowBehavior": "窗口行為", - "isHideDock": "是否隱藏 Dock 圖標", - "hideDockHint": "不支持同時隱藏 dock 和托盤", - "needRestart": "需要重啟生效", - "mainWindowSize": "設置主窗口大小(需重啟)", - "autoCloseMiniWindow": "打開主窗口時關閉迷你窗口", - "autoCloseMainWindow": "打開迷你窗口時關閉主窗口", - "miniWindowOnTop": "迷你窗口置頂", - "isCustomMiniIcon": "是否自定義迷你窗口圖標", - "customMiniIconPath": "自定義迷你窗口圖標路徑", - "startupAndShortcuts": "啟動和快捷鍵", - "autoLaunch": "開機自啟", - "setShortCuts": "設置快捷鍵", - "setMainWindowSize": "設置主窗口大小(需重啟)", - "mainWindowHeight": "主窗口高度", - "mainWindowWidth": "主窗口寬度", - "rawPicGoSize": "原 PicGo 窗口大小, 800x450", - "rawPicGoSizeHint": "不推薦使用, 僅用於兼容舊 PicGo 窗口大小" - }, - "sync": { - "title": "配置/同步", - "syncConfiguration": "同步配置", - "syncEndpointConfig": "同步方案配置", - "upDownloadSettings": "上傳下載配置文件", - "uploadSettings": "上傳配置", - "downloadSettings": "下載配置", - "syncResult": { "success": "同步成功", "failed": "同步失敗" }, - "commonConfig": "通用配置", - "manageConfig": "管理配置", - "allConfig": "所有配置", - "migrateFromPicGo": "從PicGo遷移", - "mirgrateTitle": "通知", - "mirgrateContent": "即將導入PicGo的配置文件和相冊, 這將覆蓋當前的配置文件和相冊, 是否繼續?", - "mirgrateSuccess": "導入成功, 請重啟PicList生效", - "mirgrateFailed": "導入失敗", - "fileManagement": "文件管理", - "openConfigFile": "打開配置文件", - "openConfigFileDir": "打開配置文件目錄", - "syncConfigNote": "同步的文件為配置文件", - "selectType": "請選擇同步類型", - "giteaHost": "Gitea 地址", - "webdavEndpoint": "WebDAV 端點", - "gitea": { "username": "用戶名", "repo": "倉庫名", "branch": "分支名", "token": "訪問令牌" }, - "github": { - "username": "GitHub 用戶名", - "repo": "私有倉庫名", - "branch": "GitHub 分支名", - "token": "GitHub 訪問令牌" - }, - "gitee": { - "username": "Gitee 用戶名", - "repo": "Gitee 倉庫名", - "branch": "Gitee 分支名", - "token": "Gitee 訪問令牌" - }, - "webdav": { - "username": "WebDAV 用戶名", - "password": "WebDAV 密碼", - "savePath": "WebDAV 保存路徑", - "authType": "WebDAV 認證類型", - "enableSSL": "啟用 SSL/TLS" - }, - "syncConfigProxy": "代理" - }, - "upload": { - "title": "上傳", - "uploadBehavior": "上傳行為", - "autoImportInManage": "管理頁面自動導入配置", - "autoImportInManageHint": "啟用後,管理頁面將自動導入對應圖床配置", - "autoImportPicBed": "選擇需要開啟自動導入的圖床", - "enableSecondPicBed": "啟用第二圖床同步上傳", - "enableSecondPicBedHint": "啟用後,將同步上傳到第二圖床,用於備份", - "setSecondPicBed": "設置第二圖床", - "uploadProcessing": "上傳處理", - "deleteCloud": "相冊內刪除時同步刪除雲端文件", - "manualRname": "手動重命名", - "timestampRname": "時間戳重命名", - "advancedRname": "高級重命名", - "enableAdvancedRname": "開啟高級重命名", - "advancedRnameFormat": "高級重命名格式", - "availablePlaceholders": "可用占位符", - "copySuccess": "複製成功: {content}", - "placeholder": { - "categoryTime": "時間相關", - "categoryHash": "哈希相關", - "categoryFile": "文件相關", - "year4": "年份,4位數", - "year2": "年份,2位數", - "month": "月份,2位數", - "date": "日期,2位數", - "hour": "小時,2位數", - "minute": "分鐘,2位數", - "second": "秒,2位數", - "millisecond": "毫秒,3位數", - "timestamp": "時間戳,13位數", - "md5": "MD5 哈希", - "md5-16": "MD5 哈希(前16位)", - "localFolder": "本地文件夾層級", - "filename": "文件原名", - "randomString": "number位隨機字符串", - "uuid": "隨機 UUID", - "sha256": "SHA256 哈希", - "sha256-n": "SHA256 哈希(前n位)" - }, - "imageProcessing": "圖片預處理設置", - "deleteLocalFileAfterUpload": "上傳後刪除本地文件", - "clipboardAndNotification": "剪貼板和通知", - "enableUploadNotification": "開啟上傳進度提示", - "enableUploadResultNotification": "開啟上傳結果提示", - "autoCopyUrlAfterUpload": "上傳後自動複製URL", - "useBuiltInClipboardUpload": "使用系統內置剪貼板上傳", - "useBuiltInClipboardUploadHint": "關閉時會使用腳本文件獲取圖片", - "isAutoListenClipboard": "軟件啟動時自動監聽剪貼板上傳", - "urlFormatAndLinkType": "鏈接格式和類型", - "customLinkFormat": "自定義鏈接格式", - "urlPlaceholder": "用占位符 $url 來表示 URL 的位置", - "fileNamePlaceholder": "用占位符 $fileName 來表示文件名的位置", - "extNamePlaceholder": "用占位符 $extName 來表示文件格式的位置", - "enableShortUrl": "使用短鏈接", - "shortUrlServer": "短鏈接服務", - "c1nToken": "C1N Token", - "yourlsDomain": "Yourls 域名", - "yourlsSignature": "Yourls 密鑰", - "cfWorkerHost": "CF Worker 地址", - "sinkDomain": "Sink 域名", - "sinkToken": "Sink Token", - "encodeOutputUrl": "輸出(複製) URL 時進行轉義", - "chooseShowedPicBed": "請選擇顯示在菜單的圖床", - "galleryPicBedFilter": "相簿圖床篩選器", - "galleryPicBedFilterDescription": "選擇在相簿中顯示的圖床類型。如果未選擇任何圖床,將顯示所有圖床。" - }, - "advanced": { - "title": "高級", - "logging": "日誌", - "logFilePath": "日誌文件路徑", - "setLog": "設置日誌", - "logFile": "常規日誌文件", - "guiLogFile": "GUI 日誌文件", - "manageLogFile": "管理日誌文件", - "logLevel": "日誌記錄等級", - "chooseLogLevel": "請選擇日誌記錄等級", - "logFileSize": "日誌文件大小", - "networkAndProxy": "網絡與代理", - "setProxyAndMirror": "設置代理和鏡像地址", - "uploadProxy": "上傳代理", - "pluginInstallProxy": "插件安裝代理", - "pluginInstallMirror": "插件安裝鏡像", - "serverSettings": "伺服器設置", - "enableServer": "是否開啟上傳API服務", - "uploadServer": "上傳API服務設置", - "serverSettingsNotice": "如果你不知道上傳API服務的作用,請閱讀文檔,或者不用修改配置。", - "serverHost": "監聽地址", - "serverPort": "監聽端口", - "serverKey": "鑑權密鑰", - "serverKeyPlaceholder": "請輸入鑑權密鑰,用於防止接口濫用", - "webServerSettings": "Web 服務設置", - "webServerNotice": "如果你不知道 Web 服務的作用,請閱讀文檔,或者不用修改配置。", - "enableWebServer": "是否開啟 Web 服務", - "webServerHost": "Web 服務監聽地址", - "webServerPort": "Web 服務監聽端口", - "webServerPath": "Web 服務路徑", - "webServerPlaceholderHost": "推薦默認地址: 127.0.0.1", - "webServerPlaceholderPort": "推薦默認端口: 37777", - "serverEncryptionKey": "接口數據加密密鑰", - "logLevelList": { - "all": "全部", - "success": "成功", - "info": "信息", - "warn": "警告", - "error": "錯誤", - "none": "不記錄日誌" - } - }, - "update": { - "title": "更新", - "applicationUpdates": "應用程序更新", - "checkUpdate": "檢查更新", - "clickToCheck": "點擊檢查", - "openUpdateHelper": "打開更新提醒", - "openUpdateHelperDesc": "當有新版本時顯示通知", - "currentVersion": "當前版本: {version}", - "newestVersion": "最新版本", - "getting": "正在獲取中...", - "hasNewVersion": "PicList 更新啦,請點擊確定重啟觸發更新", - "networkError": "網絡錯誤,請檢查網絡連接", - "releaseNotes": "版本說明", - "releaseNotesDescription": "查看最新的更改和更新內容", - "latestReleaseNotes": "最新版本說明", - "refresh": "刷新", - "retry": "重試", - "loadingReleaseNotes": "正在載入版本說明...", - "releaseNotesError": "載入版本說明失敗,請檢查網絡連接。", - "noReleaseNotes": "暫無版本說明", - "lastUpdated": "最後更新", - "justNow": "剛剛", - "minutesAgo": "{minutes} 分鐘前", - "hoursAgo": "{hours} 小時前", - "daysAgo": "{days} 天前" - } - }, - "plugin": { - "title": "插件", - "description": "PicList 插件管理頁面", - "importLocal": "匯入本地插件", - "updateAll": "更新全部插件", - "list": "插件列表", - "searchPlaceholder": "搜尋 npm 上的 PicGo 插件,或者點擊上方按鈕查看優秀插件列表", - "needRestart": "需要重啟生效", - "restartApp": "重啟應用", - "loading": "載入中...", - "install": "安裝", - "installing": "安裝中", - "installed": "已安裝", - "doingSomething": "進行中", - "settings": "設定", - "disabled": "已停用", - "noPluginsFound": "未找到插件", - "tryDifferentSearch": "嘗試不同的搜尋關鍵詞", - "NoPluginsInstalled": "尚未安裝任何插件", - "installPluginsToGetStarted": "請先安裝插件以開始使用", - "browsePlugins": "瀏覽插件", - "configThing": "配置 {c}", - "pluginList": "插件列表", - "notGuiImplement": "該插件未針對圖形介面進行優化,是否繼續安裝?", - "updateSuccess": "插件更新成功", - "setResult": "設定結果", - "setSuccess": "設定成功" - }, - "inputBox": { - "title": "輸入框" - }, "configForm": { "configName": "配置名稱", "configNamePlaceholder": "請輸入配置名稱" }, - "rename": { - "placeholder": "請輸入新的檔案名稱" - }, - "shortKey": { - "title": "快捷鍵", - "name": "快捷鍵名稱", - "bind": "快捷鍵綁定", - "status": "狀態", - "source": "來源", - "handle": "操作", - "noBinding": "未綁定", - "enable": "啟用", - "disable": "停用", - "enabled": "已啟用", - "disabled": "已停用", - "edit": "編輯", - "changeUpload": "修改上傳快捷鍵", - "keyBinding": "按鍵綁定", - "pressKeys": "按下要設定的快捷鍵", - "pressHint": "點擊輸入框並按下你想要綁定的按鍵" - }, - "picBedConfigs": { - "title": "配置", - "viewDoc": "查看文件", - "copyAPI": "複製上傳API", - "noConfigOptions": "暫無配置項", - "setSuccess": "設定成功", - "setFailedInfo": "設定失敗,請檢查配置項是否正確", - "loadConfigFailed": "載入配置失敗,請檢查配置文件是否正確", - "loadPicBedListFailed": "載入圖床列表失敗", - "importConfigSuccess": "匯入配置成功", - "importConfigFailed": "匯入配置失敗", - "resetSuccess": "重設成功", - "resetFailed": "重設失敗,請檢查配置項是否正確", - "viewDocFailed": "查看文件失敗", - "noConfigs": "配置為空", - "copyAPISucceed": "複製 API 位址成功", - "copyAPIFailed": "複製 API 位址失敗" - }, - "uploaderConfig": { - "title": "圖床配置", - "selected": "已選取", - "edit": "編輯", - "delete": "刪除", - "addNew": "新增", - "setAsDefault": "設為預設圖床", - "setSuccess": "設定成功", - "deleteTitle": "通知", - "deleteConfirm": "確認刪除圖床配置嗎?", - "deleteSuccess": "刪除成功" - }, - "toolbox": { - "title": "排查 PicList 執行時問題", - "description": "立即掃描以下項目,修復使用問題", - "startScan": "開始掃描", - "success": "恭喜你,沒有檢查出問題", - "startFix": "開始修復", - "autoFixFail": "自動修復失敗,請自行修復以下問題", - "reScan": "重新掃描", - "checkConfigFileBroken": "檢查配置文件是否損壞", - "openConfigFile": "打開配置文件", - "checkGalleryFileBroken": "檢查相冊文件是否損壞", - "checkProblemWithClipboardPicUpload": "檢查剪貼板圖片上傳是否存在問題", - "openFilePath": "打開文件路徑", - "checkProblemWithProxy": "檢查代理設置是否正常", - "fixDoneNeedReload": "修復完成,需要重啟生效,是否重啟", - "notice": "通知" - }, "gallery": { - "title": "相簿", - "images": "圖片", - "syncDelete": "刪除雲端", - "hideFilters": "過濾器", - "showFilters": "過濾器", - "refresh": "刷新", - "picBedType": "圖床類型", - "chooseShowedPicBed": "請選擇顯示的圖床", - "selected": "已選擇", - "dateRange": "日期範圍", - "pasteFormat": "粘貼格式", - "urlType": "連結類型", - "sort": "排序", - "sortBy": { - "name": "名稱", - "time": "日期", - "ext": "後綴", - "check": "已選中" - }, - "searchFilename": "搜索文件名", - "searchUrl": "搜索URL", - "copy": "複製", - "edit": "編輯", - "delete": "刪除", - "selectAll": "全選", - "cancel": "取消", - "noImagesFound": "未找到圖片", - "tryAdjustingFilters": "嘗試調整過濾器或上傳一些圖片", - "changeImageUrl": "修改圖片URL", "batchEditUrl": "批量修改URL", + "cancel": "取消", + "canceled": "已取消", + "changeImageUrl": "修改圖片URL", + "chooseShowedPicBed": "請選擇顯示的圖床", + "cloudDeleteFailed": "雲端刪除失敗", + "cloudDeleteSucceed": "雲端刪除成功", + "confirmRemove": "確認刪除選中的圖片嗎?", + "copy": "複製", + "copyLinkSucceed": "複製連結成功", + "dateRange": "日期範圍", + "delete": "刪除", + "edit": "編輯", + "gridView": "網格", + "haveDuplicate": "已選中的圖片中有命名重複, 是否繼續?", + "hideFilters": "過濾器", + "images": "圖片", + "inputRegexTip": "請輸入匹配字串", + "isAlwaysForceReload": "無快取", + "listView": "列表", + "longUrl": "長連結", + "noImagesFound": "未找到圖片", + "noItemsNeedRename": "沒有需要重命名的項目", + "noMatch": "未找到匹配項", + "notice": "通知", + "operationFailed": "操作失敗", + "operationSucceed": "操作成功", + "pasteFormat": "粘貼格式", + "picBedType": "圖床類型", + "previewHelp": "滾輪縮放 • 拖拽平移 • 方向鍵導航 • ESC關閉", + "refresh": "刷新", "regexPattern": "進行替換時匹配的字符串或js正則表達式 匹配到: {matched} 個", "regexPatternPlaceholder": "例如:^\\d{4}-\\d{2}-\\d{2}, 不包含正則兩邊的斜杠", "replacedWith": "需要替換的字符串,可使用自定義重命名規則中的佔位符", - "longUrl": "長連結", + "searchFilename": "搜索文件名", + "searchUrl": "搜索URL", + "selectAll": "全選", + "selected": "已選擇", "shortUrl": "短連結", - "copyLinkSucceed": "複製連結成功", - "notice": "通知", - "confirmRemove": "確認刪除選中的圖片嗎?", - "cloudDeleteSucceed": "雲端刪除成功", - "cloudDeleteFailed": "雲端刪除失敗", - "operationSucceed": "操作成功", - "operationFailed": "操作失敗", - "haveDuplicate": "已選中的圖片中有命名重複, 是否繼續?", - "canceled": "已取消", - "previewHelp": "滾輪縮放 • 拖拽平移 • 方向鍵導航 • ESC關閉", - "listView": "列表", - "gridView": "網格", - "isAlwaysForceReload": "無快取", - "inputRegexTip": "請輸入匹配字串", - "noMatch": "未找到匹配項", - "noItemsNeedRename": "沒有需要重命名的項目" + "showFilters": "過濾器", + "sort": "排序", + "sortBy": { + "check": "已選中", + "ext": "後綴", + "name": "名稱", + "time": "日期" + }, + "syncDelete": "刪除雲端", + "title": "相簿", + "tryAdjustingFilters": "嘗試調整過濾器或上傳一些圖片", + "urlType": "連結類型" }, - "tray": { - "openMainWindow": "打開主窗口", - "waitForUpload": "等待上傳", - "uploaded": "已上傳", - "copySuccess": "複製成功" + "imageProcess": { + "cancel": "取消", + "confirm": "確認", + "description": "配置圖片處理選項,包括壓縮、水印、格式轉換等", + "general": { + "basicImageProcessing": "基本圖像處理", + "destinationFormat": "目標格式", + "formatConversion": "圖片格式轉換", + "isConvert": "轉換格式", + "isRemoveExif": "移除 Exif 信息", + "quality": "壓縮質量 (1-100)", + "skipProcessExtList": "跳過處理的文件擴展名列表", + "skipProcessExtListLabel": "跳過處理的擴展名", + "skipProcessExtListPlaceholder": "輸入要跳過處理的文件擴展名,以逗號分隔(例如:jpg,png,gif)", + "specificFormatConversion": "精細化轉換格式,請填寫 JSON 格式,如: {'{'}\"png\": \"jpg\"{'}'}" + }, + "generalSettings": "常規", + "perPicBed": { + "description": "為每個圖床單獨配置設置", + "title": "圖床獨立設置" + }, + "title": "圖片處理設置", + "transform": { + "description": "調整圖片大小、旋轉、翻轉等", + "isFlip": "垂直翻轉", + "isFlop": "水平翻轉", + "isResize": "啟用調整大小", + "isResizeByPercent": "啟用按比例調整", + "isResizeByPercentHint": "優先級更高", + "isRotate": "啟用旋轉", + "percentageResize": "按比例調整尺寸", + "resizeDescription": "設置圖片縮放參數", + "resizeHeight": "調整高度 (0 表示按寬度等比縮放)", + "resizePercent": "調整比例 (輸入 50 表示 50%)", + "resizeTitle": "調整大小", + "resizeWidth": "調整寬度 (0 表示按高度等比縮放)", + "rotationDegree": "旋轉角度", + "rotationDescription": "設置圖片旋轉參數", + "rotationTitle": "旋轉設置", + "skipResizeOfSmallImgHeight": "當圖片小於設定時跳過縮放", + "title": "變換設置" + }, + "transformSettings": "變換", + "watermark": { + "color": "水印顏色,手動輸入或取色器", + "degree": "水印旋轉角度", + "description": "添加文字或圖片水印到圖片上", + "image": "圖片", + "imageOpacity": "水印透明度", + "imagePath": "水印圖片路徑(留空使用默認圖片)", + "imagePathPlaceholder": "可選,請輸入路徑", + "inputText": "水印文字", + "inputTextPlaceholder": "請輸入水印文字", + "isAdd": "啟用或禁用水印", + "isFullScreen": "是否全屏水印", + "position": "水印位置", + "positionOptions": { + "bottom": "下", + "bottomLeft": "左下", + "bottomRight": "右下", + "center": "中", + "left": "左", + "right": "右", + "top": "上", + "topLeft": "左上", + "topRight": "右上" + }, + "scaleRatio": "水印占原圖比例", + "text": "文字", + "textFontPath": "水印字體路徑(第一次使用前自動下載)", + "textFontPathPlaceholder": "可選,請輸入路徑", + "title": "水印設置", + "type": "水印類型" + }, + "watermarkSettings": "水印" + }, + "inputBox": { + "title": "輸入框" }, "manage": { - "main": { - "openPicBedUrl": "開啟圖床官網", - "newBucket": "新建儲存桶", - "loading": "載入中...", - "backToHome": "首頁", - "switchPicBed": "切換", - "settings": "設定", - "bucket": "儲存桶", - "gallery": "相簿", - "repo": "倉庫", - "createSuccess": "建立成功", - "createFailed": "建立失敗" - }, - "empty": { - "noData": "暫無資料", - "noDataDesc": "請先建立儲存桶或上傳圖片" - }, - "setting": { - "clearCache": "清空檔案列表快取資料庫,已使用 {size},可用 {percent}%", - "clearCacheMsg": "確定要清空快取嗎?", - "isAutoRefreshTitle": "每次進入新目錄時,是否自動重新整理檔案列表", - "isAutoRefreshTips": "僅對非分頁模式有效,預設於載入一次後自動快取至資料庫以加快下次載入速度", - "isShowThumbnailTitle": "圖片顯示為原圖而非預設檔案格式圖示(需要儲存桶可公開存取)", - "isUsePreSignedUrlTitle": "是否使用預先簽名 URL 預覽圖片", - "isForceCustomUrlHttpsTitle": "為自訂網域啟用強制 HTTPS", - "isForceCustomUrlHttpsTips": "啟用後,複製連結等操作將會自動為自訂網域加入 https 前綴", - "isEncodeUrlTitle": "複製連結時進行 URL 編碼", - "isEncodeUrlTips": "可依平台選擇是否啟用", - "isUploadKeepDirStructureTitle": "上傳時保持目錄結構", - "isUploadKeepDirStructureTips": "關閉後會將所有檔案展開到指定目錄下", - "isIgnoreCaseTitle": "檔案搜尋時,是否忽略大小寫", - "isIgnoreCaseTips": "建議啟用", - "timestampRenameTitle": "上傳檔案時間戳重新命名(最高優先級)", - "timestampRenameTips": "啟用後,上傳的檔案將自動更名為時間戳", - "randomStringRenameTitle": "上傳檔案隨機字串重新命名(中優先級)", - "randomStringRenameTips": "20 位隨機字元", - "customRenameTitle": "上傳檔案自訂重新命名(低優先級)", - "customRenameTips": "啟用後填寫命名格式", - "customRenameTableTitle": "自訂重新命名格式參考表", - "customRenameTablePlaceholder": "請輸入自訂重新命名格式", - "placeholder": "佔位符", - "description": "描述", - "copySuccess": "已複製 {name}", - "download": "下載", - "file": "檔案", - "folder": "資料夾", - "keepDirStructure": "保持目錄結構", - "keepDirStructureDesc": "啟用後,下載時會保持原始目錄結構", - "clearSuccess": "清空快取成功", - "clearFailed": "清空快取失敗", - "notice": "通知", - "maxDownLoadFileLimit": "最大同時下載檔案數", - "maxDownLoadFileLimitDesc": "建議依網路情況調整", - "preSignedUrlExpire": "預先簽名 URL 過期時間(單位:秒)", - "preSignedUrlExpireDesc": "建議依實際需求調整", - "copyFormat": { - "title": "複製格式", - "markdown": "Markdown", - "rawurl": "原始 URL", - "markdown-with-link": "Markdown(含連結)", - "html": "HTML 格式", - "bbcode": "BBCode 格式", - "custom": "自訂格式", - "customTitle": "自訂連結格式($url 為連結,$fileName 為檔名)", - "customTips": "請依實際需求填寫自訂格式" - }, - "selectDownloadFolderTitle": "選擇下載資料夾", - "selectDownloadFolderTips": "選擇下載目錄", - "defaultDownloadFolder": "系統預設下載資料夾", - "browse": "瀏覽" - }, "bucket": { - "selectCustomDomain": "選擇自訂網域名稱", - "inputCustomDomain": "輸入自訂網域名稱", - "uploadFiles": "上傳檔案", - "uploadFromUrl": "從 URL 上傳", - "createFolder": "建立資料夾", - "downloadPage": "下載頁面", "batchRename": "批次重新命名", - "copyFileIno": "複製檔案資訊", - "forceRefreshFileList": "強制重新整理檔案清單", - "searchPlaceholder": "搜尋檔名", - "rootFolder": "根目錄", - "fileNum": "檔案數: {num}", - "pageFileSize": "總大小: {size}", - "selectAll": "全選", "cancel": "取消", - "reverseSelect": "反選", + "canceled": "已取消", + "clear": "清空", + "clearAll": "清空所有任務", + "clearFinishedTasks": "清空已完成任務", + "clickUpload": "或: 點擊選擇檔案", + "copyDownloadTask": "複製下載任務資訊", + "copyFileInfoInJson": "複製檔案資訊為 JSON", + "copyFileIno": "複製檔案資訊", + "copySuccess": "複製成功", + "copyUploadTask": "複製上傳任務資訊", + "createFailed": "建立失敗", + "createFolder": "建立資料夾", + "createSuccess": "建立成功,請重新整理", + "deleteFailed": "刪除失敗", + "deleteMsg": "將永久刪除,是否繼續?", + "deleteMultiMsg": "刪除成功 {success} 個,失敗 {failed} 個", + "deleteSuccess": "刪除成功", + "deletingMsg": "正在刪除中,請稍候...", "downloadBtn": "下載 {num}", + "downloadFolderNotice": "確定要下載此資料夾嗎?", + "downloading": "下載中", + "downloadPage": "下載頁面", + "dragUpload": "拖曳上傳 支援目錄", + "enterFullScreen": "進入全螢幕(F11)", + "excludeExt": "替換時不包含副檔名", + "exitFullScreen": "退出全螢幕(F11)", + "failed": "失敗", + "fileDupNotice": "偵測到有 {number} 個檔名重複, 是否繼續?", + "fileInfo": "檔案資訊", + "fileNum": "檔案數: {num}", + "forceRefreshFileList": "強制重新整理檔案清單", + "getDownloadListFailed": "取得下載清單失敗", + "getDownloadListSuccess": "取得下載清單成功", + "getFileListFailed": "取得檔案清單失敗", + "getFileListSuccess": "取得檔案清單成功", + "getInBackground": "正在背景取得檔案清單,請不要切換頁面", + "includeExt": "替換時包含副檔名", + "inputCustomDomain": "輸入自訂網域名稱", + "inputFolderTitle": "請輸入資料夾名稱", + "inputPatternMsg": "請輸入匹配字串", + "inputValidUrlMsg": "請輸入有效的 URL", + "isLoadingMsg": "正在載入中,請稍候...", + "keepDirStructure": "保持目錄結構", + "lastPageMsg": "已是最後一頁", + "linkFormat": { + "bbcode": "BBCode", + "custom": "自訂", + "html": "HTML", + "markdown": "Markdown", + "markdown-with-link": "Markdown(帶連結)", + "presign": "預先簽名連結", + "url": "Url" + }, + "loading": "載入中,點擊取消", + "loadingFailed": "載入失敗", + "matchedPattern": "用字串或正則表達式匹配 - 已匹配 {num} 個", + "noFileNeedRename": "沒有需要重新命名的檔案", + "noKeepDirStructure": "不保持目錄結構", + "noMatchedFile": "未找到匹配檔案", + "noNeedToRename": "無需重新命名", + "notice": "通知", + "openDownloadFolder": "開啟下載資料夾", + "pageFileSize": "總大小: {size}", + "partFileListFailed": "部分檔案取得失敗", + "play": "播放", + "prepareDownload": "正在準備下載,點擊取消", + "preview": "預覽", + "readingDir": "讀取中,請稍候", + "regexPatternTips": "正則表達式不需要加/", + "regexPlaceholder": "請輸入正則表達式或匹配字串", "removeBtn": "刪除 {num}", + "renameFailed": "重新命名失敗", + "renameFile": "重新命名檔案", + "renameResultMsg": "重新命名成功 {success} 個,失敗 {failed} 個", + "renameSuccess": "重新命名成功", + "replaceInput": "需要替換為的字串,可使用自訂重新命名中的佔位符", + "reverseSelect": "反選", + "rootFolder": "根目錄", + "searchPlaceholder": "搜尋檔名", + "selectAll": "全選", + "selectCustomDomain": "選擇自訂網域名稱", + "selectFileMsg": "請先選擇檔案", "sort": { - "title": "排序", + "check": "選取狀態", + "ext": "類型", + "init": "初始化", "name": "檔名", "size": "大小", "time": "時間", - "ext": "類型", - "check": "選取狀態", - "init": "初始化" + "title": "排序" }, - "enterFullScreen": "進入全螢幕(F11)", - "exitFullScreen": "退出全螢幕(F11)", - "linkFormat": { - "url": "Url", - "markdown": "Markdown", - "markdown-with-link": "Markdown(帶連結)", - "html": "HTML", - "bbcode": "BBCode", - "custom": "自訂", - "presign": "預先簽名連結" - }, - "urlUploadTitle": "請輸入 URL,以換行分隔", - "fileInfo": "檔案資訊", - "copyFileInfoInJson": "複製檔案資訊為 JSON", - "renameFile": "重新命名檔案", - "matchedPattern": "用字串或正則表達式匹配 - 已匹配 {num} 個", - "regexPatternTips": "正則表達式不需要加/", - "regexPlaceholder": "請輸入正則表達式或匹配字串", - "replaceInput": "需要替換為的字串,可使用自訂重新命名中的佔位符", - "excludeExt": "替換時不包含副檔名", - "includeExt": "替換時包含副檔名", - "loading": "載入中,點擊取消", - "prepareDownload": "正在準備下載,點擊取消", - "keepDirStructure": "保持目錄結構", - "noKeepDirStructure": "不保持目錄結構", - "uploadFile": "上傳檔案", - "dragUpload": "拖曳上傳 支援目錄", - "clickUpload": "或: 點擊選擇檔案", - "readingDir": "讀取中,請稍候", - "upload": "上傳", - "clear": "清空", - "uploading": "上傳中", - "success": "成功", - "failed": "失敗", - "copyUploadTask": "複製上傳任務資訊", - "clearFinishedTasks": "清空已完成任務", - "clearAll": "清空所有任務", - "downloading": "下載中", - "copyDownloadTask": "複製下載任務資訊", - "openDownloadFolder": "開啟下載資料夾", - "preview": "預覽", - "play": "播放", - "notice": "通知", - "downloadFolderNotice": "確定要下載此資料夾嗎?", - "getDownloadListSuccess": "取得下載清單成功", - "getDownloadListFailed": "取得下載清單失敗", - "canceled": "已取消", - "copySuccess": "複製成功", - "deleteSuccess": "刪除成功", - "deleteFailed": "刪除失敗", - "deleteMultiMsg": "刪除成功 {success} 個,失敗 {failed} 個", "startLoadingFile": "開始載入檔案", - "loadingFailed": "載入失敗", - "lastPageMsg": "已是最後一頁", - "getFileListSuccess": "取得檔案清單成功", - "getFileListFailed": "取得檔案清單失敗", - "partFileListFailed": "部分檔案取得失敗", - "getInBackground": "正在背景取得檔案清單,請不要切換頁面", - "isLoadingMsg": "正在載入中,請稍候...", - "inputFolderTitle": "請輸入資料夾名稱", - "createSuccess": "建立成功,請重新整理", - "createFailed": "建立失敗", - "inputValidUrlMsg": "請輸入有效的 URL", "startUploadMsg": "開始背景下載,成功後自動上傳", - "inputPatternMsg": "請輸入匹配字串", - "noMatchedFile": "未找到匹配檔案", - "noFileNeedRename": "沒有需要重新命名的檔案", - "fileDupNotice": "偵測到有 {number} 個檔名重複, 是否繼續?", - "renameResultMsg": "重新命名成功 {success} 個,失敗 {failed} 個", - "selectFileMsg": "請先選擇檔案", + "stopGetDownloadListMsg": "是否停止取得下載檔案?", "stopGetFileListMsg": "是否停止取得檔案清單?", "stopSuccessMsg": "停止成功", - "stopGetDownloadListMsg": "是否停止取得下載檔案?", - "willDeleteMsg": "即將刪除 {num} 個檔案,是否繼續?", - "deleteMsg": "將永久刪除,是否繼續?", - "deletingMsg": "正在刪除中,請稍候...", - "noNeedToRename": "無需重新命名", - "renameSuccess": "重新命名成功", - "renameFailed": "重新命名失敗" - }, - "newBucket": { - "bucketDesc": "儲存桶名稱", - "bucketPlaceholder": "請輸入儲存桶名稱", - "bucketNoEmpty": "儲存桶名稱不能為空", - "region": "區域", - "acl": { - "title": "存取控制", - "private": "私有", - "publicRead": "公開讀取", - "publicReadWrite": "公開讀寫", - "authenticatedRead": "已認證讀取" - }, - "tcyun": { - "name": "騰訊雲", - "bucketLengthMsg": "Bucket 名稱長度不能超過 23 個字元", - "bucketCharMsg": "Bucket 名稱只能包含小寫字母、數字和連字號,且不能以連字號開頭或結尾" - }, - "aliyun": { - "name": "阿里雲", - "bucketLengthMsg": "Bucket 名稱長度必須在 3 到 63 個字元之間", - "bucketCharMsg": "Bucket 名稱只能包含小寫字母、數字和連字號,且不能以連字號開頭或結尾" - }, - "qiniu": { - "name": "七牛雲", - "bucketLengthMsg": "Bucket 名稱長度必須在 3 到 63 個字元之間", - "bucketCharMsg": "Bucket 名稱只能包含小寫字母、數字和連字號,且不能以連字號開頭或結尾", - "publicAccess": "公開存取" - }, - "s3": { - "name": "S3" - } - }, - "login": { - "title": "圖床管理", - "savedConfigs": "已儲存設定", - "refresh": "重新整理", - "noConfigs": "未找到設定", - "noConfigsDesc": "請檢查您的設定檔或重新載入頁面", - "viewDetails": "查看詳情", - "enter": "進入", - "delete": "刪除", - "selectPlaceholder": "請選擇", - "import": "匯入", - "save": "儲存", - "reset": "重設", - "configTabTitle": "已有設定,點擊複製", - "noRequiredMsg": "請填寫必填欄位", - "aliasMsg": "別名只能包含中文、英文、數字、底線和連字號", - "itemsPerPageMsg": "每頁顯示的數量必須為 20 到 1000 之間的整數", - "configChangeMsg": "設定已變更", - "configSaveMsg": "設定已儲存", - "deleteConfigSuccessMsg": "刪除設定成功", - "deleteConfigFailedMsg": "刪除設定失敗", - "copySuccess": "複製成功: {text}", - "importSuccess": "匯入成功", - "tips": "提示", - "confirmDeleteConfig": "確認要刪除此設定嗎?" + "success": "成功", + "upload": "上傳", + "uploadFile": "上傳檔案", + "uploadFiles": "上傳檔案", + "uploadFromUrl": "從 URL 上傳", + "uploading": "上傳中", + "urlUploadTitle": "請輸入 URL,以換行分隔", + "willDeleteMsg": "即將刪除 {num} 個檔案,是否繼續?" }, "constant": { - "pleaseInput": "請輸入: {name}", - "inputItemsPerPage": "輸入每頁顯示的數量", - "itemsPPBeNumber": "每頁顯示的數量必須為數字", - "itemsPPBeNumberLimit": "每頁顯示的數量必須在 20 到 1000 之間", - "inputAlias": "請輸入別名,作為此設定的唯一識別", - "aliasRuleMsg": "別名只能包含中文、英文、數字、底線和連字號", - "aliasTip": "別名只能包含中文、英文、數字、底線和連字號", - "itemsPPTip": "每頁顯示的數量必須在 20 到 1000 之間", - "pagingTip": "關閉分頁時,目錄清單將使用資料庫快取以優化效能", - "bucketNameTip": "以英文逗號分隔,例如:bucket1,bucket2,與起始目錄一一對應", - "baseDirTip": "以英文逗號分隔,例如:/dir1,/dir2,與儲存桶一一對應", - "isAutoCustomUrlTip": "開啟後,將自動取得儲存桶綁定的網域", - "aliasDesc": "設定別名", - "aliasPlaceholder": "此設定的唯一識別", - "pagingDesc": "是否啟用分頁", - "referText": "設定教學請參考:", "accessKeyDesc": "Access Key,可在主控台取得", - "accessKeyPlaceholder": "請輸入 Access Key", "accessKeyIdDesc": "Access Key ID,可在主控台取得", "accessKeyIdPlaceholder": "請輸入 Access Key ID", - "secretIdDesc": "Secret ID,可在主控台取得", - "secretIdPlaceholder": "請輸入 Secret ID", - "secretKeyDesc": "Secret Key,可在主控台取得", - "secretKeyPlaceholder": "請輸入 Secret Key", + "accessKeyPlaceholder": "請輸入 Access Key", "accessKeySecretDesc": "Access Key Secret,可在主控台取得", "accessKeySecretPlaceholder": "請輸入 Access Key Secret", - "secretKeyIdDesc": "Secret Key,可在主控台取得", - "secretKeyIdPlaceholder": "請輸入 Secret Key", - "bucketDesc": "儲存桶名稱,選填", - "bucketPlaceholder": "以英文逗號分隔,例如:bucket1,bucket2", - "baseDirDesc": "起始目錄,選填", - "baseDirPlaceholder": "以英文逗號分隔,例如:/dir1,/dir2", - "isAutoGetCustomUrl": "是否自動取得綁定網域", - "isEnablePaging": "是否啟用分頁", - "itemsPerPage": "每頁顯示的數量", - "userNameDesc": "使用者名稱", - "userNamePlaceholder": "請輸入使用者名稱", - "passwordDesc": "密碼", - "passwordPlaceholder": "請輸入密碼", - "proxyDesc": "代理位址", - "proxyPlaceholder": "例如:http://127.0.0.1:7890", - "proxyTips": "部分圖床可能需要代理才能正常存取", - "explain": "空間名與起始目錄可用英文逗號分隔設定,順序必須一致;逗號間留白或缺漏項將使用預設值", - "specialDesc": "特殊設定", - "specialPlaceholder": "請輸入特殊設定", - "specialTips": "此設定不可修改,僅供內部相容性處理使用", - "smms": { - "tokenDesc": "SM.MS Token,可在 SM.MS 個人中心取得", - "tokenPlaceholder": "請輸入 SM.MS Token", - "explain": "中國大陸地區請訪問備用網域 https://sm.ms,請勿在短時間內大量請求" - }, - "qiniu": { - "name": "七牛雲" - }, - "github": { - "tokenDesc": "GitHub Token,可在 GitHub 設定中取得", - "tokenPlaceholder": "請輸入 GitHub Token", - "tokenTips": "請提供具有完整 repo 權限的 token,否則部分功能可能無法使用", - "cdnUrlDesc": "CDN 加速網域", - "cdnUrlPlaceholder": "支援使用 {'{'}username{'}'}、{'{'}repo{'}'}、{'{'}branch{'}'} 和 {'{'}path{'}'} 作為替代占位符,用於適配不同的版本庫與分支", - "cdnUrlTips": "例如:`https://cdn.staticaly.com/gh/{'{'}username{'}'}/{'{'}repo{'}'}{'@'}{'{'}branch{'}'}/{'{'}path{'}'}`", - "protocolRuleMsg": "請以 http:// 或 https:// 開頭", - "bracketRuleMsg": "大括號必須成對出現", - "explain": "API 呼叫每小時有上限,不支援上傳超過 100 MB 的檔案" - }, + "aliasDesc": "設定別名", + "aliasPlaceholder": "此設定的唯一識別", + "aliasRuleMsg": "別名只能包含中文、英文、數字、底線和連字號", + "aliasTip": "別名只能包含中文、英文、數字、底線和連字號", "aliyun": { "name": "阿里雲" }, - "tcyun": { - "name": "騰訊雲", - "appIdDesc": "App ID,可在騰訊雲主控台取得", - "appIdPlaceholder": "請輸入 App ID", - "appIdTips": "例如:1250000000" - }, - "upyun": { - "name": "又拍雲", - "bucketDesc": "服務名", - "bucketPlaceholder": "對應其他物件儲存的儲存桶名稱", - "operatorNameDesc": "操作員", - "operatorNamePlaceholder": "使用具有完整權限的操作員", - "operatorPassDesc": "操作員密碼", - "operatorPassPlaceholder": "請輸入操作員密碼", - "baseDirDesc": "起始目錄", - "baseDirPlaceholder": "請輸入起始目錄", - "accelerationUrlDesc": "加速網域", - "accelerationUrlPlaceholder": "請輸入加速網域", - "notEmpty": "加速網域不得為空", + "baseDirDesc": "起始目錄,選填", + "baseDirPlaceholder": "以英文逗號分隔,例如:/dir1,/dir2", + "baseDirTip": "以英文逗號分隔,例如:/dir1,/dir2,與儲存桶一一對應", + "bucketDesc": "儲存桶名稱,選填", + "bucketNameTip": "以英文逗號分隔,例如:bucket1,bucket2,與起始目錄一一對應", + "bucketPlaceholder": "以英文逗號分隔,例如:bucket1,bucket2", + "explain": "空間名與起始目錄可用英文逗號分隔設定,順序必須一致;逗號間留白或缺漏項將使用預設值", + "github": { + "bracketRuleMsg": "大括號必須成對出現", + "cdnUrlDesc": "CDN 加速網域", + "cdnUrlPlaceholder": "支援使用 {'{'}username{'}'}、{'{'}repo{'}'}、{'{'}branch{'}'} 和 {'{'}path{'}'} 作為替代占位符,用於適配不同的版本庫與分支", + "cdnUrlTips": "例如:`https://cdn.staticaly.com/gh/{'{'}username{'}'}/{'{'}repo{'}'}{'@'}{'{'}branch{'}'}/{'{'}path{'}'}`", + "explain": "API 呼叫每小時有上限,不支援上傳超過 100 MB 的檔案", "protocolRuleMsg": "請以 http:// 或 https:// 開頭", - "antiLeechTokenDesc": "反盜鏈 Token", - "antiLeechTokenPlaceholder": "請輸入反盜鏈 Token", - "antiLeechTokenTooltip": "如果不填寫,預設不啟用反盜鏈", - "antiLeechExp": "反盜鏈到期時間", - "explain": "務必填寫加速網域,否則無法正常使用" + "tokenDesc": "GitHub Token,可在 GitHub 設定中取得", + "tokenPlaceholder": "請輸入 GitHub Token", + "tokenTips": "請提供具有完整 repo 權限的 token,否則部分功能可能無法使用" }, "imgur": { "accessTokenDesc": "access token", @@ -853,86 +310,629 @@ "accessTokenTips": "不是 clientID,請參考教學取得", "explain": "中國大陸地區請使用代理;API 呼叫存在限制,請留意使用頻率" }, - "s3": { - "endpointDesc": "endpoint", - "endpointPlaceholder": "例如:s3.us-east-1.amazonaws.com", - "endpointTips": "不填寫則預設使用 AWS S3", - "enableHttps": "是否啟用 HTTPS", - "enableHttpsTip": "啟用後,所有請求將使用 HTTPS", - "enableS3PathStyle": "啟用 S3 path style", - "enableS3PathStyleTip": "例如使用 MinIO 時需要開啟", - "aclDesc": "上傳檔案權限設定", - "acl": { - "private": "私有", - "publicRead": "公共讀取", - "publicReadWrite": "公共讀寫", - "authenticatedRead": "已驗證讀取", - "bucketOwnerRead": "儲存桶擁有者讀取", - "bucketOwnerFullControl": "儲存桶擁有者完全控制", - "awsExecRead": "AWS 執行讀取" - }, - "aclTips": "請依實際需求選擇合適的權限設定", - "enableDogeSupport": "是否啟用 Doge 支援", - "enableDogeSupportTip": "啟用後,所有請求將使用 Doge API" - }, - "webdav": { - "hostDesc": "位址", - "hostPlaceholder": "例如:https://example.com/dav", - "hostTips": "請填寫 WebDAV 協定位址", - "baseDirDesc": "起始目錄", - "baseDirPlaceholder": "例如:/dir1", - "customUrlDesc": "自訂 URL", - "customUrlPlaceholder": "例如:https://example.com/custom", - "customUrlTips": "若存取網址與介面位址不一致,請填寫自訂 URL", - "protocolRuleMsg": "請以 http:// 或 https:// 開頭", - "webPathDesc": "用於網址拼接的起始路徑", - "webPathPlaceholder": "例如:/dir2", - "webPathTips": "用於拼接對外存取網址", - "enableHttpsDesc": "是否啟用 HTTPS", - "enableHttpsTips": "啟用後,所有請求將使用 HTTPS", - "authTypeDesc": "認證類型", - "explain": "不同平台的 WebDAV 協定可能有所差異,請依實際情況選擇" - }, + "inputAlias": "請輸入別名,作為此設定的唯一識別", + "inputItemsPerPage": "輸入每頁顯示的數量", + "isAutoCustomUrlTip": "開啟後,將自動取得儲存桶綁定的網域", + "isAutoGetCustomUrl": "是否自動取得綁定網域", + "isEnablePaging": "是否啟用分頁", + "itemsPerPage": "每頁顯示的數量", + "itemsPPBeNumber": "每頁顯示的數量必須為數字", + "itemsPPBeNumberLimit": "每頁顯示的數量必須在 20 到 1000 之間", + "itemsPPTip": "每頁顯示的數量必須在 20 到 1000 之間", "local": { - "name": "本機儲存", "baseDirDesc": "起始目錄", "baseDirPlaceholder": "例如:/dir1", "baseDirRuleMsg": "起始目錄不得為空", "customUrlDesc": "自訂網域", "customUrlPlaceholder": "例如:https://example.com", - "customUrlTooltip": "若你的本機路徑可透過網路存取,請填寫", "customUrlRuleMsg": "請以 http:// 或 https:// 開頭", + "customUrlTooltip": "若你的本機路徑可透過網路存取,請填寫", + "explain": "本機儲存設定", + "name": "本機儲存", "webPathDesc": "用於網址拼接的起始路徑", "webPathPlaceholder": "例如:/dir2", - "webPathTips": "用於拼接對外存取網址", - "explain": "本機儲存設定" + "webPathTips": "用於拼接對外存取網址" }, + "pagingDesc": "是否啟用分頁", + "pagingTip": "關閉分頁時,目錄清單將使用資料庫快取以優化效能", + "passwordDesc": "密碼", + "passwordPlaceholder": "請輸入密碼", + "pleaseInput": "請輸入: {name}", + "proxyDesc": "代理位址", + "proxyPlaceholder": "例如:http://127.0.0.1:7890", + "proxyTips": "部分圖床可能需要代理才能正常存取", + "qiniu": { + "name": "七牛雲" + }, + "referText": "設定教學請參考:", + "s3": { + "acl": { + "authenticatedRead": "已驗證讀取", + "awsExecRead": "AWS 執行讀取", + "bucketOwnerFullControl": "儲存桶擁有者完全控制", + "bucketOwnerRead": "儲存桶擁有者讀取", + "private": "私有", + "publicRead": "公共讀取", + "publicReadWrite": "公共讀寫" + }, + "aclDesc": "上傳檔案權限設定", + "aclTips": "請依實際需求選擇合適的權限設定", + "enableDogeSupport": "是否啟用 Doge 支援", + "enableDogeSupportTip": "啟用後,所有請求將使用 Doge API", + "enableHttps": "是否啟用 HTTPS", + "enableHttpsTip": "啟用後,所有請求將使用 HTTPS", + "enableS3PathStyle": "啟用 S3 path style", + "enableS3PathStyleTip": "例如使用 MinIO 時需要開啟", + "endpointDesc": "endpoint", + "endpointPlaceholder": "例如:s3.us-east-1.amazonaws.com", + "endpointTips": "不填寫則預設使用 AWS S3" + }, + "secretIdDesc": "Secret ID,可在主控台取得", + "secretIdPlaceholder": "請輸入 Secret ID", + "secretKeyDesc": "Secret Key,可在主控台取得", + "secretKeyIdDesc": "Secret Key,可在主控台取得", + "secretKeyIdPlaceholder": "請輸入 Secret Key", + "secretKeyPlaceholder": "請輸入 Secret Key", "sftp": { - "hostDesc": "SSH 主機位址", - "hostPlaceholder": "例如:192.168.1.1", - "portDesc": "SSH 連接埠", - "portPlaceholder": "例如:22", - "privateKeyDesc": "私鑰", - "privateKeyPlaceholder": "請輸入私鑰", - "passphraseDesc": "私鑰密碼", - "passphrasePlaceholder": "請輸入私鑰密碼", - "fileModeDesc": "檔案權限設定", - "fileModePlaceholder": "例如:0644", - "dirModeDesc": "目錄權限設定", - "dirModePlaceholder": "例如:0755", "baseDirDesc": "起始目錄", "baseDirPlaceholder": "例如:/dir1", "baseDirTips": "起始目錄不得為空", "customUrlDesc": "自訂網域", "customUrlPlaceholder": "例如:https://example.com", "customUrlTips": "若對外存取網址與介面位址不一致,請填寫自訂 URL", + "dirModeDesc": "目錄權限設定", + "dirModePlaceholder": "例如:0755", + "explain": "SFTP 設定", + "fileModeDesc": "檔案權限設定", + "fileModePlaceholder": "例如:0644", + "hostDesc": "SSH 主機位址", + "hostPlaceholder": "例如:192.168.1.1", + "passphraseDesc": "私鑰密碼", + "passphrasePlaceholder": "請輸入私鑰密碼", + "portDesc": "SSH 連接埠", + "portPlaceholder": "例如:22", + "privateKeyDesc": "私鑰", + "privateKeyPlaceholder": "請輸入私鑰", "protocolRuleMsg": "請以 http:// 或 https:// 開頭", "webPathDesc": "用於網址拼接的起始路徑", "webPathPlaceholder": "例如:/dir2", - "webPathTips": "用於拼接對外存取網址", - "explain": "SFTP 設定" + "webPathTips": "用於拼接對外存取網址" + }, + "smms": { + "explain": "中國大陸地區請訪問備用網域 https://sm.ms,請勿在短時間內大量請求", + "tokenDesc": "SM.MS Token,可在 SM.MS 個人中心取得", + "tokenPlaceholder": "請輸入 SM.MS Token" + }, + "specialDesc": "特殊設定", + "specialPlaceholder": "請輸入特殊設定", + "specialTips": "此設定不可修改,僅供內部相容性處理使用", + "tcyun": { + "appIdDesc": "App ID,可在騰訊雲主控台取得", + "appIdPlaceholder": "請輸入 App ID", + "appIdTips": "例如:1250000000", + "name": "騰訊雲" + }, + "upyun": { + "accelerationUrlDesc": "加速網域", + "accelerationUrlPlaceholder": "請輸入加速網域", + "antiLeechExp": "反盜鏈到期時間", + "antiLeechTokenDesc": "反盜鏈 Token", + "antiLeechTokenPlaceholder": "請輸入反盜鏈 Token", + "antiLeechTokenTooltip": "如果不填寫,預設不啟用反盜鏈", + "baseDirDesc": "起始目錄", + "baseDirPlaceholder": "請輸入起始目錄", + "bucketDesc": "服務名", + "bucketPlaceholder": "對應其他物件儲存的儲存桶名稱", + "explain": "務必填寫加速網域,否則無法正常使用", + "name": "又拍雲", + "notEmpty": "加速網域不得為空", + "operatorNameDesc": "操作員", + "operatorNamePlaceholder": "使用具有完整權限的操作員", + "operatorPassDesc": "操作員密碼", + "operatorPassPlaceholder": "請輸入操作員密碼", + "protocolRuleMsg": "請以 http:// 或 https:// 開頭" + }, + "userNameDesc": "使用者名稱", + "userNamePlaceholder": "請輸入使用者名稱", + "webdav": { + "authTypeDesc": "認證類型", + "baseDirDesc": "起始目錄", + "baseDirPlaceholder": "例如:/dir1", + "customUrlDesc": "自訂 URL", + "customUrlPlaceholder": "例如:https://example.com/custom", + "customUrlTips": "若存取網址與介面位址不一致,請填寫自訂 URL", + "enableHttpsDesc": "是否啟用 HTTPS", + "enableHttpsTips": "啟用後,所有請求將使用 HTTPS", + "explain": "不同平台的 WebDAV 協定可能有所差異,請依實際情況選擇", + "hostDesc": "位址", + "hostPlaceholder": "例如:https://example.com/dav", + "hostTips": "請填寫 WebDAV 協定位址", + "protocolRuleMsg": "請以 http:// 或 https:// 開頭", + "webPathDesc": "用於網址拼接的起始路徑", + "webPathPlaceholder": "例如:/dir2", + "webPathTips": "用於拼接對外存取網址" } + }, + "empty": { + "noData": "暫無資料", + "noDataDesc": "請先建立儲存桶或上傳圖片" + }, + "login": { + "aliasMsg": "別名只能包含中文、英文、數字、底線和連字號", + "configChangeMsg": "設定已變更", + "configSaveMsg": "設定已儲存", + "configTabTitle": "已有設定,點擊複製", + "confirmDeleteConfig": "確認要刪除此設定嗎?", + "copySuccess": "複製成功: {text}", + "delete": "刪除", + "deleteConfigFailedMsg": "刪除設定失敗", + "deleteConfigSuccessMsg": "刪除設定成功", + "enter": "進入", + "import": "匯入", + "importSuccess": "匯入成功", + "itemsPerPageMsg": "每頁顯示的數量必須為 20 到 1000 之間的整數", + "noConfigs": "未找到設定", + "noConfigsDesc": "請檢查您的設定檔或重新載入頁面", + "noRequiredMsg": "請填寫必填欄位", + "refresh": "重新整理", + "reset": "重設", + "save": "儲存", + "savedConfigs": "已儲存設定", + "selectPlaceholder": "請選擇", + "tips": "提示", + "title": "圖床管理", + "viewDetails": "查看詳情" + }, + "main": { + "backToHome": "首頁", + "bucket": "儲存桶", + "createFailed": "建立失敗", + "createSuccess": "建立成功", + "gallery": "相簿", + "loading": "載入中...", + "newBucket": "新建儲存桶", + "openPicBedUrl": "開啟圖床官網", + "repo": "倉庫", + "settings": "設定", + "switchPicBed": "切換" + }, + "newBucket": { + "acl": { + "authenticatedRead": "已認證讀取", + "private": "私有", + "publicRead": "公開讀取", + "publicReadWrite": "公開讀寫", + "title": "存取控制" + }, + "aliyun": { + "bucketCharMsg": "Bucket 名稱只能包含小寫字母、數字和連字號,且不能以連字號開頭或結尾", + "bucketLengthMsg": "Bucket 名稱長度必須在 3 到 63 個字元之間", + "name": "阿里雲" + }, + "bucketDesc": "儲存桶名稱", + "bucketNoEmpty": "儲存桶名稱不能為空", + "bucketPlaceholder": "請輸入儲存桶名稱", + "qiniu": { + "bucketCharMsg": "Bucket 名稱只能包含小寫字母、數字和連字號,且不能以連字號開頭或結尾", + "bucketLengthMsg": "Bucket 名稱長度必須在 3 到 63 個字元之間", + "name": "七牛雲", + "publicAccess": "公開存取" + }, + "region": "區域", + "s3": { + "name": "S3" + }, + "tcyun": { + "bucketCharMsg": "Bucket 名稱只能包含小寫字母、數字和連字號,且不能以連字號開頭或結尾", + "bucketLengthMsg": "Bucket 名稱長度不能超過 23 個字元", + "name": "騰訊雲" + } + }, + "setting": { + "browse": "瀏覽", + "clearCache": "清空檔案列表快取資料庫,已使用 {size},可用 {percent}%", + "clearCacheMsg": "確定要清空快取嗎?", + "clearFailed": "清空快取失敗", + "clearSuccess": "清空快取成功", + "copyFormat": { + "bbcode": "BBCode 格式", + "custom": "自訂格式", + "customTips": "請依實際需求填寫自訂格式", + "customTitle": "自訂連結格式($url 為連結,$fileName 為檔名)", + "html": "HTML 格式", + "markdown": "Markdown", + "markdown-with-link": "Markdown(含連結)", + "rawurl": "原始 URL", + "title": "複製格式" + }, + "copySuccess": "已複製 {name}", + "customRenameTablePlaceholder": "請輸入自訂重新命名格式", + "customRenameTableTitle": "自訂重新命名格式參考表", + "customRenameTips": "啟用後填寫命名格式", + "customRenameTitle": "上傳檔案自訂重新命名(低優先級)", + "defaultDownloadFolder": "系統預設下載資料夾", + "description": "描述", + "download": "下載", + "file": "檔案", + "folder": "資料夾", + "isAutoRefreshTips": "僅對非分頁模式有效,預設於載入一次後自動快取至資料庫以加快下次載入速度", + "isAutoRefreshTitle": "每次進入新目錄時,是否自動重新整理檔案列表", + "isEncodeUrlTips": "可依平台選擇是否啟用", + "isEncodeUrlTitle": "複製連結時進行 URL 編碼", + "isForceCustomUrlHttpsTips": "啟用後,複製連結等操作將會自動為自訂網域加入 https 前綴", + "isForceCustomUrlHttpsTitle": "為自訂網域啟用強制 HTTPS", + "isIgnoreCaseTips": "建議啟用", + "isIgnoreCaseTitle": "檔案搜尋時,是否忽略大小寫", + "isShowThumbnailTitle": "圖片顯示為原圖而非預設檔案格式圖示(需要儲存桶可公開存取)", + "isUploadKeepDirStructureTips": "關閉後會將所有檔案展開到指定目錄下", + "isUploadKeepDirStructureTitle": "上傳時保持目錄結構", + "isUsePreSignedUrlTitle": "是否使用預先簽名 URL 預覽圖片", + "keepDirStructure": "保持目錄結構", + "keepDirStructureDesc": "啟用後,下載時會保持原始目錄結構", + "maxDownLoadFileLimit": "最大同時下載檔案數", + "maxDownLoadFileLimitDesc": "建議依網路情況調整", + "notice": "通知", + "placeholder": "佔位符", + "preSignedUrlExpire": "預先簽名 URL 過期時間(單位:秒)", + "preSignedUrlExpireDesc": "建議依實際需求調整", + "randomStringRenameTips": "20 位隨機字元", + "randomStringRenameTitle": "上傳檔案隨機字串重新命名(中優先級)", + "selectDownloadFolderTips": "選擇下載目錄", + "selectDownloadFolderTitle": "選擇下載資料夾", + "timestampRenameTips": "啟用後,上傳的檔案將自動更名為時間戳", + "timestampRenameTitle": "上傳檔案時間戳重新命名(最高優先級)" } + }, + "picBedConfigs": { + "copyAPI": "複製上傳API", + "copyAPIFailed": "複製 API 位址失敗", + "copyAPISucceed": "複製 API 位址成功", + "importConfigFailed": "匯入配置失敗", + "importConfigSuccess": "匯入配置成功", + "loadConfigFailed": "載入配置失敗,請檢查配置文件是否正確", + "loadPicBedListFailed": "載入圖床列表失敗", + "noConfigOptions": "暫無配置項", + "noConfigs": "配置為空", + "resetFailed": "重設失敗,請檢查配置項是否正確", + "resetSuccess": "重設成功", + "setFailedInfo": "設定失敗,請檢查配置項是否正確", + "setSuccess": "設定成功", + "title": "配置", + "viewDoc": "查看文件", + "viewDocFailed": "查看文件失敗" + }, + "plugin": { + "browsePlugins": "瀏覽插件", + "configThing": "配置 {c}", + "description": "PicList 插件管理頁面", + "disabled": "已停用", + "doingSomething": "進行中", + "importLocal": "匯入本地插件", + "install": "安裝", + "installed": "已安裝", + "installing": "安裝中", + "installPluginsToGetStarted": "請先安裝插件以開始使用", + "list": "插件列表", + "loading": "載入中...", + "needRestart": "需要重啟生效", + "noPluginsFound": "未找到插件", + "NoPluginsInstalled": "尚未安裝任何插件", + "notGuiImplement": "該插件未針對圖形介面進行優化,是否繼續安裝?", + "pluginList": "插件列表", + "restartApp": "重啟應用", + "searchPlaceholder": "搜尋 npm 上的 PicGo 插件,或者點擊上方按鈕查看優秀插件列表", + "setResult": "設定結果", + "setSuccess": "設定成功", + "settings": "設定", + "title": "插件", + "tryDifferentSearch": "嘗試不同的搜尋關鍵詞", + "updateAll": "更新全部插件", + "updateSuccess": "插件更新成功" + }, + "rename": { + "placeholder": "請輸入新的檔案名稱" + }, + "settings": { + "advanced": { + "chooseLogLevel": "請選擇日誌記錄等級", + "enableServer": "是否開啟上傳API服務", + "enableWebServer": "是否開啟 Web 服務", + "guiLogFile": "GUI 日誌文件", + "logFile": "常規日誌文件", + "logFilePath": "日誌文件路徑", + "logFileSize": "日誌文件大小", + "logging": "日誌", + "logLevel": "日誌記錄等級", + "logLevelList": { + "all": "全部", + "error": "錯誤", + "info": "信息", + "none": "不記錄日誌", + "success": "成功", + "warn": "警告" + }, + "manageLogFile": "管理日誌文件", + "networkAndProxy": "網絡與代理", + "pluginInstallMirror": "插件安裝鏡像", + "pluginInstallProxy": "插件安裝代理", + "serverEncryptionKey": "接口數據加密密鑰", + "serverHost": "監聽地址", + "serverKey": "鑑權密鑰", + "serverKeyPlaceholder": "請輸入鑑權密鑰,用於防止接口濫用", + "serverPort": "監聽端口", + "serverSettings": "伺服器設置", + "serverSettingsNotice": "如果你不知道上傳API服務的作用,請閱讀文檔,或者不用修改配置。", + "setLog": "設置日誌", + "setProxyAndMirror": "設置代理和鏡像地址", + "title": "高級", + "uploadProxy": "上傳代理", + "uploadServer": "上傳API服務設置", + "webServerHost": "Web 服務監聽地址", + "webServerNotice": "如果你不知道 Web 服務的作用,請閱讀文檔,或者不用修改配置。", + "webServerPath": "Web 服務路徑", + "webServerPlaceholderHost": "推薦默認地址: 127.0.0.1", + "webServerPlaceholderPort": "推薦默認端口: 37777", + "webServerPort": "Web 服務監聽端口", + "webServerSettings": "Web 服務設置" + }, + "clickToOpen": "點擊打開", + "clickToSet": "點擊設置", + "description": "配置 PicList 應用程序", + "docs": "文檔", + "sync": { + "allConfig": "所有配置", + "commonConfig": "通用配置", + "downloadSettings": "下載配置", + "fileManagement": "文件管理", + "gitea": { "branch": "分支名", "repo": "倉庫名", "token": "訪問令牌", "username": "用戶名" }, + "giteaHost": "Gitea 地址", + "gitee": { + "branch": "Gitee 分支名", + "repo": "Gitee 倉庫名", + "token": "Gitee 訪問令牌", + "username": "Gitee 用戶名" + }, + "github": { + "branch": "GitHub 分支名", + "repo": "私有倉庫名", + "token": "GitHub 訪問令牌", + "username": "GitHub 用戶名" + }, + "manageConfig": "管理配置", + "migrateFromPicGo": "從PicGo遷移", + "mirgrateContent": "即將導入PicGo的配置文件和相冊, 這將覆蓋當前的配置文件和相冊, 是否繼續?", + "mirgrateFailed": "導入失敗", + "mirgrateSuccess": "導入成功, 請重啟PicList生效", + "mirgrateTitle": "通知", + "openConfigFile": "打開配置文件", + "openConfigFileDir": "打開配置文件目錄", + "selectType": "請選擇同步類型", + "syncConfigNote": "同步的文件為配置文件", + "syncConfigProxy": "代理", + "syncConfiguration": "同步配置", + "syncEndpointConfig": "同步方案配置", + "syncResult": { "failed": "同步失敗", "success": "同步成功" }, + "title": "配置/同步", + "upDownloadSettings": "上傳下載配置文件", + "uploadSettings": "上傳配置", + "webdav": { + "authType": "WebDAV 認證類型", + "enableSSL": "啟用 SSL/TLS", + "password": "WebDAV 密碼", + "savePath": "WebDAV 保存路徑", + "username": "WebDAV 用戶名" + }, + "webdavEndpoint": "WebDAV 端點" + }, + "system": { + "autoCloseMainWindow": "打開迷你窗口時關閉主窗口", + "autoCloseMiniWindow": "打開主窗口時關閉迷你窗口", + "autoLaunch": "開機自啟", + "chooseLanguage": "選擇語言", + "customMiniIconPath": "自定義迷你窗口圖標路徑", + "hideDockHint": "不支持同時隱藏 dock 和托盤", + "isCustomMiniIcon": "是否自定義迷你窗口圖標", + "isHideDock": "是否隱藏 Dock 圖標", + "languageAndAppearance": "語言和外觀", + "mainMode": "主窗口", + "mainWindowHeight": "主窗口高度", + "mainWindowSize": "設置主窗口大小(需重啟)", + "mainWindowWidth": "主窗口寬度", + "miniMode": "迷你窗口", + "miniWindowOnTop": "迷你窗口置頂", + "needRestart": "需要重啟生效", + "noTrayMode": "隱藏托盤", + "quietMode": "靜默模式", + "rawPicGoSize": "原 PicGo 窗口大小, 800x450", + "rawPicGoSizeHint": "不推薦使用, 僅用於兼容舊 PicGo 窗口大小", + "setMainWindowSize": "設置主窗口大小(需重啟)", + "setShortCuts": "設置快捷鍵", + "startMode": "啟動模式", + "startupAndShortcuts": "啟動和快捷鍵", + "title": "通用", + "windowBehavior": "窗口行為" + }, + "title": "設定", + "update": { + "applicationUpdates": "應用程序更新", + "checkUpdate": "檢查更新", + "clickToCheck": "點擊檢查", + "currentVersion": "當前版本: {version}", + "daysAgo": "{days} 天前", + "getting": "正在獲取中...", + "hasNewVersion": "PicList 更新啦,請點擊確定重啟觸發更新", + "hoursAgo": "{hours} 小時前", + "justNow": "剛剛", + "lastUpdated": "最後更新", + "latestReleaseNotes": "最新版本說明", + "loadingReleaseNotes": "正在載入版本說明...", + "minutesAgo": "{minutes} 分鐘前", + "networkError": "網絡錯誤,請檢查網絡連接", + "newestVersion": "最新版本", + "noReleaseNotes": "暫無版本說明", + "openUpdateHelper": "打開更新提醒", + "openUpdateHelperDesc": "當有新版本時顯示通知", + "refresh": "刷新", + "releaseNotes": "版本說明", + "releaseNotesDescription": "查看最新的更改和更新內容", + "releaseNotesError": "載入版本說明失敗,請檢查網絡連接。", + "retry": "重試", + "title": "更新" + }, + "upload": { + "advancedRname": "高級重命名", + "advancedRnameFormat": "高級重命名格式", + "autoCopyUrlAfterUpload": "上傳後自動複製URL", + "autoImportInManage": "管理頁面自動導入配置", + "autoImportInManageHint": "啟用後,管理頁面將自動導入對應圖床配置", + "autoImportPicBed": "選擇需要開啟自動導入的圖床", + "availablePlaceholders": "可用占位符", + "c1nToken": "C1N Token", + "cfWorkerHost": "CF Worker 地址", + "chooseShowedPicBed": "請選擇顯示在菜單的圖床", + "clipboardAndNotification": "剪貼板和通知", + "copySuccess": "複製成功: {content}", + "customLinkFormat": "自定義鏈接格式", + "deleteCloud": "相冊內刪除時同步刪除雲端文件", + "deleteLocalFileAfterUpload": "上傳後刪除本地文件", + "enableAdvancedRname": "開啟高級重命名", + "enableSecondPicBed": "啟用第二圖床同步上傳", + "enableSecondPicBedHint": "啟用後,將同步上傳到第二圖床,用於備份", + "enableShortUrl": "使用短鏈接", + "enableUploadNotification": "開啟上傳進度提示", + "enableUploadResultNotification": "開啟上傳結果提示", + "encodeOutputUrl": "輸出(複製) URL 時進行轉義", + "extNamePlaceholder": "用占位符 $extName 來表示文件格式的位置", + "fileNamePlaceholder": "用占位符 $fileName 來表示文件名的位置", + "galleryPicBedFilter": "相簿圖床篩選器", + "galleryPicBedFilterDescription": "選擇在相簿中顯示的圖床類型。如果未選擇任何圖床,將顯示所有圖床。", + "imageProcessing": "圖片預處理設置", + "isAutoListenClipboard": "軟件啟動時自動監聽剪貼板上傳", + "manualRname": "手動重命名", + "placeholder": { + "categoryFile": "文件相關", + "categoryHash": "哈希相關", + "categoryTime": "時間相關", + "date": "日期,2位數", + "filename": "文件原名", + "hour": "小時,2位數", + "localFolder": "本地文件夾層級", + "md5": "MD5 哈希", + "md5-16": "MD5 哈希(前16位)", + "millisecond": "毫秒,3位數", + "minute": "分鐘,2位數", + "month": "月份,2位數", + "randomString": "number位隨機字符串", + "second": "秒,2位數", + "sha256": "SHA256 哈希", + "sha256-n": "SHA256 哈希(前n位)", + "timestamp": "時間戳,13位數", + "uuid": "隨機 UUID", + "year2": "年份,2位數", + "year4": "年份,4位數" + }, + "setSecondPicBed": "設置第二圖床", + "shortUrlServer": "短鏈接服務", + "sinkDomain": "Sink 域名", + "sinkToken": "Sink Token", + "timestampRname": "時間戳重命名", + "title": "上傳", + "uploadBehavior": "上傳行為", + "uploadProcessing": "上傳處理", + "urlFormatAndLinkType": "鏈接格式和類型", + "urlPlaceholder": "用占位符 $url 來表示 URL 的位置", + "useBuiltInClipboardUpload": "使用系統內置剪貼板上傳", + "useBuiltInClipboardUploadHint": "關閉時會使用腳本文件獲取圖片", + "yourlsDomain": "Yourls 域名", + "yourlsSignature": "Yourls 密鑰" + } + }, + "shortKey": { + "bind": "快捷鍵綁定", + "changeUpload": "修改上傳快捷鍵", + "disable": "停用", + "disabled": "已停用", + "edit": "編輯", + "enable": "啟用", + "enabled": "已啟用", + "handle": "操作", + "keyBinding": "按鍵綁定", + "name": "快捷鍵名稱", + "noBinding": "未綁定", + "pressHint": "點擊輸入框並按下你想要綁定的按鍵", + "pressKeys": "按下要設定的快捷鍵", + "source": "來源", + "status": "狀態", + "title": "快捷鍵" + }, + "toolbox": { + "autoFixFail": "自動修復失敗,請自行修復以下問題", + "checkConfigFileBroken": "檢查配置文件是否損壞", + "checkGalleryFileBroken": "檢查相冊文件是否損壞", + "checkProblemWithClipboardPicUpload": "檢查剪貼板圖片上傳是否存在問題", + "checkProblemWithProxy": "檢查代理設置是否正常", + "description": "立即掃描以下項目,修復使用問題", + "fixDoneNeedReload": "修復完成,需要重啟生效,是否重啟", + "notice": "通知", + "openConfigFile": "打開配置文件", + "openFilePath": "打開文件路徑", + "reScan": "重新掃描", + "startFix": "開始修復", + "startScan": "開始掃描", + "success": "恭喜你,沒有檢查出問題", + "title": "排查 PicList 執行時問題" + }, + "tray": { + "copySuccess": "複製成功", + "openMainWindow": "打開主窗口", + "uploaded": "已上傳", + "waitForUpload": "等待上傳" + }, + "upload": { + "changePicBed": "切換圖床", + "clickToUpload": "點擊上傳", + "clipboardPicture": "剪貼板圖片", + "dragFileToHere": "將文件拖到此處,或單擊上傳", + "dragValidPictureOrUrl": "請拖入合法的圖片文件或者圖片URL地址", + "httpPrefixTip": "以http://或https://開頭", + "imageProcessName": "圖片處理", + "inputUrlTip": "請輸入URL地址", + "inputValidUrl": "請輸入合法的URL", + "invalidUrlsFound": "發現無效的URL: {urls}", + "linkFormat": "連結格式", + "multipleUrlsHint": "多個URL請分行輸入", + "outputFormat": "輸出格式", + "quickUpload": "快捷上傳", + "uploadFailed": "上傳失敗", + "uploadHint": "支持所有文件類型,但推薦僅上傳圖片", + "uploadingMultipleUrls": "正在上傳 {count} 個URL...", + "uploadViewHint": "點擊打開圖床設定", + "urlType": { "normal": "長連結", "short": "短連結", "title": "連結類型" }, + "urlUpload": "URL上傳" + }, + "uploaderConfig": { + "addNew": "新增", + "delete": "刪除", + "deleteConfirm": "確認刪除圖床配置嗎?", + "deleteSuccess": "刪除成功", + "deleteTitle": "通知", + "edit": "編輯", + "selected": "已選取", + "setAsDefault": "設為預設圖床", + "setSuccess": "設定成功", + "title": "圖床配置" } - } + }, + "settings": { + "theme": { + "auto": "自動", + "autoDesc": "自動模式", + "dark": "深色", + "darkDesc": "黑暗模式", + "light": "淺色", + "lightDesc": "明亮模式", + "toggle": "切換主題" + } + }, + "titleBar": { "alwaysOnTop": "置頂", "close": "關閉", "minimize": "最小化", "miniWindow": "迷你視窗" } } diff --git a/src/renderer/layouts/Main.vue b/src/renderer/layouts/Main.vue index 9365ed52..781f64f5 100644 --- a/src/renderer/layouts/Main.vue +++ b/src/renderer/layouts/Main.vue @@ -48,10 +48,13 @@ export default { name: 'MainPage' } } :root { - font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; - line-height: 1.5; + font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-weight: 400; + line-height: 1.5; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizelegibility; --color-text-primary: #1d1d1f; --color-text-secondary: #6e6e73; @@ -59,11 +62,11 @@ export default { name: 'MainPage' } --color-background-primary: #ffffff; --color-background-secondary: #f5f5f7; --color-background-tertiary: #fbfbfd; - --color-surface: rgba(255, 255, 255, 0.8); - --color-surface-elevated: rgba(255, 255, 255, 0.95); - --color-border: rgba(0, 0, 0, 0.1); + --color-surface: rgb(255 255 255 / 80%); + --color-surface-elevated: rgb(255 255 255 / 95%); + --color-border: rgb(0 0 0 / 10%); --color-border-darker: #cdd0d6; - --color-border-secondary: rgba(0, 0, 0, 0.05); + --color-border-secondary: rgb(0 0 0 / 5%); --color-primary: #6366f1; --color-primary-hover: #4f46e5; --color-accent: #007aff; @@ -73,26 +76,19 @@ export default { name: 'MainPage' } --color-warning: #f1930f; --color-danger: #ff3b30; --color-error: #ff3b30; - --color-error-surface: rgba(255, 59, 48, 0.1); - - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06); - --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.08), 0 4px 6px rgba(0, 0, 0, 0.05); - --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04); - + --color-error-surface: rgb(255 59 48 / 10%); + --shadow-sm: 0 1px 3px rgb(0 0 0 / 4%), 0 1px 2px rgb(0 0 0 / 6%); + --shadow-md: 0 4px 6px rgb(0 0 0 / 5%), 0 2px 4px rgb(0 0 0 / 6%); + --shadow-lg: 0 10px 15px rgb(0 0 0 / 8%), 0 4px 6px rgb(0 0 0 / 5%); + --shadow-xl: 0 20px 25px rgb(0 0 0 / 10%), 0 10px 10px rgb(0 0 0 / 4%); --radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px; --radius-xl: 16px; --radius-2xl: 20px; - --transition-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1); --transition-medium: 0.25s cubic-bezier(0.4, 0, 0.2, 1); --transition-slow: 0.35s cubic-bezier(0.4, 0, 0.2, 1); - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-rendering: optimizeLegibility; } :root.dark, @@ -103,10 +99,10 @@ export default { name: 'MainPage' } --color-background-primary: #000000; --color-background-secondary: #1c1c1e; --color-background-tertiary: #2c2c2e; - --color-surface: rgba(28, 28, 30, 0.8); - --color-surface-elevated: rgba(44, 44, 46, 0.95); - --color-border: rgba(255, 255, 255, 0.1); - --color-border-secondary: rgba(255, 255, 255, 0.05); + --color-surface: rgb(28 28 30 / 80%); + --color-surface-elevated: rgb(44 44 46 / 95%); + --color-border: rgb(255 255 255 / 10%); + --color-border-secondary: rgb(255 255 255 / 5%); --color-primary: #6366f1; --color-primary-hover: #818cf8; --color-accent: #0a84ff; @@ -137,9 +133,9 @@ export default { name: 'MainPage' } input, select, textarea { - background: var(--color-surface); border-color: var(--color-border); color: var(--color-text-primary); + background: var(--color-surface); } input::placeholder, @@ -148,8 +144,8 @@ export default { name: 'MainPage' } } button { - color: var(--color-text-primary); border-color: var(--color-border); + color: var(--color-text-primary); } button:hover { @@ -158,19 +154,19 @@ export default { name: 'MainPage' } } body { + overflow: hidden; + font-family: inherit; color: var(--color-text-primary); background-color: var(--color-background-primary); - font-family: inherit; - overflow: hidden; } .app-container { position: relative; - height: 100vh; display: flex; overflow: hidden; - background-color: var(--color-background-primary); padding-top: 32px; + height: 100vh; + background-color: var(--color-background-primary); } .app-background { @@ -184,19 +180,19 @@ body { position: absolute; bottom: -40%; left: -20%; + border-radius: 50%; width: 60%; height: 60%; - background: radial-gradient(circle, rgba(199, 131, 233, 0.05) 0%, transparent 70%); - border-radius: 50%; + background: radial-gradient(circle, rgb(199 131 233 / 5%) 0%, transparent 70%); } .main-content { position: relative; z-index: 1; - flex: 1; - height: 100vh; overflow: scroll; + height: 100vh; background-color: var(--color-background-secondary); + flex: 1; scrollbar-width: none; -ms-overflow-style: none; } @@ -206,10 +202,10 @@ body { } .content-container { - height: 100%; + margin: 0; padding: 0.3 rem; max-width: none; - margin: 0; + height: 100%; } ::-webkit-scrollbar { @@ -222,9 +218,9 @@ body { } ::-webkit-scrollbar-thumb { - background-color: var(--color-border); - border-radius: 6px; border: 3px solid var(--color-background-primary); + border-radius: 6px; + background-color: var(--color-border); transition: background-color var(--transition-fast); } @@ -237,8 +233,8 @@ body { } ::selection { - background-color: rgba(0, 122, 255, 0.2); color: var(--color-text-primary); + background-color: rgb(0 122 255 / 20%); } :focus { diff --git a/src/renderer/main.ts b/src/renderer/main.ts index ef919653..0eb42abb 100644 --- a/src/renderer/main.ts +++ b/src/renderer/main.ts @@ -36,15 +36,15 @@ const i18n = createI18n<[MessageSchema], 'en' | 'zh-CN' | 'zh-TW'>({ messages: { en, 'zh-CN': zhCN, - 'zh-TW': zhTW - } + 'zh-TW': zhTW, + }, }) const pinia = createPinia() pinia.use(piniaPluginPersistedstate) app.use(VueLazyLoad, { loading: './loading.jpg', error: './unknown-file-type.svg', - delay: 500 + delay: 500, }) app.use(i18n) app.use(router) diff --git a/src/renderer/manage/components/CustomSwitch.vue b/src/renderer/manage/components/CustomSwitch.vue index 595f797c..b16fbbda 100644 --- a/src/renderer/manage/components/CustomSwitch.vue +++ b/src/renderer/manage/components/CustomSwitch.vue @@ -56,12 +56,12 @@ const toggleTooltip = () => { diff --git a/src/renderer/manage/pages/BucketPage.vue b/src/renderer/manage/pages/BucketPage.vue index 395675d6..8891660b 100644 --- a/src/renderer/manage/pages/BucketPage.vue +++ b/src/renderer/manage/pages/BucketPage.vue @@ -141,7 +141,7 @@