mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-07-12 16:11:27 +08:00
🎨 Style(custom): lint code
This commit is contained in:
@@ -7,9 +7,7 @@ import vue from '@vitejs/plugin-vue'
|
|||||||
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
|
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
main: {
|
main: {
|
||||||
plugins: [
|
plugins: [externalizeDepsPlugin()],
|
||||||
externalizeDepsPlugin()
|
|
||||||
],
|
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': resolve('src/renderer'),
|
'@': resolve('src/renderer'),
|
||||||
@@ -22,10 +20,11 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
preload: {
|
preload: {
|
||||||
plugins: [externalizeDepsPlugin(),
|
plugins: [
|
||||||
|
externalizeDepsPlugin(),
|
||||||
VueI18nPlugin({
|
VueI18nPlugin({
|
||||||
/* options */
|
/* options */
|
||||||
// locale messages resource pre-compile option
|
// 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/**')
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import eslint from '@eslint/js'
|
import eslint from '@eslint/js'
|
||||||
import standard from '@vue/eslint-config-standard'
|
import standard from '@vue/eslint-config-standard'
|
||||||
|
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
|
||||||
import simpleImportSort from 'eslint-plugin-simple-import-sort'
|
import simpleImportSort from 'eslint-plugin-simple-import-sort'
|
||||||
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
|
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
|
||||||
import pluginVue from 'eslint-plugin-vue'
|
import pluginVue from 'eslint-plugin-vue'
|
||||||
@@ -18,6 +19,7 @@ export default tseslint.config(
|
|||||||
...tseslint.configs.stylistic,
|
...tseslint.configs.stylistic,
|
||||||
...pluginVue.configs['flat/recommended'],
|
...pluginVue.configs['flat/recommended'],
|
||||||
...standard,
|
...standard,
|
||||||
|
eslintPluginPrettierRecommended,
|
||||||
{
|
{
|
||||||
plugins: {
|
plugins: {
|
||||||
'simple-import-sort': simpleImportSort,
|
'simple-import-sort': simpleImportSort,
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -25,10 +25,10 @@
|
|||||||
"dev": "electron-vite dev --watch",
|
"dev": "electron-vite dev --watch",
|
||||||
"i18n": "node ./scripts/gen-i18n-types.js",
|
"i18n": "node ./scripts/gen-i18n-types.js",
|
||||||
"link": "node ./scripts/link.js",
|
"link": "node ./scripts/link.js",
|
||||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src/",
|
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src/ scripts/ .",
|
||||||
"lint:dpdm": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/main/index.ts",
|
"lint:dpdm": "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:dpdm:renderer": "dpdm -T --tsconfig ./tsconfig.json --no-tree --no-warning --exit-code circular:1 src/renderer/main.ts",
|
||||||
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/",
|
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue src/ scripts/ .",
|
||||||
"ncu": "node ./scripts/check-dep.js",
|
"ncu": "node ./scripts/check-dep.js",
|
||||||
"postinstall": "electron-builder install-app-deps",
|
"postinstall": "electron-builder install-app-deps",
|
||||||
"postuninstall": "electron-builder install-app-deps",
|
"postuninstall": "electron-builder install-app-deps",
|
||||||
@@ -44,7 +44,6 @@
|
|||||||
"@aws-sdk/client-s3": "^3.864.0",
|
"@aws-sdk/client-s3": "^3.864.0",
|
||||||
"@aws-sdk/lib-storage": "^3.864.0",
|
"@aws-sdk/lib-storage": "^3.864.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.864.0",
|
"@aws-sdk/s3-request-presigner": "^3.864.0",
|
||||||
"@electron-toolkit/preload": "^3.0.2",
|
|
||||||
"@headlessui/vue": "^1.7.23",
|
"@headlessui/vue": "^1.7.23",
|
||||||
"@highlightjs/vue-plugin": "^2.1.2",
|
"@highlightjs/vue-plugin": "^2.1.2",
|
||||||
"@nodelib/fs.walk": "^3.0.1",
|
"@nodelib/fs.walk": "^3.0.1",
|
||||||
@@ -53,11 +52,12 @@
|
|||||||
"@piclist/store": "^3.0.0",
|
"@piclist/store": "^3.0.0",
|
||||||
"@smithy/node-http-handler": "^4.1.1",
|
"@smithy/node-http-handler": "^4.1.1",
|
||||||
"@videojs-player/vue": "^1.0.0",
|
"@videojs-player/vue": "^1.0.0",
|
||||||
"@vueuse/core": "^13.6.0",
|
|
||||||
"ali-oss": "^6.23.0",
|
"ali-oss": "^6.23.0",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
|
"chalk": "^5.5.0",
|
||||||
"compare-versions": "^6.1.1",
|
"compare-versions": "^6.1.1",
|
||||||
"cos-nodejs-sdk-v5": "^2.15.4",
|
"cos-nodejs-sdk-v5": "^2.15.4",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"dexie": "^3.2.4",
|
"dexie": "^3.2.4",
|
||||||
"electron-updater": "^6.6.2",
|
"electron-updater": "^6.6.2",
|
||||||
"fast-xml-parser": "^5.2.5",
|
"fast-xml-parser": "^5.2.5",
|
||||||
@@ -78,13 +78,12 @@
|
|||||||
"piclist": "^2.0.0",
|
"piclist": "^2.0.0",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"pinia-plugin-persistedstate": "^4.5.0",
|
"pinia-plugin-persistedstate": "^4.5.0",
|
||||||
"proxy-agent": "^6.5.0",
|
|
||||||
"qiniu": "7.14.0",
|
"qiniu": "7.14.0",
|
||||||
"qrcode.vue": "^3.6.0",
|
"qrcode.vue": "^3.6.0",
|
||||||
"querystring": "^0.2.1",
|
|
||||||
"semver": "^7.7.2",
|
"semver": "^7.7.2",
|
||||||
"shell-path": "3.0.0",
|
"shell-path": "3.0.0",
|
||||||
"ssh2-no-cpu-features": "^2.0.0",
|
"ssh2-no-cpu-features": "^2.0.0",
|
||||||
|
"tunnel": "^0.0.6",
|
||||||
"upyun": "^3.4.6",
|
"upyun": "^3.4.6",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"video.js": "^8.23.4",
|
"video.js": "^8.23.4",
|
||||||
@@ -112,9 +111,7 @@
|
|||||||
"@types/video.js": "^7.3.58",
|
"@types/video.js": "^7.3.58",
|
||||||
"@types/write-file-atomic": "^4.0.3",
|
"@types/write-file-atomic": "^4.0.3",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vue/eslint-config-prettier": "^10.2.0",
|
|
||||||
"@vue/eslint-config-standard": "^9.0.1",
|
"@vue/eslint-config-standard": "^9.0.1",
|
||||||
"@vue/eslint-config-typescript": "^14.6.0",
|
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"dpdm": "^3.14.0",
|
"dpdm": "^3.14.0",
|
||||||
"electron": "^36.7.4",
|
"electron": "^36.7.4",
|
||||||
@@ -122,10 +119,12 @@
|
|||||||
"electron-devtools-installer": "^4.0.0",
|
"electron-devtools-installer": "^4.0.0",
|
||||||
"electron-vite": "^4.0.0",
|
"electron-vite": "^4.0.0",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.33.0",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"eslint-plugin-unicorn": "^60.0.0",
|
"eslint-plugin-unicorn": "^60.0.0",
|
||||||
"eslint-plugin-vue": "^10.4.0",
|
"eslint-plugin-vue": "^10.4.0",
|
||||||
|
"globals": "^16.3.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"node-bump-version": "^2.0.0",
|
"node-bump-version": "^2.0.0",
|
||||||
"npm-check-updates": "^18.0.2",
|
"npm-check-updates": "^18.0.2",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { run } from 'npm-check-updates'
|
import { run } from 'npm-check-updates'
|
||||||
|
|
||||||
async function getRepositoryInfo (packageName) {
|
async function getRepositoryInfo(packageName) {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(`https://registry.npmjs.org/${packageName}`)
|
const { data } = await axios.get(`https://registry.npmjs.org/${packageName}`)
|
||||||
const repository = data.repository
|
const repository = data.repository
|
||||||
@@ -17,7 +17,7 @@ async function getRepositoryInfo (packageName) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkUpdates () {
|
async function checkUpdates() {
|
||||||
const updated = await run({
|
const updated = await run({
|
||||||
packageFile: './package.json',
|
packageFile: './package.json',
|
||||||
upgrade: false
|
upgrade: false
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import path from 'node:path'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
import pkg from '../package.json' with { type: 'json'}
|
import pkg from '../package.json' with { type: 'json' }
|
||||||
const version = process.argv[2] || pkg.version
|
const version = process.argv[2] || pkg.version
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
@@ -26,7 +26,7 @@ const files = [
|
|||||||
/**
|
/**
|
||||||
* Create progress bar string
|
* Create progress bar string
|
||||||
*/
|
*/
|
||||||
function getProgressBar (current, total, length = 20) {
|
function getProgressBar(current, total, length = 20) {
|
||||||
const progress = Math.round((current / total) * length)
|
const progress = Math.round((current / total) * length)
|
||||||
const percentage = Math.round((current / total) * 100)
|
const percentage = Math.round((current / total) * 100)
|
||||||
const bar = '█'.repeat(progress) + '░'.repeat(length - progress)
|
const bar = '█'.repeat(progress) + '░'.repeat(length - progress)
|
||||||
@@ -36,7 +36,7 @@ function getProgressBar (current, total, length = 20) {
|
|||||||
/**
|
/**
|
||||||
* Format bytes to human-readable format
|
* Format bytes to human-readable format
|
||||||
*/
|
*/
|
||||||
function formatBytes (bytes, decimals = 2) {
|
function formatBytes(bytes, decimals = 2) {
|
||||||
if (bytes === 0) return '0 Bytes'
|
if (bytes === 0) return '0 Bytes'
|
||||||
const k = 1024
|
const k = 1024
|
||||||
const sizes = ['Bytes', 'KB', 'MB', 'GB']
|
const sizes = ['Bytes', 'KB', 'MB', 'GB']
|
||||||
@@ -47,7 +47,7 @@ function formatBytes (bytes, decimals = 2) {
|
|||||||
/**
|
/**
|
||||||
* Download file and calculate SHA256 hash
|
* Download file and calculate SHA256 hash
|
||||||
*/
|
*/
|
||||||
async function downloadAndHash (fileInfo) {
|
async function downloadAndHash(fileInfo) {
|
||||||
const { url, name } = fileInfo
|
const { url, name } = fileInfo
|
||||||
const filePath = path.join(DOWNLOAD_DIR, name)
|
const filePath = path.join(DOWNLOAD_DIR, name)
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ async function downloadAndHash (fileInfo) {
|
|||||||
/**
|
/**
|
||||||
* Main function
|
* Main function
|
||||||
*/
|
*/
|
||||||
async function main () {
|
async function main() {
|
||||||
console.log(`Generating SHA256 hashes for PicList v${version}`)
|
console.log(`Generating SHA256 hashes for PicList v${version}`)
|
||||||
console.log(`Download directory: ${DOWNLOAD_DIR}`)
|
console.log(`Download directory: ${DOWNLOAD_DIR}`)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ require('dotenv').config()
|
|||||||
const { notarize } = require('@electron/notarize')
|
const { notarize } = require('@electron/notarize')
|
||||||
const { ELECTRON_SKIP_NOTARIZATION, XCODE_APP_LOADER_EMAIL, XCODE_APP_LOADER_PASSWORD, XCODE_TEAM_ID } = process.env
|
const { ELECTRON_SKIP_NOTARIZATION, XCODE_APP_LOADER_EMAIL, XCODE_APP_LOADER_PASSWORD, XCODE_TEAM_ID } = process.env
|
||||||
|
|
||||||
async function main (context) {
|
async function main(context) {
|
||||||
const { electronPlatformName, appOutDir } = context
|
const { electronPlatformName, appOutDir } = context
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ class RemoteNoticeHandler {
|
|||||||
private remoteNotice: IRemoteNotice | null = null
|
private remoteNotice: IRemoteNotice | null = null
|
||||||
private remoteNoticeLocalCountStorage: IRemoteNoticeLocalCountStorage | null = null
|
private remoteNoticeLocalCountStorage: IRemoteNoticeLocalCountStorage | null = null
|
||||||
|
|
||||||
async init () {
|
async init() {
|
||||||
this.remoteNotice = await this.getRemoteNoticeInfo()
|
this.remoteNotice = await this.getRemoteNoticeInfo()
|
||||||
this.initLocalCountStorage()
|
this.initLocalCountStorage()
|
||||||
}
|
}
|
||||||
|
|
||||||
private initLocalCountStorage () {
|
private initLocalCountStorage() {
|
||||||
const localCountStorage = {}
|
const localCountStorage = {}
|
||||||
if (!fs.existsSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH)) {
|
if (!fs.existsSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH)) {
|
||||||
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify({}))
|
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify({}))
|
||||||
@@ -44,14 +44,14 @@ class RemoteNoticeHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private saveLocalCountStorage (newData?: IRemoteNoticeLocalCountStorage) {
|
private saveLocalCountStorage(newData?: IRemoteNoticeLocalCountStorage) {
|
||||||
if (newData) {
|
if (newData) {
|
||||||
this.remoteNoticeLocalCountStorage = newData
|
this.remoteNoticeLocalCountStorage = newData
|
||||||
}
|
}
|
||||||
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify(this.remoteNoticeLocalCountStorage))
|
fs.writeFileSync(REMOTE_NOTICE_LOCAL_STORAGE_PATH, JSON.stringify(this.remoteNoticeLocalCountStorage))
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getRemoteNoticeInfo (): Promise<IRemoteNotice | null> {
|
private async getRemoteNoticeInfo(): Promise<IRemoteNotice | null> {
|
||||||
try {
|
try {
|
||||||
const noticeInfo = (await axios({
|
const noticeInfo = (await axios({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -68,7 +68,7 @@ class RemoteNoticeHandler {
|
|||||||
* if the notice is not shown or is always shown, then show the notice
|
* if the notice is not shown or is always shown, then show the notice
|
||||||
* @param action
|
* @param action
|
||||||
*/
|
*/
|
||||||
private checkActionCount (action: IRemoteNoticeAction) {
|
private checkActionCount(action: IRemoteNoticeAction) {
|
||||||
try {
|
try {
|
||||||
if (!this.remoteNoticeLocalCountStorage) {
|
if (!this.remoteNoticeLocalCountStorage) {
|
||||||
return true
|
return true
|
||||||
@@ -102,7 +102,7 @@ class RemoteNoticeHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async doActions (actions: IRemoteNoticeAction[]) {
|
private async doActions(actions: IRemoteNoticeAction[]) {
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (this.checkActionCount(action)) {
|
if (this.checkActionCount(action)) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@@ -117,7 +117,7 @@ class RemoteNoticeHandler {
|
|||||||
body: action.data?.content || '',
|
body: action.data?.content || '',
|
||||||
clickToCopy: !!action.data?.copyToClipboard,
|
clickToCopy: !!action.data?.copyToClipboard,
|
||||||
copyContent: action.data?.copyToClipboard || '',
|
copyContent: action.data?.copyToClipboard || '',
|
||||||
clickFn () {
|
clickFn() {
|
||||||
if (action.data?.url) {
|
if (action.data?.url) {
|
||||||
shell.openExternal(action.data.url)
|
shell.openExternal(action.data.url)
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ class RemoteNoticeHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerHook (hook: string) {
|
triggerHook(hook: string) {
|
||||||
if (!this.remoteNotice || !this.remoteNotice.list) {
|
if (!this.remoteNotice || !this.remoteNotice.list) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,24 +6,30 @@ import shortKeyService from 'apis/app/shortKey/shortKeyService'
|
|||||||
import GuiApi from 'apis/gui'
|
import GuiApi from 'apis/gui'
|
||||||
import { globalShortcut } from 'electron'
|
import { globalShortcut } from 'electron'
|
||||||
|
|
||||||
import type { IKeyCommandType, IPluginShortKeyConfig, IShortKeyConfig, IShortKeyConfigs, IShortKeyHandler } from '#/types/types'
|
import type {
|
||||||
|
IKeyCommandType,
|
||||||
|
IPluginShortKeyConfig,
|
||||||
|
IShortKeyConfig,
|
||||||
|
IShortKeyConfigs,
|
||||||
|
IShortKeyHandler
|
||||||
|
} from '#/types/types'
|
||||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
|
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
|
||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
|
|
||||||
class ShortKeyHandler {
|
class ShortKeyHandler {
|
||||||
private isInModifiedMode: boolean = false
|
private isInModifiedMode: boolean = false
|
||||||
constructor () {
|
constructor() {
|
||||||
bus.on(TOGGLE_SHORTKEY_MODIFIED_MODE, flag => {
|
bus.on(TOGGLE_SHORTKEY_MODIFIED_MODE, flag => {
|
||||||
this.isInModifiedMode = flag
|
this.isInModifiedMode = flag
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async init () {
|
async init() {
|
||||||
this.initBuiltInShortKey()
|
this.initBuiltInShortKey()
|
||||||
await this.initPluginsShortKey()
|
await this.initPluginsShortKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
private initBuiltInShortKey () {
|
private initBuiltInShortKey() {
|
||||||
const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
|
const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
|
||||||
Object.keys(commands)
|
Object.keys(commands)
|
||||||
.filter(item => item.includes('picgo:'))
|
.filter(item => item.includes('picgo:'))
|
||||||
@@ -38,7 +44,7 @@ class ShortKeyHandler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initPluginsShortKey () {
|
private async initPluginsShortKey() {
|
||||||
// get enabled plugin
|
// get enabled plugin
|
||||||
const pluginList = picgo.pluginLoader.getList()
|
const pluginList = picgo.pluginLoader.getList()
|
||||||
for (const item of pluginList) {
|
for (const item of pluginList) {
|
||||||
@@ -68,7 +74,7 @@ class ShortKeyHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerShortKey (
|
private registerShortKey(
|
||||||
config: IShortKeyConfig | IPluginShortKeyConfig,
|
config: IShortKeyConfig | IPluginShortKeyConfig,
|
||||||
command: string,
|
command: string,
|
||||||
handler: IShortKeyHandler,
|
handler: IShortKeyHandler,
|
||||||
@@ -97,7 +103,7 @@ class ShortKeyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enable or disable shortKey
|
// enable or disable shortKey
|
||||||
bindOrUnbindShortKey (item: IShortKeyConfig, from: string): boolean {
|
bindOrUnbindShortKey(item: IShortKeyConfig, from: string): boolean {
|
||||||
const command = `${from}:${item.name}`
|
const command = `${from}:${item.name}`
|
||||||
if (item.enable === false) {
|
if (item.enable === false) {
|
||||||
globalShortcut.unregister(item.key)
|
globalShortcut.unregister(item.key)
|
||||||
@@ -121,7 +127,7 @@ class ShortKeyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update shortKey bindings
|
// update shortKey bindings
|
||||||
updateShortKey (item: IShortKeyConfig, oldKey: string, from: string): boolean {
|
updateShortKey(item: IShortKeyConfig, oldKey: string, from: string): boolean {
|
||||||
const command = `${from}:${item.name}`
|
const command = `${from}:${item.name}`
|
||||||
if (globalShortcut.isRegistered(item.key)) return false
|
if (globalShortcut.isRegistered(item.key)) return false
|
||||||
globalShortcut.unregister(oldKey)
|
globalShortcut.unregister(oldKey)
|
||||||
@@ -134,7 +140,7 @@ class ShortKeyHandler {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handler (command: string) {
|
private async handler(command: string) {
|
||||||
if (this.isInModifiedMode) {
|
if (this.isInModifiedMode) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -150,7 +156,7 @@ class ShortKeyHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerPluginShortKey (pluginName: string) {
|
async registerPluginShortKey(pluginName: string) {
|
||||||
const plugin = await picgo.pluginLoader.getPlugin(pluginName)
|
const plugin = await picgo.pluginLoader.getPlugin(pluginName)
|
||||||
if (plugin && plugin.commands) {
|
if (plugin && plugin.commands) {
|
||||||
if (typeof plugin.commands !== 'function') {
|
if (typeof plugin.commands !== 'function') {
|
||||||
@@ -170,7 +176,7 @@ class ShortKeyHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterPluginShortKey (pluginName: string) {
|
unregisterPluginShortKey(pluginName: string) {
|
||||||
const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
|
const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
|
||||||
const keyList = Object.keys(commands)
|
const keyList = Object.keys(commands)
|
||||||
.filter(command => command.includes(pluginName))
|
.filter(command => command.includes(pluginName))
|
||||||
|
|||||||
@@ -4,22 +4,22 @@ import type { IShortKeyHandler } from '#/types/types'
|
|||||||
|
|
||||||
class ShortKeyService {
|
class ShortKeyService {
|
||||||
private commandList: Map<string, IShortKeyHandler> = new Map()
|
private commandList: Map<string, IShortKeyHandler> = new Map()
|
||||||
registerCommand (command: string, handler: IShortKeyHandler) {
|
registerCommand(command: string, handler: IShortKeyHandler) {
|
||||||
this.commandList.set(command, handler)
|
this.commandList.set(command, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterCommand (command: string) {
|
unregisterCommand(command: string) {
|
||||||
this.commandList.delete(command)
|
this.commandList.delete(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
getShortKeyHandler (command: string): IShortKeyHandler | null {
|
getShortKeyHandler(command: string): IShortKeyHandler | null {
|
||||||
const handler = this.commandList.get(command)
|
const handler = this.commandList.get(command)
|
||||||
if (handler) return handler
|
if (handler) return handler
|
||||||
logger.warn(`cannot find command: ${command}`)
|
logger.warn(`cannot find command: ${command}`)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
getCommandList () {
|
getCommandList() {
|
||||||
return [...this.commandList.keys()]
|
return [...this.commandList.keys()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import uploadPng from '../../../../../resources/upload.png?asset&asarUnpack'
|
|||||||
import uploadDarkPng from '../../../../../resources/upload-dark.png?asset&asarUnpack'
|
import uploadDarkPng from '../../../../../resources/upload-dark.png?asset&asarUnpack'
|
||||||
let contextMenu: Menu | null
|
let contextMenu: Menu | null
|
||||||
|
|
||||||
export function setDockMenu () {
|
export function setDockMenu() {
|
||||||
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
|
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
|
||||||
const dockMenu = Menu.buildFromTemplate([
|
const dockMenu = Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
@@ -45,7 +45,7 @@ export function setDockMenu () {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('START_WATCH_CLIPBOARD'),
|
label: $t('START_WATCH_CLIPBOARD'),
|
||||||
click () {
|
click() {
|
||||||
db.set(configPaths.settings.isListeningClipboard, true)
|
db.set(configPaths.settings.isListeningClipboard, true)
|
||||||
clipboardPoll.startListening()
|
clipboardPoll.startListening()
|
||||||
clipboardPoll.on('change', () => {
|
clipboardPoll.on('change', () => {
|
||||||
@@ -58,7 +58,7 @@ export function setDockMenu () {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('STOP_WATCH_CLIPBOARD'),
|
label: $t('STOP_WATCH_CLIPBOARD'),
|
||||||
click () {
|
click() {
|
||||||
db.set(configPaths.settings.isListeningClipboard, false)
|
db.set(configPaths.settings.isListeningClipboard, false)
|
||||||
clipboardPoll.stopListening()
|
clipboardPoll.stopListening()
|
||||||
clipboardPoll.removeAllListeners()
|
clipboardPoll.removeAllListeners()
|
||||||
@@ -70,7 +70,7 @@ export function setDockMenu () {
|
|||||||
app.dock?.setMenu(dockMenu)
|
app.dock?.setMenu(dockMenu)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createMenu () {
|
export function createMenu() {
|
||||||
const submenu = buildPicBedListMenu()
|
const submenu = buildPicBedListMenu()
|
||||||
const appMenu = Menu.buildFromTemplate([
|
const appMenu = Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
@@ -79,7 +79,7 @@ export function createMenu () {
|
|||||||
{ label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow },
|
{ label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow },
|
||||||
{
|
{
|
||||||
label: $t('RELOAD_APP'),
|
label: $t('RELOAD_APP'),
|
||||||
click () {
|
click() {
|
||||||
app.relaunch()
|
app.relaunch()
|
||||||
app.exit(0)
|
app.exit(0)
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ export function createMenu () {
|
|||||||
Menu.setApplicationMenu(appMenu)
|
Menu.setApplicationMenu(appMenu)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createContextMenu () {
|
export function createContextMenu() {
|
||||||
const ClipboardWatcher = clipboardPoll
|
const ClipboardWatcher = clipboardPoll
|
||||||
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
|
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
|
||||||
const isMiniWindowVisible =
|
const isMiniWindowVisible =
|
||||||
@@ -147,7 +147,7 @@ export function createContextMenu () {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('RELOAD_APP'),
|
label: $t('RELOAD_APP'),
|
||||||
click () {
|
click() {
|
||||||
app.relaunch()
|
app.relaunch()
|
||||||
app.exit(0)
|
app.exit(0)
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ export function createContextMenu () {
|
|||||||
0,
|
0,
|
||||||
{
|
{
|
||||||
label: $t('OPEN_MINI_WINDOW'),
|
label: $t('OPEN_MINI_WINDOW'),
|
||||||
click () {
|
click() {
|
||||||
openMiniWindow(false)
|
openMiniWindow(false)
|
||||||
},
|
},
|
||||||
visible: !isMiniWindowVisible
|
visible: !isMiniWindowVisible
|
||||||
@@ -185,7 +185,7 @@ export function createContextMenu () {
|
|||||||
{ label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow },
|
{ label: $t('OPEN_MAIN_WINDOW'), click: openMainWindow },
|
||||||
{
|
{
|
||||||
label: $t('OPEN_MINI_WINDOW'),
|
label: $t('OPEN_MINI_WINDOW'),
|
||||||
click () {
|
click() {
|
||||||
openMiniWindow(false)
|
openMiniWindow(false)
|
||||||
},
|
},
|
||||||
visible: !isMiniWindowVisible
|
visible: !isMiniWindowVisible
|
||||||
@@ -207,7 +207,7 @@ export function createContextMenu () {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('ABOUT'),
|
label: $t('ABOUT'),
|
||||||
click () {
|
click() {
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
title: 'PicList',
|
title: 'PicList',
|
||||||
message: 'PicList',
|
message: 'PicList',
|
||||||
@@ -230,7 +230,7 @@ const getTrayIcon = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTray (tooltip: string) {
|
export function createTray(tooltip: string) {
|
||||||
const menubarPic = getTrayIcon()
|
const menubarPic = getTrayIcon()
|
||||||
setTray(new Tray(menubarPic))
|
setTray(new Tray(menubarPic))
|
||||||
tray.setToolTip(tooltip)
|
tray.setToolTip(tooltip)
|
||||||
@@ -309,7 +309,7 @@ export function createTray (tooltip: string) {
|
|||||||
// drop-files only be supported in macOS
|
// drop-files only be supported in macOS
|
||||||
// so the tray window must be available
|
// so the tray window must be available
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
(tray as any).on('drop-files', async (_: Event, files: string[]) => {
|
;(tray as any).on('drop-files', async (_: Event, files: string[]) => {
|
||||||
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
|
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
|
||||||
const rawInput = cloneDeep(files)
|
const rawInput = cloneDeep(files)
|
||||||
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||||
@@ -338,14 +338,14 @@ export function createTray (tooltip: string) {
|
|||||||
imgs[i].shortUrl = shortUrl
|
imgs[i].shortUrl = shortUrl
|
||||||
pasteText.push(pasteTextItem)
|
pasteText.push(pasteTextItem)
|
||||||
const isShowResultNotification =
|
const isShowResultNotification =
|
||||||
db.get(configPaths.settings.uploadResultNotification) === undefined
|
db.get(configPaths.settings.uploadResultNotification) === undefined
|
||||||
? true
|
? true
|
||||||
: !!db.get(configPaths.settings.uploadResultNotification)
|
: !!db.get(configPaths.settings.uploadResultNotification)
|
||||||
if (isShowResultNotification) {
|
if (isShowResultNotification) {
|
||||||
const notification = new Notification({
|
const notification = new Notification({
|
||||||
title: $t('UPLOAD_SUCCEED'),
|
title: $t('UPLOAD_SUCCEED'),
|
||||||
body: shortUrl || imgs[i].imgUrl!
|
body: shortUrl || imgs[i].imgUrl!
|
||||||
// icon: files[i]
|
// icon: files[i]
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
notification.show()
|
notification.show()
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ const waitForRename = (window: BrowserWindow, id: number): Promise<string | null
|
|||||||
class Uploader {
|
class Uploader {
|
||||||
private webContents: WebContents | null = null
|
private webContents: WebContents | null = null
|
||||||
|
|
||||||
constructor () {
|
constructor() {
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
init () {
|
init() {
|
||||||
picgo.on(ICOREBuildInEvent.NOTIFICATION, (message: any) => {
|
picgo.on(ICOREBuildInEvent.NOTIFICATION, (message: any) => {
|
||||||
new Notification(message).show()
|
new Notification(message).show()
|
||||||
})
|
})
|
||||||
@@ -92,12 +92,12 @@ class Uploader {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setWebContents (webContents: WebContents) {
|
setWebContents(webContents: WebContents) {
|
||||||
this.webContents = webContents
|
this.webContents = webContents
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getClipboardImagePath (): Promise<string | false> {
|
private async getClipboardImagePath(): Promise<string | false> {
|
||||||
const imgPath = getClipboardFilePath()
|
const imgPath = getClipboardFilePath()
|
||||||
if (imgPath) return imgPath
|
if (imgPath) return imgPath
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class Uploader {
|
|||||||
/**
|
/**
|
||||||
* use electron's clipboard image to upload
|
* use electron's clipboard image to upload
|
||||||
*/
|
*/
|
||||||
async uploadWithBuildInClipboard (): Promise<ImgInfo[] | false> {
|
async uploadWithBuildInClipboard(): Promise<ImgInfo[] | false> {
|
||||||
let imgPath: string | false = false
|
let imgPath: string | false = false
|
||||||
try {
|
try {
|
||||||
imgPath = await this.getClipboardImagePath()
|
imgPath = await this.getClipboardImagePath()
|
||||||
@@ -131,7 +131,7 @@ class Uploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadWithBuildInClipboardReturnCtx (img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
|
async uploadWithBuildInClipboardReturnCtx(img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
|
||||||
let imgPath: string | false = false
|
let imgPath: string | false = false
|
||||||
try {
|
try {
|
||||||
imgPath = await this.getClipboardImagePath()
|
imgPath = await this.getClipboardImagePath()
|
||||||
@@ -147,7 +147,7 @@ class Uploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadReturnCtx (img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
|
async uploadReturnCtx(img?: IUploadOption, skipProcess = false): Promise<IPicGo | false> {
|
||||||
try {
|
try {
|
||||||
const ctx = await picgo.uploadReturnCtx(img, skipProcess)
|
const ctx = await picgo.uploadReturnCtx(img, skipProcess)
|
||||||
if (!Array.isArray(ctx.output) || !ctx.output.some((item: ImgInfo) => item.imgUrl)) return false
|
if (!Array.isArray(ctx.output) || !ctx.output.some((item: ImgInfo) => item.imgUrl)) return false
|
||||||
@@ -172,7 +172,7 @@ class Uploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async upload (img?: IUploadOption): Promise<ImgInfo[] | false> {
|
async upload(img?: IUploadOption): Promise<ImgInfo[] | false> {
|
||||||
try {
|
try {
|
||||||
const output = await picgo.upload(img)
|
const output = await picgo.upload(img)
|
||||||
if (!Array.isArray(output) || !output.some((item: ImgInfo) => item.imgUrl)) return false
|
if (!Array.isArray(output) || !output.some((item: ImgInfo) => item.imgUrl)) return false
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const getDefaultWindowSizes = (): { width: number; height: number } => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMiniWindowShape (win: BrowserWindow) {
|
function setMiniWindowShape(win: BrowserWindow) {
|
||||||
const radius = 32
|
const radius = 32
|
||||||
const shape: Rectangle[] = []
|
const shape: Rectangle[] = []
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ windowList.set(IWindowList.TRAY_WINDOW, {
|
|||||||
isValid: process.platform !== 'linux',
|
isValid: process.platform !== 'linux',
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => trayWindowOptions,
|
options: () => trayWindowOptions,
|
||||||
callback (window) {
|
callback(window) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(process.env.ELECTRON_RENDERER_URL)
|
window.loadURL(process.env.ELECTRON_RENDERER_URL)
|
||||||
} else {
|
} else {
|
||||||
@@ -193,7 +193,7 @@ windowList.set(IWindowList.SETTING_WINDOW, {
|
|||||||
isValid: true,
|
isValid: true,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => settingWindowOptions,
|
options: () => settingWindowOptions,
|
||||||
callback (window, windowManager) {
|
callback(window, windowManager) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`)
|
||||||
} else {
|
} else {
|
||||||
@@ -218,7 +218,7 @@ windowList.set(IWindowList.MINI_WINDOW, {
|
|||||||
isValid: process.platform !== 'darwin',
|
isValid: process.platform !== 'darwin',
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => miniWindowOptions,
|
options: () => miniWindowOptions,
|
||||||
callback (window) {
|
callback(window) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`)
|
||||||
} else {
|
} else {
|
||||||
@@ -234,7 +234,7 @@ windowList.set(IWindowList.RENAME_WINDOW, {
|
|||||||
isValid: true,
|
isValid: true,
|
||||||
multiple: true,
|
multiple: true,
|
||||||
options: () => renameWindowOptions,
|
options: () => renameWindowOptions,
|
||||||
async callback (window, windowManager) {
|
async callback(window, windowManager) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`)
|
||||||
} else {
|
} else {
|
||||||
@@ -256,7 +256,7 @@ windowList.set(IWindowList.TOOLBOX_WINDOW, {
|
|||||||
isValid: true,
|
isValid: true,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => toolboxWindowOptions,
|
options: () => toolboxWindowOptions,
|
||||||
async callback (window, windowManager) {
|
async callback(window, windowManager) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import type { IWindowListItem, IWindowManager } from '#/types/electron'
|
|||||||
import { IWindowList } from '~/utils/enum'
|
import { IWindowList } from '~/utils/enum'
|
||||||
|
|
||||||
class WindowManager implements IWindowManager {
|
class WindowManager implements IWindowManager {
|
||||||
#windowMap: Map< string, BrowserWindow> = new Map()
|
#windowMap: Map<string, BrowserWindow> = new Map()
|
||||||
#windowIdMap: Map<number, string> = new Map()
|
#windowIdMap: Map<number, string> = new Map()
|
||||||
|
|
||||||
create (name: string) {
|
create(name: string) {
|
||||||
const windowConfig: IWindowListItem = windowList.get(name)!
|
const windowConfig: IWindowListItem = windowList.get(name)!
|
||||||
if (!windowConfig.isValid) return null
|
if (!windowConfig.isValid) return null
|
||||||
|
|
||||||
@@ -30,14 +30,14 @@ class WindowManager implements IWindowManager {
|
|||||||
return window
|
return window
|
||||||
}
|
}
|
||||||
|
|
||||||
get (name: string) {
|
get(name: string) {
|
||||||
if (this.has(name)) {
|
if (this.has(name)) {
|
||||||
return this.#windowMap.get(name)!
|
return this.#windowMap.get(name)!
|
||||||
}
|
}
|
||||||
return this.create(name)
|
return this.create(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
has (name: string) {
|
has(name: string) {
|
||||||
return this.#windowMap.has(name)
|
return this.#windowMap.has(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ class WindowManager implements IWindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getAvailableWindow (isSkipMiniWindow = false) {
|
getAvailableWindow(isSkipMiniWindow = false) {
|
||||||
const miniWindow = this.#windowMap.get(IWindowList.MINI_WINDOW)
|
const miniWindow = this.#windowMap.get(IWindowList.MINI_WINDOW)
|
||||||
if (miniWindow && miniWindow.isVisible() && !isSkipMiniWindow) {
|
if (miniWindow && miniWindow.isVisible() && !isSkipMiniWindow) {
|
||||||
return miniWindow
|
return miniWindow
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { EventEmitter } from 'node:events'
|
import { EventEmitter } from 'node:events'
|
||||||
|
|
||||||
class OptimizedBus extends EventEmitter {
|
class OptimizedBus extends EventEmitter {
|
||||||
constructor () {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.setMaxListeners(50)
|
this.setMaxListeners(50)
|
||||||
}
|
}
|
||||||
|
|
||||||
once (event: string | symbol, listener: (...args: any[]) => void): this {
|
once(event: string | symbol, listener: (...args: any[]) => void): this {
|
||||||
const wrappedListener = (...args: any[]) => {
|
const wrappedListener = (...args: any[]) => {
|
||||||
try {
|
try {
|
||||||
listener(...args)
|
listener(...args)
|
||||||
@@ -17,7 +17,7 @@ class OptimizedBus extends EventEmitter {
|
|||||||
return super.once(event, wrappedListener)
|
return super.once(event, wrappedListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupListeners () {
|
cleanupListeners() {
|
||||||
const events = this.eventNames()
|
const events = this.eventNames()
|
||||||
events.forEach(event => {
|
events.forEach(event => {
|
||||||
const listenerCount = this.listenerCount(event)
|
const listenerCount = this.listenerCount(event)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const errorMsg = {
|
|||||||
brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP')
|
brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP')
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbChecker () {
|
function dbChecker() {
|
||||||
if (process.type !== 'renderer') {
|
if (process.type !== 'renderer') {
|
||||||
// db save bak
|
// db save bak
|
||||||
try {
|
try {
|
||||||
@@ -80,7 +80,7 @@ function dbChecker () {
|
|||||||
/**
|
/**
|
||||||
* Get config path
|
* Get config path
|
||||||
*/
|
*/
|
||||||
function dbPathChecker (): string {
|
function dbPathChecker(): string {
|
||||||
if (_configFilePath) {
|
if (_configFilePath) {
|
||||||
return _configFilePath
|
return _configFilePath
|
||||||
}
|
}
|
||||||
@@ -120,11 +120,11 @@ function dbPathChecker (): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbPathDir () {
|
function dbPathDir() {
|
||||||
return path.dirname(dbPathChecker())
|
return path.dirname(dbPathChecker())
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGalleryDBPath (): {
|
function getGalleryDBPath(): {
|
||||||
dbPath: string
|
dbPath: string
|
||||||
dbBackupPath: string
|
dbBackupPath: string
|
||||||
} {
|
} {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const DB_PATH: string = getGalleryDBPath().dbPath
|
|||||||
class ConfigStore {
|
class ConfigStore {
|
||||||
#db: JSONStore
|
#db: JSONStore
|
||||||
|
|
||||||
constructor () {
|
constructor() {
|
||||||
this.#db = new JSONStore(CONFIG_PATH)
|
this.#db = new JSONStore(CONFIG_PATH)
|
||||||
|
|
||||||
if (!this.#db.has('picBed')) {
|
if (!this.#db.has('picBed')) {
|
||||||
@@ -43,11 +43,11 @@ class ConfigStore {
|
|||||||
this.read()
|
this.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
read (flush?: boolean): IJSON {
|
read(flush?: boolean): IJSON {
|
||||||
return this.#db.read(flush)
|
return this.#db.read(flush)
|
||||||
}
|
}
|
||||||
|
|
||||||
getSingle (key = ''): any {
|
getSingle(key = ''): any {
|
||||||
if (key === '') {
|
if (key === '') {
|
||||||
return this.#db.read(true)
|
return this.#db.read(true)
|
||||||
}
|
}
|
||||||
@@ -55,43 +55,43 @@ class ConfigStore {
|
|||||||
return this.#db.get(key)
|
return this.#db.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
get (key: string): any
|
get(key: string): any
|
||||||
get (key: string[]): any[]
|
get(key: string[]): any[]
|
||||||
get (key: string | string[] = ''): any {
|
get(key: string | string[] = ''): any {
|
||||||
if (Array.isArray(key)) {
|
if (Array.isArray(key)) {
|
||||||
return key.map(k => this.getSingle(k))
|
return key.map(k => this.getSingle(k))
|
||||||
}
|
}
|
||||||
return this.getSingle(key)
|
return this.getSingle(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
set (key: string, value: any): void {
|
set(key: string, value: any): void {
|
||||||
this.read(true)
|
this.read(true)
|
||||||
return this.#db.set(key, value)
|
return this.#db.set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
has (key: string) {
|
has(key: string) {
|
||||||
this.read(true)
|
this.read(true)
|
||||||
return this.#db.has(key)
|
return this.#db.has(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
unset (key: string, value: any): boolean {
|
unset(key: string, value: any): boolean {
|
||||||
this.read(true)
|
this.read(true)
|
||||||
return this.#db.unset(key, value)
|
return this.#db.unset(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
saveConfig (config: Partial<IConfig>): void {
|
saveConfig(config: Partial<IConfig>): void {
|
||||||
Object.keys(config).forEach((name: string) => {
|
Object.keys(config).forEach((name: string) => {
|
||||||
this.set(name, config[name])
|
this.set(name, config[name])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
removeConfig (config: IConfig): void {
|
removeConfig(config: IConfig): void {
|
||||||
Object.keys(config).forEach((name: string) => {
|
Object.keys(config).forEach((name: string) => {
|
||||||
this.unset(name, config[name])
|
this.unset(name, config[name])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfigPath () {
|
getConfigPath() {
|
||||||
return CONFIG_PATH
|
return CONFIG_PATH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,11 +103,11 @@ export default db
|
|||||||
// v2.3.0 add gallery db
|
// v2.3.0 add gallery db
|
||||||
class GalleryDB {
|
class GalleryDB {
|
||||||
static #instance: DBStore
|
static #instance: DBStore
|
||||||
private constructor () {
|
private constructor() {
|
||||||
console.log('init gallery db')
|
console.log('init gallery db')
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInstance (): DBStore {
|
static getInstance(): DBStore {
|
||||||
if (!GalleryDB.#instance) {
|
if (!GalleryDB.#instance) {
|
||||||
GalleryDB.#instance = new DBStore(DB_PATH, 'gallery')
|
GalleryDB.#instance = new DBStore(DB_PATH, 'gallery')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ picgo.GUI_VERSION = pkg.version
|
|||||||
|
|
||||||
const originPicGoSaveConfig = picgo.saveConfig.bind(picgo)
|
const originPicGoSaveConfig = picgo.saveConfig.bind(picgo)
|
||||||
|
|
||||||
function flushDB () {
|
function flushDB() {
|
||||||
db.read(true)
|
db.read(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ interface IConfigMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class AlistApi {
|
export default class AlistApi {
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const { fileName, config } = configMap
|
const { fileName, config } = configMap
|
||||||
try {
|
try {
|
||||||
const { version, url, uploadPath, token } = config
|
const { version, url, uploadPath, token } = config
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const getAListToken = async (url: string, username: string, password: string) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class AListplistApi {
|
export default class AListplistApi {
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const { fileName, config } = configMap
|
const { fileName, config } = configMap
|
||||||
try {
|
try {
|
||||||
const { url, username, password, uploadPath } = config
|
const { url, username, password, uploadPath } = config
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ interface IConfigMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class AliyunApi {
|
export default class AliyunApi {
|
||||||
static #getKey (fileName: string, path?: string): string {
|
static #getKey(fileName: string, path?: string): string {
|
||||||
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${fileName}` : fileName
|
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${fileName}` : fileName
|
||||||
}
|
}
|
||||||
|
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const { fileName, config } = configMap
|
const { fileName, config } = configMap
|
||||||
try {
|
try {
|
||||||
const client = new OSS({ ...config, region: config.area })
|
const client = new OSS({ ...config, region: config.area })
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const apiMap: IStringKeyMap = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class ALLApi {
|
export default class ALLApi {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const api = apiMap[configMap.type]
|
const api = apiMap[configMap.type]
|
||||||
return api ? await api.delete(configMap) : false
|
return api ? await api.delete(configMap) : false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { removeFileFromS3InMain } from '~/utils/deleteFunc'
|
|||||||
import { deleteFailedLog } from '~/utils/deleteLog'
|
import { deleteFailedLog } from '~/utils/deleteLog'
|
||||||
|
|
||||||
export default class AwsS3Api {
|
export default class AwsS3Api {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
return await removeFileFromS3InMain(getRawData(configMap))
|
return await removeFileFromS3InMain(getRawData(configMap))
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { removeFileFromDogeInMain } from '~/utils/deleteFunc'
|
|||||||
import { deleteFailedLog } from '~/utils/deleteLog'
|
import { deleteFailedLog } from '~/utils/deleteLog'
|
||||||
|
|
||||||
export default class AwsS3Api {
|
export default class AwsS3Api {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
return await removeFileFromDogeInMain(getRawData(configMap))
|
return await removeFileFromDogeInMain(getRawData(configMap))
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@@ -10,18 +10,18 @@ interface IConfigMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class GithubApi {
|
export default class GithubApi {
|
||||||
static #createOctokit (token: string) {
|
static #createOctokit(token: string) {
|
||||||
return new Octokit({
|
return new Octokit({
|
||||||
auth: token
|
auth: token
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static #createKey (path: string | undefined, fileName: string): string {
|
static #createKey(path: string | undefined, fileName: string): string {
|
||||||
const formatedFileName = fileName.replace(/%2F/g, '/')
|
const formatedFileName = fileName.replace(/%2F/g, '/')
|
||||||
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${formatedFileName}` : formatedFileName
|
return path && path !== '/' ? `${path.replace(/^\/+|\/+$/, '')}/${formatedFileName}` : formatedFileName
|
||||||
}
|
}
|
||||||
|
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const {
|
const {
|
||||||
fileName,
|
fileName,
|
||||||
hash,
|
hash,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { removeFileFromHuaweiInMain } from '~/utils/deleteFunc'
|
|||||||
import { deleteFailedLog } from '~/utils/deleteLog'
|
import { deleteFailedLog } from '~/utils/deleteLog'
|
||||||
|
|
||||||
export default class HuaweicloudApi {
|
export default class HuaweicloudApi {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
return await removeFileFromHuaweiInMain(getRawData(configMap))
|
return await removeFileFromHuaweiInMain(getRawData(configMap))
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ interface IConfigMap {
|
|||||||
export default class ImgurApi {
|
export default class ImgurApi {
|
||||||
static #baseUrl = 'https://api.imgur.com/3'
|
static #baseUrl = 'https://api.imgur.com/3'
|
||||||
|
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const { config: { clientId = '', username = '', accessToken = '' } = {}, hash = '' } = configMap
|
const { config: { clientId = '', username = '', accessToken = '' } = {}, hash = '' } = configMap
|
||||||
let Authorization: string, apiUrl: string
|
let Authorization: string, apiUrl: string
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ interface IConfigMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class LocalApi {
|
export default class LocalApi {
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const { hash } = configMap
|
const { hash } = configMap
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
deleteLog(hash, 'Local', false, 'Local.delete: invalid params')
|
deleteLog(hash, 'Local', false, 'Local.delete: invalid params')
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { IStringKeyMap } from '#/types/types'
|
|||||||
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
|
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
|
||||||
|
|
||||||
export default class LskyplistApi {
|
export default class LskyplistApi {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { hash, config } = configMap
|
const { hash, config } = configMap
|
||||||
if (!hash || !config || !config.token) {
|
if (!hash || !config || !config.token) {
|
||||||
deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid params')
|
deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid params')
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { IStringKeyMap } from '#/types/types'
|
|||||||
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
|
import { deleteFailedLog, deleteLog } from '~/utils/deleteLog'
|
||||||
|
|
||||||
export default class PiclistApi {
|
export default class PiclistApi {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { config, fullResult } = configMap
|
const { config, fullResult } = configMap
|
||||||
const { host, port } = config
|
const { host, port } = config
|
||||||
if (!fullResult) return true
|
if (!fullResult) return true
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ interface IConfigMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class QiniuApi {
|
export default class QiniuApi {
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const {
|
const {
|
||||||
fileName,
|
fileName,
|
||||||
config: { accessKey, secretKey, bucket, path }
|
config: { accessKey, secretKey, bucket, path }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { removeFileFromSFTPInMain } from '~/utils/deleteFunc'
|
|||||||
import { deleteFailedLog } from '~/utils/deleteLog'
|
import { deleteFailedLog } from '~/utils/deleteLog'
|
||||||
|
|
||||||
export default class SftpPlistApi {
|
export default class SftpPlistApi {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileName, config } = configMap
|
const { fileName, config } = configMap
|
||||||
try {
|
try {
|
||||||
return await removeFileFromSFTPInMain(getRawData(config), fileName)
|
return await removeFileFromSFTPInMain(getRawData(config), fileName)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ interface IConfigMap {
|
|||||||
export default class SmmsApi {
|
export default class SmmsApi {
|
||||||
static readonly #baseUrl = 'https://smms.app/api/v2'
|
static readonly #baseUrl = 'https://smms.app/api/v2'
|
||||||
|
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const { hash, config } = configMap
|
const { hash, config } = configMap
|
||||||
if (!hash || !config || !config.token) {
|
if (!hash || !config || !config.token) {
|
||||||
deleteLog(hash, 'Smms', false, 'SmmsApi.delete: invalid params')
|
deleteLog(hash, 'Smms', false, 'SmmsApi.delete: invalid params')
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ interface IConfigMap {
|
|||||||
config: PartialKeys<ITcYunConfig, 'path'>
|
config: PartialKeys<ITcYunConfig, 'path'>
|
||||||
}
|
}
|
||||||
export default class TcyunApi {
|
export default class TcyunApi {
|
||||||
static #createCOS (SecretId: string, SecretKey: string): COS {
|
static #createCOS(SecretId: string, SecretKey: string): COS {
|
||||||
return new COS({
|
return new COS({
|
||||||
SecretId,
|
SecretId,
|
||||||
SecretKey
|
SecretKey
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const {
|
const {
|
||||||
fileName,
|
fileName,
|
||||||
config: { secretId, secretKey, bucket, area, path }
|
config: { secretId, secretKey, bucket, area, path }
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface IConfigMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class UpyunApi {
|
export default class UpyunApi {
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const {
|
const {
|
||||||
fileName,
|
fileName,
|
||||||
config: { bucket, operator, password, path }
|
config: { bucket, operator, password, path }
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface IConfigMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class WebdavApi {
|
export default class WebdavApi {
|
||||||
static async delete (configMap: IConfigMap): Promise<boolean> {
|
static async delete(configMap: IConfigMap): Promise<boolean> {
|
||||||
const {
|
const {
|
||||||
fileName,
|
fileName,
|
||||||
config: { host, username, password, path, sslEnabled, authType }
|
config: { host, username, password, path, sslEnabled, authType }
|
||||||
|
|||||||
@@ -8,7 +8,16 @@ import { BrowserWindow, dialog, ipcMain, IpcMainEvent, MessageBoxOptions, Notifi
|
|||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
import type { IGuiApi, ImgInfo, IShowFileExplorerOption, IShowInputBoxOption, IShowMessageBoxOption, IShowMessageBoxResult, IShowNotificationOption, IUploadOption } from '#/types/types'
|
import type {
|
||||||
|
IGuiApi,
|
||||||
|
ImgInfo,
|
||||||
|
IShowFileExplorerOption,
|
||||||
|
IShowInputBoxOption,
|
||||||
|
IShowMessageBoxOption,
|
||||||
|
IShowMessageBoxResult,
|
||||||
|
IShowNotificationOption,
|
||||||
|
IUploadOption
|
||||||
|
} from '#/types/types'
|
||||||
import { SHOW_INPUT_BOX } from '~/events/constant'
|
import { SHOW_INPUT_BOX } from '~/events/constant'
|
||||||
import { T as $t } from '~/i18n'
|
import { T as $t } from '~/i18n'
|
||||||
import { handleCopyUrl } from '~/utils/common'
|
import { handleCopyUrl } from '~/utils/common'
|
||||||
@@ -21,18 +30,18 @@ class GuiApi implements IGuiApi {
|
|||||||
private static instance: GuiApi
|
private static instance: GuiApi
|
||||||
private windowId: number = -1
|
private windowId: number = -1
|
||||||
private settingWindowId: number = -1
|
private settingWindowId: number = -1
|
||||||
private constructor () {
|
private constructor() {
|
||||||
console.log('init guiapi')
|
console.log('init guiapi')
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInstance (): GuiApi {
|
static getInstance(): GuiApi {
|
||||||
if (!GuiApi.instance) {
|
if (!GuiApi.instance) {
|
||||||
GuiApi.instance = new GuiApi()
|
GuiApi.instance = new GuiApi()
|
||||||
}
|
}
|
||||||
return GuiApi.instance
|
return GuiApi.instance
|
||||||
}
|
}
|
||||||
|
|
||||||
private async showSettingWindow () {
|
private async showSettingWindow() {
|
||||||
this.settingWindowId = await getSettingWindowId()
|
this.settingWindowId = await getSettingWindowId()
|
||||||
const settingWindow = BrowserWindow.fromId(this.settingWindowId)
|
const settingWindow = BrowserWindow.fromId(this.settingWindowId)
|
||||||
if (settingWindow?.isVisible()) {
|
if (settingWindow?.isVisible()) {
|
||||||
@@ -46,11 +55,11 @@ class GuiApi implements IGuiApi {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private getWebcontentsByWindowId (id: number) {
|
private getWebcontentsByWindowId(id: number) {
|
||||||
return BrowserWindow.fromId(id)?.webContents
|
return BrowserWindow.fromId(id)?.webContents
|
||||||
}
|
}
|
||||||
|
|
||||||
async showInputBox (
|
async showInputBox(
|
||||||
options: IShowInputBoxOption = {
|
options: IShowInputBoxOption = {
|
||||||
title: '',
|
title: '',
|
||||||
placeholder: ''
|
placeholder: ''
|
||||||
@@ -65,13 +74,13 @@ class GuiApi implements IGuiApi {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async showFileExplorer (options: IShowFileExplorerOption = {}) {
|
async showFileExplorer(options: IShowFileExplorerOption = {}) {
|
||||||
this.windowId = await getWindowId()
|
this.windowId = await getWindowId()
|
||||||
const res = await dialog.showOpenDialog(BrowserWindow.fromId(this.windowId)!, options)
|
const res = await dialog.showOpenDialog(BrowserWindow.fromId(this.windowId)!, options)
|
||||||
return res.filePaths || []
|
return res.filePaths || []
|
||||||
}
|
}
|
||||||
|
|
||||||
async upload (input: IUploadOption) {
|
async upload(input: IUploadOption) {
|
||||||
this.windowId = await getWindowId()
|
this.windowId = await getWindowId()
|
||||||
const webContents = this.getWebcontentsByWindowId(this.windowId)
|
const webContents = this.getWebcontentsByWindowId(this.windowId)
|
||||||
const rawInput = cloneDeep(input)
|
const rawInput = cloneDeep(input)
|
||||||
@@ -122,7 +131,7 @@ class GuiApi implements IGuiApi {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
showNotification (
|
showNotification(
|
||||||
options: IShowNotificationOption = {
|
options: IShowNotificationOption = {
|
||||||
title: '',
|
title: '',
|
||||||
body: ''
|
body: ''
|
||||||
@@ -135,7 +144,7 @@ class GuiApi implements IGuiApi {
|
|||||||
notification.show()
|
notification.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessageBox (
|
showMessageBox(
|
||||||
options: IShowMessageBoxOption = {
|
options: IShowMessageBoxOption = {
|
||||||
title: '',
|
title: '',
|
||||||
message: '',
|
message: '',
|
||||||
@@ -159,7 +168,7 @@ class GuiApi implements IGuiApi {
|
|||||||
/**
|
/**
|
||||||
* get picgo config/data path
|
* get picgo config/data path
|
||||||
*/
|
*/
|
||||||
async getConfigPath () {
|
async getConfigPath() {
|
||||||
const currentConfigPath = dbPathChecker()
|
const currentConfigPath = dbPathChecker()
|
||||||
const galleryDBPath = getGalleryDBPath().dbPath
|
const galleryDBPath = getGalleryDBPath().dbPath
|
||||||
return {
|
return {
|
||||||
@@ -169,12 +178,12 @@ class GuiApi implements IGuiApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get galleryDB (): DBStore {
|
get galleryDB(): DBStore {
|
||||||
return new Proxy<DBStore>(GalleryDB.getInstance(), {
|
return new Proxy<DBStore>(GalleryDB.getInstance(), {
|
||||||
get (target, prop: keyof DBStore) {
|
get(target, prop: keyof DBStore) {
|
||||||
if (prop === 'overwrite') {
|
if (prop === 'overwrite') {
|
||||||
return new Proxy(GalleryDB.getInstance().overwrite, {
|
return new Proxy(GalleryDB.getInstance().overwrite, {
|
||||||
apply (target, ctx, args) {
|
apply(target, ctx, args) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const guiApi = GuiApi.getInstance()
|
const guiApi = GuiApi.getInstance()
|
||||||
guiApi
|
guiApi
|
||||||
@@ -197,7 +206,7 @@ class GuiApi implements IGuiApi {
|
|||||||
}
|
}
|
||||||
if (prop === 'removeById') {
|
if (prop === 'removeById') {
|
||||||
return new Proxy(GalleryDB.getInstance().removeById, {
|
return new Proxy(GalleryDB.getInstance().removeById, {
|
||||||
apply (target, ctx, args) {
|
apply(target, ctx, args) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const guiApi = GuiApi.getInstance()
|
const guiApi = GuiApi.getInstance()
|
||||||
guiApi
|
guiApi
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import windowManager from 'apis/app/window/windowManager'
|
|||||||
import type { IFileWithPath } from '#/types/types'
|
import type { IFileWithPath } from '#/types/types'
|
||||||
import { IWindowList } from '~/utils/enum'
|
import { IWindowList } from '~/utils/enum'
|
||||||
|
|
||||||
function initEventCenter () {
|
function initEventCenter() {
|
||||||
const eventList: any = {
|
const eventList: any = {
|
||||||
'picgo:upload': uploadClipboardFiles,
|
'picgo:upload': uploadClipboardFiles,
|
||||||
[UPLOAD_WITH_CLIPBOARD_FILES]: busCallUploadClipboardFiles,
|
[UPLOAD_WITH_CLIPBOARD_FILES]: busCallUploadClipboardFiles,
|
||||||
@@ -31,31 +31,31 @@ function initEventCenter () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function busCallUploadClipboardFiles () {
|
async function busCallUploadClipboardFiles() {
|
||||||
const result = await uploadClipboardFiles()
|
const result = await uploadClipboardFiles()
|
||||||
const imgUrl = result.url
|
const imgUrl = result.url
|
||||||
bus.emit(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, imgUrl)
|
bus.emit(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, imgUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function busCallUploadFiles (pathList: IFileWithPath[]) {
|
async function busCallUploadFiles(pathList: IFileWithPath[]) {
|
||||||
const win = windowManager.getAvailableWindow()
|
const win = windowManager.getAvailableWindow()
|
||||||
const result = await uploadChoosedFiles(win.webContents, pathList)
|
const result = await uploadChoosedFiles(win.webContents, pathList)
|
||||||
const urls = result.map((item: any) => item.url)
|
const urls = result.map((item: any) => item.url)
|
||||||
bus.emit(UPLOAD_WITH_FILES_RESPONSE, urls)
|
bus.emit(UPLOAD_WITH_FILES_RESPONSE, urls)
|
||||||
}
|
}
|
||||||
|
|
||||||
function busCallGetWindowId () {
|
function busCallGetWindowId() {
|
||||||
const win = windowManager.getAvailableWindow()
|
const win = windowManager.getAvailableWindow()
|
||||||
bus.emit(GET_WINDOW_ID_REPONSE, win.id)
|
bus.emit(GET_WINDOW_ID_REPONSE, win.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
function busCallGetSettingWindowId () {
|
function busCallGetSettingWindowId() {
|
||||||
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
bus.emit(GET_SETTING_WINDOW_ID_RESPONSE, settingWindow.id)
|
bus.emit(GET_SETTING_WINDOW_ID_RESPONSE, settingWindow.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
listen () {
|
listen() {
|
||||||
initEventCenter()
|
initEventCenter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,19 +46,19 @@ const buildMiniPageMenu = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('UPLOAD_BY_CLIPBOARD'),
|
label: $t('UPLOAD_BY_CLIPBOARD'),
|
||||||
click () {
|
click() {
|
||||||
uploadClipboardFiles()
|
uploadClipboardFiles()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('HIDE_MINI_WINDOW'),
|
label: $t('HIDE_MINI_WINDOW'),
|
||||||
click () {
|
click() {
|
||||||
BrowserWindow.getFocusedWindow()!.hide()
|
BrowserWindow.getFocusedWindow()!.hide()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('START_WATCH_CLIPBOARD'),
|
label: $t('START_WATCH_CLIPBOARD'),
|
||||||
click () {
|
click() {
|
||||||
db.set(configPaths.settings.isListeningClipboard, true)
|
db.set(configPaths.settings.isListeningClipboard, true)
|
||||||
ClipboardWatcher.startListening()
|
ClipboardWatcher.startListening()
|
||||||
ClipboardWatcher.on('change', () => {
|
ClipboardWatcher.on('change', () => {
|
||||||
@@ -71,7 +71,7 @@ const buildMiniPageMenu = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('STOP_WATCH_CLIPBOARD'),
|
label: $t('STOP_WATCH_CLIPBOARD'),
|
||||||
click () {
|
click() {
|
||||||
db.set(configPaths.settings.isListeningClipboard, false)
|
db.set(configPaths.settings.isListeningClipboard, false)
|
||||||
ClipboardWatcher.stopListening()
|
ClipboardWatcher.stopListening()
|
||||||
ClipboardWatcher.removeAllListeners()
|
ClipboardWatcher.removeAllListeners()
|
||||||
@@ -81,7 +81,7 @@ const buildMiniPageMenu = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('RELOAD_APP'),
|
label: $t('RELOAD_APP'),
|
||||||
click () {
|
click() {
|
||||||
app.relaunch()
|
app.relaunch()
|
||||||
app.exit(0)
|
app.exit(0)
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ const buildMainPageMenu = (win: BrowserWindow) => {
|
|||||||
const template = [
|
const template = [
|
||||||
{
|
{
|
||||||
label: $t('ABOUT'),
|
label: $t('ABOUT'),
|
||||||
click () {
|
click() {
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
title: 'PicList',
|
title: 'PicList',
|
||||||
message: 'PicList',
|
message: 'PicList',
|
||||||
@@ -108,26 +108,26 @@ const buildMainPageMenu = (win: BrowserWindow) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('SHOW_PICBED_QRCODE'),
|
label: $t('SHOW_PICBED_QRCODE'),
|
||||||
click () {
|
click() {
|
||||||
win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE)
|
win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('OPEN_TOOLBOX'),
|
label: $t('OPEN_TOOLBOX'),
|
||||||
click () {
|
click() {
|
||||||
const window = windowManager.create(IWindowList.TOOLBOX_WINDOW)
|
const window = windowManager.create(IWindowList.TOOLBOX_WINDOW)
|
||||||
window?.show()
|
window?.show()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('SHOW_DEVTOOLS'),
|
label: $t('SHOW_DEVTOOLS'),
|
||||||
click () {
|
click() {
|
||||||
win?.webContents?.openDevTools({ mode: 'detach' })
|
win?.webContents?.openDevTools({ mode: 'detach' })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('FEEDBACK'),
|
label: $t('FEEDBACK'),
|
||||||
click () {
|
click() {
|
||||||
const url = 'https://github.com/Kuingsmile/PicList/issues'
|
const url = 'https://github.com/Kuingsmile/PicList/issues'
|
||||||
shell.openExternal(url)
|
shell.openExternal(url)
|
||||||
}
|
}
|
||||||
@@ -176,10 +176,10 @@ const buildSecondPicBedMenu = () => {
|
|||||||
: undefined,
|
: undefined,
|
||||||
click: !hasSubmenu
|
click: !hasSubmenu
|
||||||
? function () {
|
? function () {
|
||||||
picgo.saveConfig({
|
picgo.saveConfig({
|
||||||
[configPaths.picBed.secondUploader]: item.type
|
[configPaths.picBed.secondUploader]: item.type
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -233,15 +233,15 @@ const buildPicBedListMenu = () => {
|
|||||||
: undefined,
|
: undefined,
|
||||||
click: !hasSubmenu
|
click: !hasSubmenu
|
||||||
? function () {
|
? function () {
|
||||||
picgo.saveConfig({
|
picgo.saveConfig({
|
||||||
[configPaths.picBed.current]: item.type,
|
[configPaths.picBed.current]: item.type,
|
||||||
[configPaths.picBed.uploader]: item.type
|
[configPaths.picBed.uploader]: item.type
|
||||||
})
|
})
|
||||||
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed')
|
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed')
|
||||||
|
}
|
||||||
|
setTrayToolTip(item.type)
|
||||||
}
|
}
|
||||||
setTrayToolTip(item.type)
|
|
||||||
}
|
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -278,7 +278,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
|||||||
{
|
{
|
||||||
label: $t('ENABLE_PLUGIN'),
|
label: $t('ENABLE_PLUGIN'),
|
||||||
enabled: !plugin.enabled,
|
enabled: !plugin.enabled,
|
||||||
click () {
|
click() {
|
||||||
picgo.saveConfig({
|
picgo.saveConfig({
|
||||||
[`picgoPlugins.${plugin.fullName}`]: true
|
[`picgoPlugins.${plugin.fullName}`]: true
|
||||||
})
|
})
|
||||||
@@ -289,7 +289,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
|||||||
{
|
{
|
||||||
label: $t('DISABLE_PLUGIN'),
|
label: $t('DISABLE_PLUGIN'),
|
||||||
enabled: plugin.enabled,
|
enabled: plugin.enabled,
|
||||||
click () {
|
click() {
|
||||||
picgo.saveConfig({
|
picgo.saveConfig({
|
||||||
[`picgoPlugins.${plugin.fullName}`]: false
|
[`picgoPlugins.${plugin.fullName}`]: false
|
||||||
})
|
})
|
||||||
@@ -307,7 +307,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('UNINSTALL_PLUGIN'),
|
label: $t('UNINSTALL_PLUGIN'),
|
||||||
click () {
|
click() {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
|
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
|
||||||
handlePluginUninstall(plugin.fullName)
|
handlePluginUninstall(plugin.fullName)
|
||||||
@@ -315,7 +315,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('UPDATE_PLUGIN'),
|
label: $t('UPDATE_PLUGIN'),
|
||||||
click () {
|
click() {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
|
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
|
||||||
handlePluginUpdate(plugin.fullName)
|
handlePluginUpdate(plugin.fullName)
|
||||||
@@ -328,7 +328,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
|||||||
label: $t('CONFIG_THING', {
|
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 () {
|
click() {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const currentType = i
|
const currentType = i
|
||||||
const configName = plugin.config[i].fullName || plugin.config[i].name
|
const configName = plugin.config[i].fullName || plugin.config[i].name
|
||||||
@@ -346,7 +346,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
|||||||
const pluginTransformer = plugin.config.transformer.name
|
const pluginTransformer = plugin.config.transformer.name
|
||||||
const obj = {
|
const obj = {
|
||||||
label: `${currentTransformer === pluginTransformer ? $t('DISABLE') : $t('ENABLE')}transformer - ${plugin.config.transformer.name}`,
|
label: `${currentTransformer === pluginTransformer ? $t('DISABLE') : $t('ENABLE')}transformer - ${plugin.config.transformer.name}`,
|
||||||
click () {
|
click() {
|
||||||
const transformer = plugin.config.transformer.name
|
const transformer = plugin.config.transformer.name
|
||||||
const currentTransformer = picgo.getConfig<string>(configPaths.picBed.transformer) || 'path'
|
const currentTransformer = picgo.getConfig<string>(configPaths.picBed.transformer) || 'path'
|
||||||
if (currentTransformer === transformer) {
|
if (currentTransformer === transformer) {
|
||||||
@@ -371,7 +371,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
|
|||||||
for (const i of plugin.guiMenu) {
|
for (const i of plugin.guiMenu) {
|
||||||
menu.push({
|
menu.push({
|
||||||
label: i.label,
|
label: i.label,
|
||||||
async click () {
|
async click() {
|
||||||
const picgPlugin = await picgo.pluginLoader.getPlugin(plugin.fullName)
|
const picgPlugin = await picgo.pluginLoader.getPlugin(plugin.fullName)
|
||||||
if (picgPlugin?.guiMenu?.(picgo)?.length) {
|
if (picgPlugin?.guiMenu?.(picgo)?.length) {
|
||||||
const menu: GuiMenuItem[] = picgPlugin.guiMenu(picgo)
|
const menu: GuiMenuItem[] = picgPlugin.guiMenu(picgo)
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ class RPCServer implements IRPCServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start () {
|
start() {
|
||||||
ipcMain.on(RPC_ACTIONS, this.rpcEventHandler)
|
ipcMain.on(RPC_ACTIONS, this.rpcEventHandler)
|
||||||
ipcMain.handle(RPC_ACTIONS_INVOKE, this.rpcEventHandlerWithResponse)
|
ipcMain.handle(RPC_ACTIONS_INVOKE, this.rpcEventHandlerWithResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
use (routes: IRPCRoutes) {
|
use(routes: IRPCRoutes) {
|
||||||
for (const [action, route] of routes) {
|
for (const [action, route] of routes) {
|
||||||
if (route.type === IRPCType.SEND) {
|
if (route.type === IRPCType.SEND) {
|
||||||
this.routes.set(action, route)
|
this.routes.set(action, route)
|
||||||
@@ -52,7 +52,7 @@ class RPCServer implements IRPCServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stop () {
|
stop() {
|
||||||
ipcMain.off(RPC_ACTIONS, this.rpcEventHandler)
|
ipcMain.off(RPC_ACTIONS, this.rpcEventHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class RPCRouter implements IRPCRouter {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
routes () {
|
routes() {
|
||||||
return this.routeMap
|
return this.routeMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { IRPCActionType, IRPCType } from '~/utils/enum'
|
|||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
action: IRPCActionType.DELETE_ALL_API,
|
action: IRPCActionType.DELETE_ALL_API,
|
||||||
handler: async (_: IIPCEvent, args:[item: ImgInfo]) => {
|
handler: async (_: IIPCEvent, args: [item: ImgInfo]) => {
|
||||||
return await ALLApi.delete(args[0])
|
return await ALLApi.delete(args[0])
|
||||||
},
|
},
|
||||||
type: IRPCType.INVOKE
|
type: IRPCType.INVOKE
|
||||||
|
|||||||
@@ -85,11 +85,15 @@ const getPluginList = async (): Promise<IPicGoPlugin[]> => {
|
|||||||
},
|
},
|
||||||
uploader: {
|
uploader: {
|
||||||
name: uploaderName,
|
name: uploaderName,
|
||||||
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo))
|
config: handleConfigWithFunction(
|
||||||
|
getConfig(uploaderName, IPicGoHelperType.uploader as keyof typeof IPicGoHelperType, picgo)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
transformer: {
|
transformer: {
|
||||||
name: transformerName,
|
name: transformerName,
|
||||||
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo))
|
config: handleConfigWithFunction(
|
||||||
|
getConfig(uploaderName, IPicGoHelperType.transformer as keyof typeof IPicGoHelperType, picgo)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
|
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils'
|
|||||||
import { T as $t } from '~/i18n'
|
import { T as $t } from '~/i18n'
|
||||||
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum'
|
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum'
|
||||||
|
|
||||||
export const checkFileMap: IToolboxCheckerMap<
|
export const checkFileMap: IToolboxCheckerMap<string> = {
|
||||||
string
|
|
||||||
> = {
|
|
||||||
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => {
|
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => {
|
||||||
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN)
|
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN)
|
||||||
sendToolboxRes(event, {
|
sendToolboxRes(event, {
|
||||||
@@ -62,9 +60,7 @@ export const checkFileMap: IToolboxCheckerMap<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fixFileMap: IToolboxFixMap<
|
export const fixFileMap: IToolboxFixMap<string> = {
|
||||||
string
|
|
||||||
> = {
|
|
||||||
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => {
|
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => {
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(dbPathChecker())
|
fs.unlinkSync(dbPathChecker())
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { sendToolboxResWithType } from '~/events/rpc/routes/toolbox/utils'
|
|||||||
import { T as $t } from '~/i18n'
|
import { T as $t } from '~/i18n'
|
||||||
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum'
|
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/utils/enum'
|
||||||
|
|
||||||
function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null {
|
function getProxy(proxyStr: string): AxiosRequestConfig['proxy'] | null {
|
||||||
if (proxyStr) {
|
if (proxyStr) {
|
||||||
try {
|
try {
|
||||||
const proxyOptions = new URL(proxyStr)
|
const proxyOptions = new URL(proxyStr)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { IpcMainEvent } from 'electron'
|
|||||||
import type { IToolboxCheckRes } from '#/types/rpc'
|
import type { IToolboxCheckRes } from '#/types/rpc'
|
||||||
import { IRPCActionType } from '~/utils/enum'
|
import { IRPCActionType } from '~/utils/enum'
|
||||||
|
|
||||||
export function sendToolboxResWithType (type: string) {
|
export function sendToolboxResWithType(type: string) {
|
||||||
return (event: IpcMainEvent, res?: Omit<IToolboxCheckRes, 'type'>) => {
|
return (event: IpcMainEvent, res?: Omit<IToolboxCheckRes, 'type'>) => {
|
||||||
return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, {
|
return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, {
|
||||||
...res,
|
...res,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const serverPort = 36699
|
|||||||
|
|
||||||
let server: http.Server
|
let server: http.Server
|
||||||
|
|
||||||
export function startFileServer () {
|
export function startFileServer() {
|
||||||
server = http.createServer((req, res) => {
|
server = http.createServer((req, res) => {
|
||||||
const requestPath = req.url?.split('?')[0]
|
const requestPath = req.url?.split('?')[0]
|
||||||
const filePath = path.join(imgFilePath, decodeURIComponent(requestPath as string))
|
const filePath = path.join(imgFilePath, decodeURIComponent(requestPath as string))
|
||||||
@@ -36,7 +36,7 @@ export function startFileServer () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stopFileServer () {
|
export function stopFileServer() {
|
||||||
server.close(() => {
|
server.close(() => {
|
||||||
logger.info('File server is stopped')
|
logger.info('File server is stopped')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -33,18 +33,18 @@ class I18nManager {
|
|||||||
readonly defaultLanguage: string = 'zh-CN'
|
readonly defaultLanguage: string = 'zh-CN'
|
||||||
private i18nFileList: II18nItem[] = builtinI18nList
|
private i18nFileList: II18nItem[] = builtinI18nList
|
||||||
|
|
||||||
setOutterI18nFolder (folder: string) {
|
setOutterI18nFolder(folder: string) {
|
||||||
this.outterI18nFolder = folder
|
this.outterI18nFolder = folder
|
||||||
}
|
}
|
||||||
|
|
||||||
addI18nFile (file: string, label: string) {
|
addI18nFile(file: string, label: string) {
|
||||||
this.i18nFileList.push({
|
this.i18nFileList.push({
|
||||||
label,
|
label,
|
||||||
value: file
|
value: file
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLocales (lang: string): ILocales {
|
private getLocales(lang: string): ILocales {
|
||||||
if (this.localesMap.has(lang)) {
|
if (this.localesMap.has(lang)) {
|
||||||
return this.localesMap.get(lang)!
|
return this.localesMap.get(lang)!
|
||||||
}
|
}
|
||||||
@@ -71,13 +71,13 @@ class I18nManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentLanguage (lang: string) {
|
setCurrentLanguage(lang: string) {
|
||||||
const locales = this.getLocales(lang)
|
const locales = this.getLocales(lang)
|
||||||
this.currentLanguage = lang
|
this.currentLanguage = lang
|
||||||
this.initI18n(lang, locales)
|
this.initI18n(lang, locales)
|
||||||
}
|
}
|
||||||
|
|
||||||
private initI18n (lang: string = this.defaultLanguage, locales: ILocales) {
|
private initI18n(lang: string = this.defaultLanguage, locales: ILocales) {
|
||||||
const objectAdapter = new ObjectAdapter({
|
const objectAdapter = new ObjectAdapter({
|
||||||
[lang]: locales
|
[lang]: locales
|
||||||
})
|
})
|
||||||
@@ -87,15 +87,15 @@ class I18nManager {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
T (key: ILocalesKey, args: IStringKeyMap = {}): string {
|
T(key: ILocalesKey, args: IStringKeyMap = {}): string {
|
||||||
return this.i18n?.translate(key, args) || key
|
return this.i18n?.translate(key, args) || key
|
||||||
}
|
}
|
||||||
|
|
||||||
get languageList () {
|
get languageList() {
|
||||||
return this.i18nFileList
|
return this.i18nFileList
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentLocales () {
|
getCurrentLocales() {
|
||||||
return {
|
return {
|
||||||
lang: this.currentLanguage,
|
lang: this.currentLanguage,
|
||||||
locales: this.getLocales(this.currentLanguage)
|
locales: this.getLocales(this.currentLanguage)
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ process.on('unhandledRejection', (error: any) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// acconrding to https://github.com/Molunerfinn/PicGo/commit/7363be798cfef11e980934e542817ff1d6c04389#diff-896d0db4fbd446798fbffec14d456b4cd98d4c72c46856c770a585fa7ab0926f
|
// acconrding to https://github.com/Molunerfinn/PicGo/commit/7363be798cfef11e980934e542817ff1d6c04389#diff-896d0db4fbd446798fbffec14d456b4cd98d4c72c46856c770a585fa7ab0926f
|
||||||
function bootstrapEPIPESuppression () {
|
function bootstrapEPIPESuppression() {
|
||||||
let suppressing = false
|
let suppressing = false
|
||||||
function logEPIPEErrorOnce () {
|
function logEPIPEErrorOnce() {
|
||||||
if (suppressing) {
|
if (suppressing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -41,11 +41,11 @@ function bootstrapEPIPESuppression () {
|
|||||||
|
|
||||||
bootstrapEPIPESuppression()
|
bootstrapEPIPESuppression()
|
||||||
|
|
||||||
function epipeBomb (stream: any, callback: any) {
|
function epipeBomb(stream: any, callback: any) {
|
||||||
if (stream == null) stream = process.stdout
|
if (stream == null) stream = process.stdout
|
||||||
if (callback == null) callback = process.exit
|
if (callback == null) callback = process.exit
|
||||||
|
|
||||||
function epipeFilter (err: any) {
|
function epipeFilter(err: any) {
|
||||||
if (err.code === 'EPIPE') return callback()
|
if (err.code === 'EPIPE') return callback()
|
||||||
|
|
||||||
// If there's more than one error handler (ie, us),
|
// If there's more than one error handler (ie, us),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { shellPathSync } from 'shell-path'
|
import { shellPathSync } from 'shell-path'
|
||||||
|
|
||||||
export default function fixPath () {
|
export default function fixPath() {
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ updater.autoUpdater.on('error', err => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
class LifeCycle {
|
class LifeCycle {
|
||||||
async #beforeReady () {
|
async #beforeReady() {
|
||||||
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
|
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
|
||||||
// fix the $PATH in macOS & linux
|
// fix the $PATH in macOS & linux
|
||||||
fixPath()
|
fixPath()
|
||||||
@@ -171,7 +171,7 @@ class LifeCycle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#onReady () {
|
#onReady() {
|
||||||
const readyFunction = async () => {
|
const readyFunction = async () => {
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
installExtension(VUEJS_DEVTOOLS).catch(err => {
|
installExtension(VUEJS_DEVTOOLS).catch(err => {
|
||||||
@@ -241,9 +241,15 @@ class LifeCycle {
|
|||||||
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
||||||
miniWindow.setPosition(width - 100, height - 100)
|
miniWindow.setPosition(width - 100, height - 100)
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
||||||
} else if (lastPosition[0] + miniWindow.getSize()[0] > width || lastPosition[1] + miniWindow.getSize()[1] > height) {
|
} else if (
|
||||||
|
lastPosition[0] + miniWindow.getSize()[0] > width ||
|
||||||
|
lastPosition[1] + miniWindow.getSize()[1] > height
|
||||||
|
) {
|
||||||
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]])
|
db.set(configPaths.settings.miniWindowPosition, [
|
||||||
|
width - miniWindow.getSize()[0],
|
||||||
|
height - miniWindow.getSize()[1]
|
||||||
|
])
|
||||||
} else {
|
} else {
|
||||||
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
||||||
}
|
}
|
||||||
@@ -269,7 +275,7 @@ class LifeCycle {
|
|||||||
app.whenReady().then(readyFunction)
|
app.whenReady().then(readyFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
#onRunning () {
|
#onRunning() {
|
||||||
app.on('second-instance', (_, commandLine, workingDirectory) => {
|
app.on('second-instance', (_, commandLine, workingDirectory) => {
|
||||||
logger.info('detect second instance')
|
logger.info('detect second instance')
|
||||||
const result = handleStartUpFiles(commandLine, workingDirectory)
|
const result = handleStartUpFiles(commandLine, workingDirectory)
|
||||||
@@ -303,7 +309,7 @@ class LifeCycle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#onQuit () {
|
#onQuit() {
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
app.quit()
|
app.quit()
|
||||||
@@ -336,7 +342,7 @@ class LifeCycle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchApp () {
|
async launchApp() {
|
||||||
const gotTheLock = app.requestSingleInstanceLock()
|
const gotTheLock = app.requestSingleInstanceLock()
|
||||||
if (!gotTheLock) {
|
if (!gotTheLock) {
|
||||||
app.quit()
|
app.quit()
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class AliyunApi {
|
|||||||
timeOut = 30000
|
timeOut = 30000
|
||||||
logger: ManageLogger
|
logger: ManageLogger
|
||||||
|
|
||||||
constructor (accessKeyId: string, accessKeySecret: string, logger: ManageLogger) {
|
constructor(accessKeyId: string, accessKeySecret: string, logger: ManageLogger) {
|
||||||
this.ctx = new OSS({
|
this.ctx = new OSS({
|
||||||
accessKeyId,
|
accessKeyId,
|
||||||
accessKeySecret,
|
accessKeySecret,
|
||||||
@@ -39,7 +39,7 @@ class AliyunApi {
|
|||||||
this.logger = logger
|
this.logger = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFolder (item: string, slicedPrefix: string, urlPrefix: string): any {
|
formatFolder(item: string, slicedPrefix: string, urlPrefix: string): any {
|
||||||
return {
|
return {
|
||||||
key: item,
|
key: item,
|
||||||
url: `${urlPrefix}/${item}`,
|
url: `${urlPrefix}/${item}`,
|
||||||
@@ -54,7 +54,7 @@ class AliyunApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any {
|
formatFile(item: OSS.ObjectMeta, slicedPrefix: string, urlPrefix: string): any {
|
||||||
const fileName = item.name.replace(slicedPrefix, '')
|
const fileName = item.name.replace(slicedPrefix, '')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -71,7 +71,7 @@ class AliyunApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCanonicalizedOSSHeaders (headers: IStringKeyMap) {
|
getCanonicalizedOSSHeaders(headers: IStringKeyMap) {
|
||||||
const lowerCaseHeaders = Object.keys(headers).reduce((acc, key) => {
|
const lowerCaseHeaders = Object.keys(headers).reduce((acc, key) => {
|
||||||
acc[key.toLowerCase()] = headers[key]
|
acc[key.toLowerCase()] = headers[key]
|
||||||
return acc
|
return acc
|
||||||
@@ -84,7 +84,7 @@ class AliyunApi {
|
|||||||
return canonicalizedOSSHeaders
|
return canonicalizedOSSHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization (
|
authorization(
|
||||||
method: string,
|
method: string,
|
||||||
canonicalizedResource: string,
|
canonicalizedResource: string,
|
||||||
headers: IStringKeyMap,
|
headers: IStringKeyMap,
|
||||||
@@ -96,7 +96,7 @@ class AliyunApi {
|
|||||||
return `OSS ${this.accessKeyId}:${hmacSha1Base64(this.accessKeySecret, stringToSign)}`
|
return `OSS ${this.accessKeyId}:${hmacSha1Base64(this.accessKeySecret, stringToSign)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
getNewCtx (region: string, bucket: string) {
|
getNewCtx(region: string, bucket: string) {
|
||||||
return new OSS({
|
return new OSS({
|
||||||
accessKeyId: this.accessKeyId,
|
accessKeyId: this.accessKeyId,
|
||||||
accessKeySecret: this.accessKeySecret,
|
accessKeySecret: this.accessKeySecret,
|
||||||
@@ -109,7 +109,7 @@ class AliyunApi {
|
|||||||
/**
|
/**
|
||||||
* 获取存储桶列表
|
* 获取存储桶列表
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList(): Promise<any> {
|
||||||
const getBuckets = async (marker?: string) => {
|
const getBuckets = async (marker?: string) => {
|
||||||
const res = (await this.ctx.listBuckets({
|
const res = (await this.ctx.listBuckets({
|
||||||
marker,
|
marker,
|
||||||
@@ -143,7 +143,7 @@ class AliyunApi {
|
|||||||
/**
|
/**
|
||||||
* 获取自定义域名
|
* 获取自定义域名
|
||||||
*/
|
*/
|
||||||
async getBucketDomain (param: IStringKeyMap): Promise<any> {
|
async getBucketDomain(param: IStringKeyMap): Promise<any> {
|
||||||
const headers = {
|
const headers = {
|
||||||
Date: new Date().toUTCString()
|
Date: new Date().toUTCString()
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ class AliyunApi {
|
|||||||
* @description
|
* @description
|
||||||
* acl: private | publicRead | publicReadWrite
|
* acl: private | publicRead | publicReadWrite
|
||||||
*/
|
*/
|
||||||
async createBucket (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucket(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const client = new OSS({
|
const client = new OSS({
|
||||||
accessKeyId: this.accessKeyId,
|
accessKeyId: this.accessKeyId,
|
||||||
accessKeySecret: this.accessKeySecret,
|
accessKeySecret: this.accessKeySecret,
|
||||||
@@ -207,7 +207,7 @@ class AliyunApi {
|
|||||||
return res?.res?.status === 200
|
return res?.res?.status === 200
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
@@ -262,7 +262,7 @@ class AliyunApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
@@ -336,7 +336,7 @@ class AliyunApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getBucketFileList (configMap: IStringKeyMap): Promise<any> {
|
async getBucketFileList(configMap: IStringKeyMap): Promise<any> {
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
bucketConfig: { Location: region },
|
bucketConfig: { Location: region },
|
||||||
@@ -393,7 +393,7 @@ class AliyunApi {
|
|||||||
* newKey: string
|
* newKey: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, oldKey, newKey } = configMap
|
const { bucketName, region, oldKey, newKey } = configMap
|
||||||
const client = this.getNewCtx(region, bucketName)
|
const client = this.getNewCtx(region, bucketName)
|
||||||
const copyRes = (await client.copy(newKey, oldKey)) as any
|
const copyRes = (await client.copy(newKey, oldKey)) as any
|
||||||
@@ -413,7 +413,7 @@ class AliyunApi {
|
|||||||
* key: string
|
* key: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
const client = this.getNewCtx(region, bucketName)
|
const client = this.getNewCtx(region, bucketName)
|
||||||
const res = (await client.delete(key)) as any
|
const res = (await client.delete(key)) as any
|
||||||
@@ -424,7 +424,7 @@ class AliyunApi {
|
|||||||
* 删除文件夹
|
* 删除文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
const client = this.getNewCtx(region, bucketName)
|
const client = this.getNewCtx(region, bucketName)
|
||||||
let marker
|
let marker
|
||||||
@@ -486,7 +486,7 @@ class AliyunApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getPreSignedUrl (configMap: IStringKeyMap): Promise<string> {
|
async getPreSignedUrl(configMap: IStringKeyMap): Promise<string> {
|
||||||
const { bucketName, region, key, expires, customUrl } = configMap
|
const { bucketName, region, key, expires, customUrl } = configMap
|
||||||
const client = this.getNewCtx(region, bucketName)
|
const client = this.getNewCtx(region, bucketName)
|
||||||
const res = client.signatureUrl(key, {
|
const res = client.signatureUrl(key, {
|
||||||
@@ -499,7 +499,7 @@ class AliyunApi {
|
|||||||
* 上传文件
|
* 上传文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
// fileArray = [{
|
// fileArray = [{
|
||||||
// bucketName: string,
|
// bucketName: string,
|
||||||
@@ -586,7 +586,7 @@ class AliyunApi {
|
|||||||
* 新建文件夹
|
* 新建文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
const client = this.getNewCtx(region, bucketName)
|
const client = this.getNewCtx(region, bucketName)
|
||||||
const res = (await client.put(key, Buffer.from(''))) as any
|
const res = (await client.put(key, Buffer.from(''))) as any
|
||||||
@@ -597,7 +597,7 @@ class AliyunApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class GithubApi {
|
|||||||
baseUrl = 'https://api.github.com'
|
baseUrl = 'https://api.github.com'
|
||||||
commonHeaders: IStringKeyMap
|
commonHeaders: IStringKeyMap
|
||||||
|
|
||||||
constructor (token: string, username: string, proxy: string | undefined, logger: ManageLogger) {
|
constructor(token: string, username: string, proxy: string | undefined, logger: ManageLogger) {
|
||||||
this.logger = logger
|
this.logger = logger
|
||||||
this.token = token.startsWith('Bearer ') ? token : `Bearer ${token}`.trim()
|
this.token = token.startsWith('Bearer ') ? token : `Bearer ${token}`.trim()
|
||||||
this.username = username
|
this.username = username
|
||||||
@@ -41,7 +41,7 @@ class GithubApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFolder (item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) {
|
formatFolder(item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) {
|
||||||
const key = `${slicedPrefix ? `${slicedPrefix}/` : ''}${item.path}/`
|
const key = `${slicedPrefix ? `${slicedPrefix}/` : ''}${item.path}/`
|
||||||
let rawUrl = ''
|
let rawUrl = ''
|
||||||
const placeholders = ['{username}', '{repo}', '{branch}', '{path}']
|
const placeholders = ['{username}', '{repo}', '{branch}', '{path}']
|
||||||
@@ -78,7 +78,7 @@ class GithubApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) {
|
formatFile(item: any, slicedPrefix: string, branch: string, repo: string, cdnUrl: string | undefined) {
|
||||||
let rawUrl = ''
|
let rawUrl = ''
|
||||||
const placeholders = ['{username}', '{repo}', '{branch}', '{path}']
|
const placeholders = ['{username}', '{repo}', '{branch}', '{path}']
|
||||||
const key = slicedPrefix === '' ? item.path : `${slicedPrefix}/${item.path}`
|
const key = slicedPrefix === '' ? item.path : `${slicedPrefix}/${item.path}`
|
||||||
@@ -119,7 +119,7 @@ class GithubApi {
|
|||||||
/**
|
/**
|
||||||
* get repo list
|
* get repo list
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList(): Promise<any> {
|
||||||
let initPage = 1
|
let initPage = 1
|
||||||
let res
|
let res
|
||||||
const result = [] as any[]
|
const result = [] as any[]
|
||||||
@@ -156,7 +156,7 @@ class GithubApi {
|
|||||||
/**
|
/**
|
||||||
* 获取branch列表
|
* 获取branch列表
|
||||||
*/
|
*/
|
||||||
async getBucketDomain (param: IStringKeyMap): Promise<any> {
|
async getBucketDomain(param: IStringKeyMap): Promise<any> {
|
||||||
const { bucketName: repo } = param
|
const { bucketName: repo } = param
|
||||||
let initPage = 1
|
let initPage = 1
|
||||||
let res
|
let res
|
||||||
@@ -184,7 +184,7 @@ class GithubApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap
|
const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap
|
||||||
const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '')
|
const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '')
|
||||||
@@ -235,7 +235,7 @@ class GithubApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap
|
const { bucketName: repo, customUrl: branch, prefix, cancelToken, cdnUrl } = configMap
|
||||||
const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '')
|
const slicedPrefix = prefix.replace(/(^\/+|\/+$)/g, '')
|
||||||
@@ -285,7 +285,7 @@ class GithubApi {
|
|||||||
* key: string
|
* key: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName: repo, githubBranch: branch, key, DeleteHash: sha } = configMap
|
const { bucketName: repo, githubBranch: branch, key, DeleteHash: sha } = configMap
|
||||||
const body = {
|
const body = {
|
||||||
message: 'deleted by PicList',
|
message: 'deleted by PicList',
|
||||||
@@ -303,7 +303,7 @@ class GithubApi {
|
|||||||
* create a new tree to delete a folder
|
* create a new tree to delete a folder
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName: repo, githubBranch: branch, key } = configMap
|
const { bucketName: repo, githubBranch: branch, key } = configMap
|
||||||
// get sha of the branch
|
// get sha of the branch
|
||||||
const refRes = (await got(
|
const refRes = (await got(
|
||||||
@@ -412,7 +412,7 @@ class GithubApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getPreSignedUrl (configMap: IStringKeyMap): Promise<string> {
|
async getPreSignedUrl(configMap: IStringKeyMap): Promise<string> {
|
||||||
const { bucketName: repo, customUrl: branch, key, rawUrl, githubPrivate: isPrivate } = configMap
|
const { bucketName: repo, customUrl: branch, key, rawUrl, githubPrivate: isPrivate } = configMap
|
||||||
if (!isPrivate) return rawUrl
|
if (!isPrivate) return rawUrl
|
||||||
const res = (await got(
|
const res = (await got(
|
||||||
@@ -436,7 +436,7 @@ class GithubApi {
|
|||||||
* 新建文件夹
|
* 新建文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName: repo, githubBranch: branch, key } = configMap
|
const { bucketName: repo, githubBranch: branch, key } = configMap
|
||||||
const newFileKey = `${trimPath(key)}/.gitkeep`
|
const newFileKey = `${trimPath(key)}/.gitkeep`
|
||||||
const base64Content = Buffer.from('created by PicList').toString('base64')
|
const base64Content = Buffer.from('created by PicList').toString('base64')
|
||||||
@@ -456,7 +456,7 @@ class GithubApi {
|
|||||||
* 上传文件
|
* 上传文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
fileArray.forEach((item: any) => {
|
fileArray.forEach((item: any) => {
|
||||||
@@ -505,7 +505,7 @@ class GithubApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class ImgurApi {
|
|||||||
idHeaders: any
|
idHeaders: any
|
||||||
baseUrl = 'https://api.imgur.com/3'
|
baseUrl = 'https://api.imgur.com/3'
|
||||||
|
|
||||||
constructor (userName: string, accessToken: string, proxy: any, logger: ManageLogger) {
|
constructor(userName: string, accessToken: string, proxy: any, logger: ManageLogger) {
|
||||||
this.userName = userName
|
this.userName = userName
|
||||||
this.accessToken = accessToken.startsWith('Bearer ') ? accessToken : `Bearer ${accessToken}`
|
this.accessToken = accessToken.startsWith('Bearer ') ? accessToken : `Bearer ${accessToken}`
|
||||||
this.proxy = proxy
|
this.proxy = proxy
|
||||||
@@ -42,7 +42,7 @@ class ImgurApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: any) {
|
formatFile(item: any) {
|
||||||
const fileName = path.basename(item.link)
|
const fileName = path.basename(item.link)
|
||||||
const isImg = isImage(fileName)
|
const isImg = isImage(fileName)
|
||||||
return {
|
return {
|
||||||
@@ -64,7 +64,7 @@ class ImgurApi {
|
|||||||
/**
|
/**
|
||||||
* get repo list
|
* get repo list
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList(): Promise<any> {
|
||||||
let initPage = 0
|
let initPage = 0
|
||||||
let res
|
let res
|
||||||
const result = [] as any[]
|
const result = [] as any[]
|
||||||
@@ -93,7 +93,7 @@ class ImgurApi {
|
|||||||
return finalResult
|
return finalResult
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const {
|
const {
|
||||||
bucketConfig: { Location: albumHash },
|
bucketConfig: { Location: albumHash },
|
||||||
@@ -153,7 +153,7 @@ class ImgurApi {
|
|||||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { DeleteHash: deleteHash } = configMap
|
const { DeleteHash: deleteHash } = configMap
|
||||||
const res = (await got(
|
const res = (await got(
|
||||||
`${this.baseUrl}/account/${this.userName}/image/${deleteHash}`,
|
`${this.baseUrl}/account/${this.userName}/image/${deleteHash}`,
|
||||||
@@ -166,7 +166,7 @@ class ImgurApi {
|
|||||||
* 上传文件
|
* 上传文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
fileArray.forEach((item: any) => {
|
fileArray.forEach((item: any) => {
|
||||||
@@ -226,7 +226,7 @@ class ImgurApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class LocalApi {
|
|||||||
logger: ManageLogger
|
logger: ManageLogger
|
||||||
isWindows: boolean
|
isWindows: boolean
|
||||||
|
|
||||||
constructor (logger: ManageLogger) {
|
constructor(logger: ManageLogger) {
|
||||||
this.logger = logger
|
this.logger = logger
|
||||||
this.isWindows = process.platform === 'win32'
|
this.isWindows = process.platform === 'win32'
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,12 @@ class LocalApi {
|
|||||||
logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'LocalApi', method }))
|
logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'LocalApi', method }))
|
||||||
|
|
||||||
// windows 系统下将路径转换为 unix 风格
|
// windows 系统下将路径转换为 unix 风格
|
||||||
transPathToUnix (filePath: string | undefined) {
|
transPathToUnix(filePath: string | undefined) {
|
||||||
if (!filePath) return ''
|
if (!filePath) return ''
|
||||||
return this.isWindows ? filePath.split(path.sep).join(path.posix.sep) : filePath.replace(/^\/+/, '')
|
return this.isWindows ? filePath.split(path.sep).join(path.posix.sep) : filePath.replace(/^\/+/, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
transBack (filePath: string | undefined) {
|
transBack(filePath: string | undefined) {
|
||||||
if (!filePath) return ''
|
if (!filePath) return ''
|
||||||
return this.isWindows
|
return this.isWindows
|
||||||
? filePath
|
? filePath
|
||||||
@@ -40,7 +40,7 @@ class LocalApi {
|
|||||||
: `/${filePath.replace(/^\/+|\/+$/g, '')}`
|
: `/${filePath.replace(/^\/+|\/+$/g, '')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFolder (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) {
|
formatFolder(item: fs.Stats, urlPrefix: string, fileName: string, filePath: string) {
|
||||||
const key = `${this.transPathToUnix(filePath)}/`.replace(/\/+$/, '/')
|
const key = `${this.transPathToUnix(filePath)}/`.replace(/\/+$/, '/')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -57,7 +57,7 @@ class LocalApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: fs.Stats, urlPrefix: string, fileName: string, filePath: string, isDownload = false) {
|
formatFile(item: fs.Stats, urlPrefix: string, fileName: string, filePath: string, isDownload = false) {
|
||||||
const key = isDownload ? filePath : this.transPathToUnix(filePath)
|
const key = isDownload ? filePath : this.transPathToUnix(filePath)
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -74,7 +74,7 @@ class LocalApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { prefix, customUrl = '', cancelToken } = configMap
|
const { prefix, customUrl = '', cancelToken } = configMap
|
||||||
const urlPrefix = customUrl.replace(/\/+$/, '')
|
const urlPrefix = customUrl.replace(/\/+$/, '')
|
||||||
@@ -114,7 +114,7 @@ class LocalApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { customUrl = '', cancelToken, baseDir } = configMap
|
const { customUrl = '', cancelToken, baseDir } = configMap
|
||||||
let prefix = configMap.prefix
|
let prefix = configMap.prefix
|
||||||
@@ -170,7 +170,7 @@ class LocalApi {
|
|||||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||||
}
|
}
|
||||||
|
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { oldKey, newKey } = configMap
|
const { oldKey, newKey } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -182,7 +182,7 @@ class LocalApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -194,7 +194,7 @@ class LocalApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -208,7 +208,7 @@ class LocalApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
for (const item of fileArray) {
|
for (const item of fileArray) {
|
||||||
@@ -250,7 +250,7 @@ class LocalApi {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -264,7 +264,7 @@ class LocalApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray } = configMap
|
const { downloadPath, fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
for (const item of fileArray) {
|
for (const item of fileArray) {
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ class QiniuApi {
|
|||||||
getBucketDomain: 'https://uc.qiniuapi.com/v2/domains'
|
getBucketDomain: 'https://uc.qiniuapi.com/v2/domains'
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (accessKey: string, secretKey: string, logger: ManageLogger) {
|
constructor(accessKey: string, secretKey: string, logger: ManageLogger) {
|
||||||
this.mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
|
this.mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
|
||||||
this.accessKey = accessKey
|
this.accessKey = accessKey
|
||||||
this.secretKey = secretKey
|
this.secretKey = secretKey
|
||||||
this.logger = logger
|
this.logger = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFolder (item: string, slicedPrefix: string, urlPrefix: string) {
|
formatFolder(item: string, slicedPrefix: string, urlPrefix: string) {
|
||||||
return {
|
return {
|
||||||
Key: item,
|
Key: item,
|
||||||
key: item,
|
key: item,
|
||||||
@@ -54,7 +54,7 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: any, slicedPrefix: string, urlPrefix: string) {
|
formatFile(item: any, slicedPrefix: string, urlPrefix: string) {
|
||||||
const fileName = item.key.replace(slicedPrefix, '')
|
const fileName = item.key.replace(slicedPrefix, '')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -69,7 +69,7 @@ class QiniuApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization (
|
authorization(
|
||||||
method: string,
|
method: string,
|
||||||
urlPath: string,
|
urlPath: string,
|
||||||
host: string,
|
host: string,
|
||||||
@@ -98,7 +98,7 @@ class QiniuApi {
|
|||||||
/**
|
/**
|
||||||
* 获取存储桶列表
|
* 获取存储桶列表
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList(): Promise<any> {
|
||||||
const host = this.hostList.getBucketList
|
const host = this.hostList.getBucketList
|
||||||
const authorization = qiniu.util.generateAccessToken(this.mac, host, undefined)
|
const authorization = qiniu.util.generateAccessToken(this.mac, host, undefined)
|
||||||
const res = await axios.get(host, {
|
const res = await axios.get(host, {
|
||||||
@@ -128,7 +128,7 @@ class QiniuApi {
|
|||||||
/**
|
/**
|
||||||
* 获取存储桶详细信息
|
* 获取存储桶详细信息
|
||||||
*/
|
*/
|
||||||
async getBucketInfo (param: IStringKeyMap): Promise<any> {
|
async getBucketInfo(param: IStringKeyMap): Promise<any> {
|
||||||
const { bucketName } = param
|
const { bucketName } = param
|
||||||
const urlPath = `/v2/bucketInfo?bucket=${bucketName}&fs=true`
|
const urlPath = `/v2/bucketInfo?bucket=${bucketName}&fs=true`
|
||||||
const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json')
|
const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json')
|
||||||
@@ -160,7 +160,7 @@ class QiniuApi {
|
|||||||
/**
|
/**
|
||||||
* 获取自定义域名
|
* 获取自定义域名
|
||||||
*/
|
*/
|
||||||
async getBucketDomain (param: IStringKeyMap): Promise<any> {
|
async getBucketDomain(param: IStringKeyMap): Promise<any> {
|
||||||
const { bucketName } = param
|
const { bucketName } = param
|
||||||
const host = this.hostList.getBucketDomain
|
const host = this.hostList.getBucketDomain
|
||||||
const authorization = qiniu.util.generateAccessToken(this.mac, `${host}?tbl=${bucketName}`, undefined)
|
const authorization = qiniu.util.generateAccessToken(this.mac, `${host}?tbl=${bucketName}`, undefined)
|
||||||
@@ -180,7 +180,7 @@ class QiniuApi {
|
|||||||
/**
|
/**
|
||||||
* 修改存储桶权限
|
* 修改存储桶权限
|
||||||
*/
|
*/
|
||||||
async setBucketAclPolicy (param: IStringKeyMap): Promise<boolean> {
|
async setBucketAclPolicy(param: IStringKeyMap): Promise<boolean> {
|
||||||
// 0: 公开访问 1: 私有访问
|
// 0: 公开访问 1: 私有访问
|
||||||
const { bucketName } = param
|
const { bucketName } = param
|
||||||
let { isPrivate } = param
|
let { isPrivate } = param
|
||||||
@@ -213,7 +213,7 @@ class QiniuApi {
|
|||||||
* acl: boolean // 是否公开访问
|
* acl: boolean // 是否公开访问
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async createBucket (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucket(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { BucketName, region, acl } = configMap
|
const { BucketName, region, acl } = configMap
|
||||||
const urlPath = `/mkbucketv3/${BucketName}/region/${region}`
|
const urlPath = `/mkbucketv3/${BucketName}/region/${region}`
|
||||||
const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json')
|
const authorization = this.authorization('POST', urlPath, this.host, '', '', 'application/json')
|
||||||
@@ -235,7 +235,7 @@ class QiniuApi {
|
|||||||
: false
|
: false
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap
|
const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap
|
||||||
let marker = undefined as any
|
let marker = undefined as any
|
||||||
@@ -297,7 +297,7 @@ class QiniuApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap
|
const { bucketName: bucket, prefix, cancelToken, customUrl: urlPrefix } = configMap
|
||||||
let marker = undefined as any
|
let marker = undefined as any
|
||||||
@@ -380,7 +380,7 @@ class QiniuApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getBucketFileList (configMap: IStringKeyMap): Promise<any> {
|
async getBucketFileList(configMap: IStringKeyMap): Promise<any> {
|
||||||
const { bucketName: bucket, prefix, marker, itemsPerPage, customUrl: urlPrefix } = configMap
|
const { bucketName: bucket, prefix, marker, itemsPerPage, customUrl: urlPrefix } = configMap
|
||||||
const slicedPrefix = prefix.slice(1)
|
const slicedPrefix = prefix.slice(1)
|
||||||
const config = new qiniu.conf.Config()
|
const config = new qiniu.conf.Config()
|
||||||
@@ -440,7 +440,7 @@ class QiniuApi {
|
|||||||
* key: string
|
* key: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, key } = configMap
|
const { bucketName, key } = configMap
|
||||||
const config = new qiniu.conf.Config()
|
const config = new qiniu.conf.Config()
|
||||||
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
||||||
@@ -463,7 +463,7 @@ class QiniuApi {
|
|||||||
* 删除文件夹
|
* 删除文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, key } = configMap
|
const { bucketName, key } = configMap
|
||||||
const config = new qiniu.conf.Config()
|
const config = new qiniu.conf.Config()
|
||||||
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
||||||
@@ -535,7 +535,7 @@ class QiniuApi {
|
|||||||
* newKey: string
|
* newKey: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, oldKey, newKey } = configMap
|
const { bucketName, oldKey, newKey } = configMap
|
||||||
const config = new qiniu.conf.Config()
|
const config = new qiniu.conf.Config()
|
||||||
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
||||||
@@ -574,7 +574,7 @@ class QiniuApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getPreSignedUrl (configMap: IStringKeyMap): Promise<string> {
|
async getPreSignedUrl(configMap: IStringKeyMap): Promise<string> {
|
||||||
const { key, expires, customUrl } = configMap
|
const { key, expires, customUrl } = configMap
|
||||||
const config = new qiniu.conf.Config()
|
const config = new qiniu.conf.Config()
|
||||||
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
const bucketManager = new qiniu.rs.BucketManager(this.mac, config)
|
||||||
@@ -588,7 +588,7 @@ class QiniuApi {
|
|||||||
* 上传文件
|
* 上传文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
fileArray.forEach((item: any) => {
|
fileArray.forEach((item: any) => {
|
||||||
@@ -667,7 +667,7 @@ class QiniuApi {
|
|||||||
* 新建文件夹
|
* 新建文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, key } = configMap
|
const { bucketName, key } = configMap
|
||||||
const putPolicy = new qiniu.rs.PutPolicy({
|
const putPolicy = new qiniu.rs.PutPolicy({
|
||||||
scope: `${bucketName}:${key}`
|
scope: `${bucketName}:${key}`
|
||||||
@@ -694,7 +694,7 @@ class QiniuApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class S3plistApi {
|
|||||||
secretAccessKey: string
|
secretAccessKey: string
|
||||||
bucketName: string
|
bucketName: string
|
||||||
|
|
||||||
constructor (
|
constructor(
|
||||||
accessKeyId: string,
|
accessKeyId: string,
|
||||||
secretAccessKey: string,
|
secretAccessKey: string,
|
||||||
endpoint: string | undefined,
|
endpoint: string | undefined,
|
||||||
@@ -75,7 +75,7 @@ class S3plistApi {
|
|||||||
this.proxy = formatHttpProxy(proxy, 'string') as string | undefined
|
this.proxy = formatHttpProxy(proxy, 'string') as string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDogeCloudToken () {
|
async getDogeCloudToken() {
|
||||||
if (!this.dogeCloudSupport) return
|
if (!this.dogeCloudSupport) return
|
||||||
const token = (await getTempToken(this.accessKeyId, this.secretAccessKey)) as DogecloudToken
|
const token = (await getTempToken(this.accessKeyId, this.secretAccessKey)) as DogecloudToken
|
||||||
if (Object.keys(token).length === 0) {
|
if (Object.keys(token).length === 0) {
|
||||||
@@ -88,7 +88,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setAgent (proxy: string | undefined, sslEnabled: boolean): NodeHttpHandler {
|
setAgent(proxy: string | undefined, sslEnabled: boolean): NodeHttpHandler {
|
||||||
const agent = getAgent(proxy, sslEnabled)
|
const agent = getAgent(proxy, sslEnabled)
|
||||||
const commonOptions: AgentOptions = {
|
const commonOptions: AgentOptions = {
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
@@ -98,26 +98,26 @@ class S3plistApi {
|
|||||||
const extraOptions = sslEnabled ? { rejectUnauthorized: false } : {}
|
const extraOptions = sslEnabled ? { rejectUnauthorized: false } : {}
|
||||||
return sslEnabled
|
return sslEnabled
|
||||||
? new NodeHttpHandler({
|
? new NodeHttpHandler({
|
||||||
httpsAgent: agent.https
|
httpsAgent: agent.https
|
||||||
? agent.https
|
? agent.https
|
||||||
: new https.Agent({
|
: new https.Agent({
|
||||||
...commonOptions,
|
...commonOptions,
|
||||||
...extraOptions
|
...extraOptions
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
: new NodeHttpHandler({
|
: new NodeHttpHandler({
|
||||||
httpAgent: agent.http
|
httpAgent: agent.http
|
||||||
? agent.http
|
? agent.http
|
||||||
: new http.Agent({
|
: new http.Agent({
|
||||||
...commonOptions,
|
...commonOptions,
|
||||||
...extraOptions
|
...extraOptions
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'S3plistApi', method }))
|
logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'S3plistApi', method }))
|
||||||
|
|
||||||
formatFolder (item: CommonPrefix, slicedPrefix: string, urlPrefix: string): any {
|
formatFolder(item: CommonPrefix, slicedPrefix: string, urlPrefix: string): any {
|
||||||
return {
|
return {
|
||||||
Key: item.Prefix,
|
Key: item.Prefix,
|
||||||
url: `${urlPrefix}/${item.Prefix}`,
|
url: `${urlPrefix}/${item.Prefix}`,
|
||||||
@@ -132,7 +132,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: _Object, slicedPrefix: string, urlPrefix: string): any {
|
formatFile(item: _Object, slicedPrefix: string, urlPrefix: string): any {
|
||||||
const fileName = item.Key?.replace(slicedPrefix, '')
|
const fileName = item.Key?.replace(slicedPrefix, '')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -148,7 +148,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async putPublicAccess (bucketName: string, client: S3Client) {
|
async putPublicAccess(bucketName: string, client: S3Client) {
|
||||||
const input = {
|
const input = {
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
PublicAccessBlockConfiguration: {
|
PublicAccessBlockConfiguration: {
|
||||||
@@ -175,11 +175,11 @@ class S3plistApi {
|
|||||||
* acl: string
|
* acl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async createBucket (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucket(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { BucketName, region, acl, endpoint } = configMap
|
const { BucketName, region, acl, endpoint } = configMap
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListBucketsCommand({})
|
const command = new ListBucketsCommand({})
|
||||||
@@ -234,7 +234,7 @@ class S3plistApi {
|
|||||||
/**
|
/**
|
||||||
* 获取存储桶列表
|
* 获取存储桶列表
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList(): Promise<any> {
|
||||||
if (this.dogeCloudSupport) {
|
if (this.dogeCloudSupport) {
|
||||||
try {
|
try {
|
||||||
const res = await dogecloudApi('/oss/bucket/list.json', {}, false, this.accessKeyId, this.secretAccessKey)
|
const res = await dogecloudApi('/oss/bucket/list.json', {}, false, this.accessKeyId, this.secretAccessKey)
|
||||||
@@ -255,7 +255,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
const result: IStringKeyMap[] = []
|
const result: IStringKeyMap[] = []
|
||||||
const endpoint = (options.endpoint as string) || ''
|
const endpoint = (options.endpoint as string) || ''
|
||||||
options.region = endpoint.includes('cloudflarestorage') ? 'auto' : 'us-east-1'
|
options.region = endpoint.includes('cloudflarestorage') ? 'auto' : 'us-east-1'
|
||||||
@@ -305,7 +305,7 @@ class S3plistApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
@@ -331,7 +331,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
@@ -369,7 +369,7 @@ class S3plistApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
@@ -396,7 +396,7 @@ class S3plistApi {
|
|||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
do {
|
do {
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
@@ -439,7 +439,7 @@ class S3plistApi {
|
|||||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketFileList (configMap: IStringKeyMap): Promise<any> {
|
async getBucketFileList(configMap: IStringKeyMap): Promise<any> {
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
bucketConfig: { Location: region },
|
bucketConfig: { Location: region },
|
||||||
@@ -457,10 +457,10 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({
|
const options = {
|
||||||
|
...this.baseOptions,
|
||||||
...this.baseOptions, region: String(region) || 'us-east-1'
|
region: String(region) || 'us-east-1'
|
||||||
}) as S3ClientConfig
|
} as S3ClientConfig
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
@@ -495,15 +495,15 @@ class S3plistApi {
|
|||||||
* newKey: string
|
* newKey: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, oldKey, newKey } = configMap
|
const { bucketName, region, oldKey, newKey } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({
|
const options = {
|
||||||
|
...this.baseOptions,
|
||||||
...this.baseOptions, region: String(region) || 'us-east-1'
|
region: String(region) || 'us-east-1'
|
||||||
}) as S3ClientConfig
|
} as S3ClientConfig
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new CopyObjectCommand({
|
const command = new CopyObjectCommand({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
@@ -540,12 +540,12 @@ class S3plistApi {
|
|||||||
* key: string
|
* key: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new DeleteObjectCommand({
|
const command = new DeleteObjectCommand({
|
||||||
@@ -568,7 +568,7 @@ class S3plistApi {
|
|||||||
* 删除文件夹
|
* 删除文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
let marker
|
let marker
|
||||||
let result = false
|
let result = false
|
||||||
@@ -581,7 +581,7 @@ class S3plistApi {
|
|||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
do {
|
do {
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new ListObjectsV2Command({
|
const command = new ListObjectsV2Command({
|
||||||
@@ -616,7 +616,7 @@ class S3plistApi {
|
|||||||
}
|
}
|
||||||
if (allFileList.Contents.length > 0) {
|
if (allFileList.Contents.length > 0) {
|
||||||
const cycle = Math.ceil(allFileList.Contents.length / 1000)
|
const cycle = Math.ceil(allFileList.Contents.length / 1000)
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
for (let i = 0; i < cycle; i++) {
|
for (let i = 0; i < cycle; i++) {
|
||||||
@@ -657,11 +657,11 @@ class S3plistApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getPreSignedUrl (configMap: IStringKeyMap): Promise<string> {
|
async getPreSignedUrl(configMap: IStringKeyMap): Promise<string> {
|
||||||
const { bucketName, region, key, expires } = configMap
|
const { bucketName, region, key, expires } = configMap
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const signedUrl = await getSignedUrl(
|
const signedUrl = await getSignedUrl(
|
||||||
@@ -685,12 +685,12 @@ class S3plistApi {
|
|||||||
* 新建文件夹
|
* 新建文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
await this.getDogeCloudToken()
|
await this.getDogeCloudToken()
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const command = new PutObjectCommand({
|
const command = new PutObjectCommand({
|
||||||
@@ -713,7 +713,7 @@ class S3plistApi {
|
|||||||
* upload file
|
* upload file
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
// fileArray = [{
|
// fileArray = [{
|
||||||
// bucketName: string,
|
// bucketName: string,
|
||||||
@@ -764,7 +764,7 @@ class S3plistApi {
|
|||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const options = ({ ...this.baseOptions }) as S3ClientConfig
|
const options = { ...this.baseOptions } as S3ClientConfig
|
||||||
options.region = String(region) || 'us-east-1'
|
options.region = String(region) || 'us-east-1'
|
||||||
const client = new S3Client(options)
|
const client = new S3Client(options)
|
||||||
const fileStream = fs.createReadStream(filePath)
|
const fileStream = fs.createReadStream(filePath)
|
||||||
@@ -825,7 +825,7 @@ class S3plistApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class SftpApi {
|
|||||||
passphrase: string
|
passphrase: string
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (
|
constructor(
|
||||||
host: string,
|
host: string,
|
||||||
port: Undefinable<number>,
|
port: Undefinable<number>,
|
||||||
username: Undefinable<string>,
|
username: Undefinable<string>,
|
||||||
@@ -94,7 +94,7 @@ class SftpApi {
|
|||||||
return `0${result}`
|
return `0${result}`
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFolder (item: listDirResult, urlPrefix: string, isWebPath = false) {
|
formatFolder(item: listDirResult, urlPrefix: string, isWebPath = false) {
|
||||||
const key = item.key
|
const key = item.key
|
||||||
let url: string
|
let url: string
|
||||||
if (isWebPath) {
|
if (isWebPath) {
|
||||||
@@ -121,7 +121,7 @@ class SftpApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: listDirResult, urlPrefix: string, isWebPath = false) {
|
formatFile(item: listDirResult, urlPrefix: string, isWebPath = false) {
|
||||||
const key = item.key
|
const key = item.key
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -151,7 +151,7 @@ class SftpApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { prefix, customUrl, cancelToken } = configMap
|
const { prefix, customUrl, cancelToken } = configMap
|
||||||
const urlPrefix = customUrl || `${this.host}:${this.port}`
|
const urlPrefix = customUrl || `${this.host}:${this.port}`
|
||||||
@@ -191,7 +191,7 @@ class SftpApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
formatLSResult (res: string, cwd: string): listDirResult[] {
|
formatLSResult(res: string, cwd: string): listDirResult[] {
|
||||||
const result = [] as listDirResult[]
|
const result = [] as listDirResult[]
|
||||||
const resArray = res.trim().split('\n')
|
const resArray = res.trim().split('\n')
|
||||||
resArray.slice(resArray[0].startsWith('total') ? 1 : 0).forEach((item: string) => {
|
resArray.slice(resArray[0].startsWith('total') ? 1 : 0).forEach((item: string) => {
|
||||||
@@ -217,7 +217,7 @@ class SftpApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { prefix, customUrl, cancelToken, baseDir } = configMap
|
const { prefix, customUrl, cancelToken, baseDir } = configMap
|
||||||
let urlPrefix = customUrl || `${this.host}:${this.port}`
|
let urlPrefix = customUrl || `${this.host}:${this.port}`
|
||||||
@@ -276,7 +276,7 @@ class SftpApi {
|
|||||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||||
}
|
}
|
||||||
|
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { oldKey, newKey } = configMap
|
const { oldKey, newKey } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -290,7 +290,7 @@ class SftpApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -304,7 +304,7 @@ class SftpApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -321,7 +321,7 @@ class SftpApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
for (const item of fileArray) {
|
for (const item of fileArray) {
|
||||||
@@ -376,7 +376,7 @@ class SftpApi {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -390,7 +390,7 @@ class SftpApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray } = configMap
|
const { downloadPath, fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
for (const item of fileArray) {
|
for (const item of fileArray) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SmmsApi {
|
|||||||
logger: ManageLogger
|
logger: ManageLogger
|
||||||
timeout = 30000
|
timeout = 30000
|
||||||
|
|
||||||
constructor (token: string, logger: ManageLogger) {
|
constructor(token: string, logger: ManageLogger) {
|
||||||
this.token = token
|
this.token = token
|
||||||
this.axiosInstance = axios.create({
|
this.axiosInstance = axios.create({
|
||||||
baseURL: this.baseUrl,
|
baseURL: this.baseUrl,
|
||||||
@@ -37,7 +37,7 @@ class SmmsApi {
|
|||||||
this.logger = logger
|
this.logger = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: any) {
|
formatFile(item: any) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
Key: item.path,
|
Key: item.path,
|
||||||
@@ -54,7 +54,7 @@ class SmmsApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { cancelToken } = configMap
|
const { cancelToken } = configMap
|
||||||
let marker = 1
|
let marker = 1
|
||||||
@@ -123,7 +123,7 @@ class SmmsApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getBucketFileList ({ currentPage }: IStringKeyMap): Promise<any> {
|
async getBucketFileList({ currentPage }: IStringKeyMap): Promise<any> {
|
||||||
const result = {
|
const result = {
|
||||||
fullList: [] as any,
|
fullList: [] as any,
|
||||||
isTruncated: false,
|
isTruncated: false,
|
||||||
@@ -162,7 +162,7 @@ class SmmsApi {
|
|||||||
* DeleteHash: string
|
* DeleteHash: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile ({ DeleteHash }: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile({ DeleteHash }: IStringKeyMap): Promise<boolean> {
|
||||||
const res = await this.axiosInstance(`/delete/${DeleteHash}`, {
|
const res = await this.axiosInstance(`/delete/${DeleteHash}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
params: {
|
params: {
|
||||||
@@ -177,7 +177,7 @@ class SmmsApi {
|
|||||||
* 上传文件
|
* 上传文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
for (const item of fileArray) {
|
for (const item of fileArray) {
|
||||||
@@ -214,7 +214,7 @@ class SmmsApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class TcyunApi {
|
|||||||
ctx: COS
|
ctx: COS
|
||||||
logger: ManageLogger
|
logger: ManageLogger
|
||||||
|
|
||||||
constructor (secretId: string, secretKey: string, logger: ManageLogger) {
|
constructor(secretId: string, secretKey: string, logger: ManageLogger) {
|
||||||
this.ctx = new COS({
|
this.ctx = new COS({
|
||||||
SecretId: secretId,
|
SecretId: secretId,
|
||||||
SecretKey: secretKey
|
SecretKey: secretKey
|
||||||
@@ -25,7 +25,7 @@ class TcyunApi {
|
|||||||
this.logger = logger
|
this.logger = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFolder (item: { Prefix: string }, slicedPrefix: string, urlPrefix: string) {
|
formatFolder(item: { Prefix: string }, slicedPrefix: string, urlPrefix: string) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
key: item.Prefix,
|
key: item.Prefix,
|
||||||
@@ -40,7 +40,7 @@ class TcyunApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: COS.CosObject, slicedPrefix: string, urlPrefix: string): any {
|
formatFile(item: COS.CosObject, slicedPrefix: string, urlPrefix: string): any {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
key: item.Key,
|
key: item.Key,
|
||||||
@@ -58,7 +58,7 @@ class TcyunApi {
|
|||||||
/**
|
/**
|
||||||
* 获取存储桶列表
|
* 获取存储桶列表
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList(): Promise<any> {
|
||||||
const res = await this.ctx.getService({})
|
const res = await this.ctx.getService({})
|
||||||
return res?.Buckets || []
|
return res?.Buckets || []
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ class TcyunApi {
|
|||||||
/**
|
/**
|
||||||
* 获取自定义域名
|
* 获取自定义域名
|
||||||
*/
|
*/
|
||||||
async getBucketDomain (param: IStringKeyMap): Promise<any> {
|
async getBucketDomain(param: IStringKeyMap): Promise<any> {
|
||||||
const { bucketName, region } = param
|
const { bucketName, region } = param
|
||||||
const res = await this.ctx.getBucketDomain({
|
const res = await this.ctx.getBucketDomain({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
@@ -87,7 +87,7 @@ class TcyunApi {
|
|||||||
* @description
|
* @description
|
||||||
* acl: private | publicRead | publicReadWrite
|
* acl: private | publicRead | publicReadWrite
|
||||||
*/
|
*/
|
||||||
async createBucket (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucket(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const res = await this.ctx.putBucket({
|
const res = await this.ctx.putBucket({
|
||||||
ACL: configMap.acl,
|
ACL: configMap.acl,
|
||||||
Bucket: configMap.BucketName,
|
Bucket: configMap.BucketName,
|
||||||
@@ -96,7 +96,7 @@ class TcyunApi {
|
|||||||
return res?.statusCode === 200
|
return res?.statusCode === 200
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
@@ -150,7 +150,7 @@ class TcyunApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
@@ -221,7 +221,7 @@ class TcyunApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getBucketFileList (configMap: IStringKeyMap): Promise<any> {
|
async getBucketFileList(configMap: IStringKeyMap): Promise<any> {
|
||||||
const {
|
const {
|
||||||
bucketName: bucket,
|
bucketName: bucket,
|
||||||
bucketConfig: { Location: region },
|
bucketConfig: { Location: region },
|
||||||
@@ -272,7 +272,7 @@ class TcyunApi {
|
|||||||
* newKey: string
|
* newKey: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, oldKey, newKey } = configMap
|
const { bucketName, region, oldKey, newKey } = configMap
|
||||||
const copyRes = await this.ctx.putObjectCopy({
|
const copyRes = await this.ctx.putObjectCopy({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
@@ -301,7 +301,7 @@ class TcyunApi {
|
|||||||
* key: string
|
* key: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
const res = await this.ctx.deleteObject({
|
const res = await this.ctx.deleteObject({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
@@ -315,7 +315,7 @@ class TcyunApi {
|
|||||||
* 删除文件夹
|
* 删除文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
let marker
|
let marker
|
||||||
let res: any
|
let res: any
|
||||||
@@ -346,7 +346,9 @@ class TcyunApi {
|
|||||||
region,
|
region,
|
||||||
key: item.Prefix
|
key: item.Prefix
|
||||||
}))
|
}))
|
||||||
) { return false }
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const cycles = Math.ceil(allFileList.Contents.length / 1000)
|
const cycles = Math.ceil(allFileList.Contents.length / 1000)
|
||||||
for (let i = 0; i < cycles; i++) {
|
for (let i = 0; i < cycles; i++) {
|
||||||
@@ -371,7 +373,7 @@ class TcyunApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getPreSignedUrl (configMap: IStringKeyMap): Promise<string> {
|
async getPreSignedUrl(configMap: IStringKeyMap): Promise<string> {
|
||||||
const { bucketName, region, key, expires, customUrl } = configMap
|
const { bucketName, region, key, expires, customUrl } = configMap
|
||||||
const res = this.ctx.getObjectUrl(
|
const res = this.ctx.getObjectUrl(
|
||||||
{
|
{
|
||||||
@@ -390,7 +392,7 @@ class TcyunApi {
|
|||||||
* 高级上传文件
|
* 高级上传文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
// fileArray = [{
|
// fileArray = [{
|
||||||
// bucketName: string,
|
// bucketName: string,
|
||||||
@@ -470,7 +472,7 @@ class TcyunApi {
|
|||||||
* 新建文件夹
|
* 新建文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { bucketName, region, key } = configMap
|
const { bucketName, region, key } = configMap
|
||||||
const res = await this.ctx.putObject({
|
const res = await this.ctx.putObject({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
@@ -485,7 +487,7 @@ class TcyunApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray } = configMap
|
const { downloadPath, fileArray } = configMap
|
||||||
// fileArray = [{
|
// fileArray = [{
|
||||||
// bucketName: string,
|
// bucketName: string,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class UpyunApi {
|
|||||||
stopMarker = 'g2gCZAAEbmV4dGQAA2VvZg'
|
stopMarker = 'g2gCZAAEbmV4dGQAA2VvZg'
|
||||||
logger: ManageLogger
|
logger: ManageLogger
|
||||||
|
|
||||||
constructor (
|
constructor(
|
||||||
bucket: string,
|
bucket: string,
|
||||||
operator: string,
|
operator: string,
|
||||||
password: string,
|
password: string,
|
||||||
@@ -52,7 +52,7 @@ class UpyunApi {
|
|||||||
this.expireTime = expireTime || 24 * 60 * 60
|
this.expireTime = expireTime || 24 * 60 * 60
|
||||||
}
|
}
|
||||||
|
|
||||||
getAntiLeechParam (key: string): string {
|
getAntiLeechParam(key: string): string {
|
||||||
const uri = `/${key}`.replace(/%2F/g, '/').replace(/^\/+/g, '/')
|
const uri = `/${key}`.replace(/%2F/g, '/').replace(/^\/+/g, '/')
|
||||||
const now = Math.round(new Date().getTime() / 1000)
|
const now = Math.round(new Date().getTime() / 1000)
|
||||||
const expire = this.expireTime ? now + parseInt(this.expireTime.toString(), 10) : now + 1800
|
const expire = this.expireTime ? now + parseInt(this.expireTime.toString(), 10) : now + 1800
|
||||||
@@ -61,7 +61,7 @@ class UpyunApi {
|
|||||||
return `_upt=${upt}`
|
return `_upt=${upt}`
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFolder (item: any, slicedPrefix: string, urlPrefix: string) {
|
formatFolder(item: any, slicedPrefix: string, urlPrefix: string) {
|
||||||
const key = `${slicedPrefix}${item.name}/`
|
const key = `${slicedPrefix}${item.name}/`
|
||||||
let url = `${urlPrefix}/${key}`
|
let url = `${urlPrefix}/${key}`
|
||||||
if (this.antiLeechToken) {
|
if (this.antiLeechToken) {
|
||||||
@@ -82,7 +82,7 @@ class UpyunApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: any, slicedPrefix: string, urlPrefix: string) {
|
formatFile(item: any, slicedPrefix: string, urlPrefix: string) {
|
||||||
const key = `${slicedPrefix}${item.name}`
|
const key = `${slicedPrefix}${item.name}`
|
||||||
let url = `${urlPrefix}/${key}`
|
let url = `${urlPrefix}/${key}`
|
||||||
if (this.antiLeechToken) {
|
if (this.antiLeechToken) {
|
||||||
@@ -102,7 +102,7 @@ class UpyunApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
authorization (method: string, uri: string, contentMd5: string, operator: string, password: string) {
|
authorization(method: string, uri: string, contentMd5: string, operator: string, password: string) {
|
||||||
return `UPYUN ${operator}:${hmacSha1Base64(
|
return `UPYUN ${operator}:${hmacSha1Base64(
|
||||||
md5(password, 'hex'),
|
md5(password, 'hex'),
|
||||||
`${method.toUpperCase()}&${encodeURI(uri)}&${new Date().toUTCString()}${contentMd5 ? `&${contentMd5}` : ''}`
|
`${method.toUpperCase()}&${encodeURI(uri)}&${new Date().toUTCString()}${contentMd5 ? `&${contentMd5}` : ''}`
|
||||||
@@ -112,11 +112,11 @@ class UpyunApi {
|
|||||||
/**
|
/**
|
||||||
* 获取空间列表
|
* 获取空间列表
|
||||||
*/
|
*/
|
||||||
async getBucketList (): Promise<any> {
|
async getBucketList(): Promise<any> {
|
||||||
return this.bucket
|
return this.bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { bucketName: bucket, prefix, cancelToken } = configMap
|
const { bucketName: bucket, prefix, cancelToken } = configMap
|
||||||
const slicedPrefix = prefix.slice(1)
|
const slicedPrefix = prefix.slice(1)
|
||||||
@@ -168,7 +168,7 @@ class UpyunApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { bucketName: bucket, prefix, cancelToken } = configMap
|
const { bucketName: bucket, prefix, cancelToken } = configMap
|
||||||
const slicedPrefix = prefix.slice(1)
|
const slicedPrefix = prefix.slice(1)
|
||||||
@@ -227,7 +227,7 @@ class UpyunApi {
|
|||||||
* customUrl: string
|
* customUrl: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async getBucketFileList (configMap: IStringKeyMap): Promise<any> {
|
async getBucketFileList(configMap: IStringKeyMap): Promise<any> {
|
||||||
const { bucketName: bucket, prefix, marker, itemsPerPage } = configMap
|
const { bucketName: bucket, prefix, marker, itemsPerPage } = configMap
|
||||||
const slicedPrefix = prefix.slice(1)
|
const slicedPrefix = prefix.slice(1)
|
||||||
const urlPrefix = configMap.customUrl || `http://${bucket}.test.upcdn.net`
|
const urlPrefix = configMap.customUrl || `http://${bucket}.test.upcdn.net`
|
||||||
@@ -264,7 +264,7 @@ class UpyunApi {
|
|||||||
* newKey: string
|
* newKey: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const oldKey = configMap.oldKey
|
const oldKey = configMap.oldKey
|
||||||
let newKey = configMap.newKey
|
let newKey = configMap.newKey
|
||||||
const method = 'PUT'
|
const method = 'PUT'
|
||||||
@@ -297,7 +297,7 @@ class UpyunApi {
|
|||||||
* key: string
|
* key: string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
const res = await this.cli.deleteFile(key)
|
const res = await this.cli.deleteFile(key)
|
||||||
return res
|
return res
|
||||||
@@ -307,7 +307,7 @@ class UpyunApi {
|
|||||||
* delete bucket folder
|
* delete bucket folder
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let marker = ''
|
let marker = ''
|
||||||
let isTruncated
|
let isTruncated
|
||||||
@@ -370,7 +370,7 @@ class UpyunApi {
|
|||||||
* axiso:onUploadProgress not work in nodejs , use got instead
|
* axiso:onUploadProgress not work in nodejs , use got instead
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
fileArray.forEach((item: any) => {
|
fileArray.forEach((item: any) => {
|
||||||
@@ -426,7 +426,7 @@ class UpyunApi {
|
|||||||
* 新建文件夹
|
* 新建文件夹
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
const res = await this.cli.makeDir(`/${key}`)
|
const res = await this.cli.makeDir(`/${key}`)
|
||||||
return res
|
return res
|
||||||
@@ -436,7 +436,7 @@ class UpyunApi {
|
|||||||
* 下载文件
|
* 下载文件
|
||||||
* @param configMap
|
* @param configMap
|
||||||
*/
|
*/
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class WebdavplistApi {
|
|||||||
agent: https.Agent | http.Agent
|
agent: https.Agent | http.Agent
|
||||||
ctx: WebDAVClient
|
ctx: WebDAVClient
|
||||||
|
|
||||||
constructor (
|
constructor(
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
@@ -62,7 +62,7 @@ class WebdavplistApi {
|
|||||||
|
|
||||||
logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'WebdavplistApi', method }))
|
logParam = (error: any, method: string) => this.logger.error(formatError(error, { class: 'WebdavplistApi', method }))
|
||||||
|
|
||||||
formatFolder (item: FileStat, urlPrefix: string, isWebPath = false) {
|
formatFolder(item: FileStat, urlPrefix: string, isWebPath = false) {
|
||||||
const key = item.filename.replace(/^\/+/, '')
|
const key = item.filename.replace(/^\/+/, '')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -79,7 +79,7 @@ class WebdavplistApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatFile (item: FileStat, urlPrefix: string, isWebPath = false) {
|
formatFile(item: FileStat, urlPrefix: string, isWebPath = false) {
|
||||||
const key = item.filename.replace(/^\/+/, '')
|
const key = item.filename.replace(/^\/+/, '')
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -98,7 +98,7 @@ class WebdavplistApi {
|
|||||||
|
|
||||||
isRequestSuccess = (code: number) => code >= 200 && code < 300
|
isRequestSuccess = (code: number) => code >= 200 && code < 300
|
||||||
|
|
||||||
async getBucketListRecursively (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListRecursively(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { prefix, customUrl, cancelToken } = configMap
|
const { prefix, customUrl, cancelToken } = configMap
|
||||||
const urlPrefix = customUrl || this.endpoint
|
const urlPrefix = customUrl || this.endpoint
|
||||||
@@ -138,7 +138,7 @@ class WebdavplistApi {
|
|||||||
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListBackstage (configMap: IStringKeyMap): Promise<any> {
|
async getBucketListBackstage(configMap: IStringKeyMap): Promise<any> {
|
||||||
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
const { prefix, customUrl, cancelToken, baseDir } = configMap
|
const { prefix, customUrl, cancelToken, baseDir } = configMap
|
||||||
let urlPrefix = customUrl || this.endpoint
|
let urlPrefix = customUrl || this.endpoint
|
||||||
@@ -197,7 +197,7 @@ class WebdavplistApi {
|
|||||||
ipcMain.removeAllListeners('cancelLoadingFileList')
|
ipcMain.removeAllListeners('cancelLoadingFileList')
|
||||||
}
|
}
|
||||||
|
|
||||||
async renameBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { oldKey, newKey } = configMap
|
const { oldKey, newKey } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -209,7 +209,7 @@ class WebdavplistApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -221,7 +221,7 @@ class WebdavplistApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -233,7 +233,7 @@ class WebdavplistApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPreSignedUrl (configMap: IStringKeyMap): Promise<string> {
|
async getPreSignedUrl(configMap: IStringKeyMap): Promise<string> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = ''
|
let result = ''
|
||||||
try {
|
try {
|
||||||
@@ -245,7 +245,7 @@ class WebdavplistApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { fileArray } = configMap
|
const { fileArray } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
for (const item of fileArray) {
|
for (const item of fileArray) {
|
||||||
@@ -306,7 +306,7 @@ class WebdavplistApi {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBucketFolder (configMap: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { key } = configMap
|
const { key } = configMap
|
||||||
let result = false
|
let result = false
|
||||||
try {
|
try {
|
||||||
@@ -320,7 +320,7 @@ class WebdavplistApi {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadBucketFile (configMap: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
const { downloadPath, fileArray, maxDownloadFileCount } = configMap
|
||||||
const instance = UpDownTaskQueue.getInstance()
|
const instance = UpDownTaskQueue.getInstance()
|
||||||
const promises = [] as any
|
const promises = [] as any
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface IJSON {
|
|||||||
class ManageDB {
|
class ManageDB {
|
||||||
readonly #ctx: IManageApiType
|
readonly #ctx: IManageApiType
|
||||||
readonly #db: JSONStore
|
readonly #db: JSONStore
|
||||||
constructor (ctx: IManageApiType) {
|
constructor(ctx: IManageApiType) {
|
||||||
this.#ctx = ctx
|
this.#ctx = ctx
|
||||||
this.#db = new JSONStore(this.#ctx.configPath)
|
this.#db = new JSONStore(this.#ctx.configPath)
|
||||||
const initParams: IStringKeyMap = {
|
const initParams: IStringKeyMap = {
|
||||||
@@ -28,37 +28,37 @@ class ManageDB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read (flush?: boolean): IJSON {
|
read(flush?: boolean): IJSON {
|
||||||
return this.#db.read(flush)
|
return this.#db.read(flush)
|
||||||
}
|
}
|
||||||
|
|
||||||
get (key: string = ''): any {
|
get(key: string = ''): any {
|
||||||
this.read(true)
|
this.read(true)
|
||||||
return this.#db.get(key)
|
return this.#db.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
set (key: string, value: any): void {
|
set(key: string, value: any): void {
|
||||||
this.read(true)
|
this.read(true)
|
||||||
return this.#db.set(key, value)
|
return this.#db.set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
has (key: string): boolean {
|
has(key: string): boolean {
|
||||||
this.read(true)
|
this.read(true)
|
||||||
return this.#db.has(key)
|
return this.#db.has(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
unset (key: string, value: any): boolean {
|
unset(key: string, value: any): boolean {
|
||||||
this.read(true)
|
this.read(true)
|
||||||
return this.#db.unset(key, value)
|
return this.#db.unset(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
saveConfig (config: Partial<IManageConfigType>): void {
|
saveConfig(config: Partial<IManageConfigType>): void {
|
||||||
Object.keys(config).forEach((name: string) => {
|
Object.keys(config).forEach((name: string) => {
|
||||||
this.set(name, config[name])
|
this.set(name, config[name])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
removeConfig (config: IManageConfigType): void {
|
removeConfig(config: IManageConfigType): void {
|
||||||
Object.keys(config).forEach((name: string) => {
|
Object.keys(config).forEach((name: string) => {
|
||||||
this.unset(name, config[name])
|
this.unset(name, config[name])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const errorMsg = {
|
|||||||
brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP')
|
brokenButBackup: $t('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP')
|
||||||
}
|
}
|
||||||
|
|
||||||
function manageDbChecker () {
|
function manageDbChecker() {
|
||||||
if (process.type !== 'renderer') {
|
if (process.type !== 'renderer') {
|
||||||
const manageConfigFilePath = managePathChecker()
|
const manageConfigFilePath = managePathChecker()
|
||||||
if (!fs.existsSync(manageConfigFilePath)) {
|
if (!fs.existsSync(manageConfigFilePath)) {
|
||||||
@@ -72,7 +72,7 @@ function manageDbChecker () {
|
|||||||
/**
|
/**
|
||||||
* Get manage config path
|
* Get manage config path
|
||||||
*/
|
*/
|
||||||
function managePathChecker (): string {
|
function managePathChecker(): string {
|
||||||
if (_configFilePath) {
|
if (_configFilePath) {
|
||||||
return _configFilePath
|
return _configFilePath
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ function managePathChecker (): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function managePathDir () {
|
function managePathDir() {
|
||||||
return path.dirname(managePathChecker())
|
return path.dirname(managePathChecker())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,38 +18,38 @@ class UpDownTaskQueue {
|
|||||||
|
|
||||||
private persistPath = path.join(app.getPath('userData'), 'UpDownTaskQueue.json')
|
private persistPath = path.join(app.getPath('userData'), 'UpDownTaskQueue.json')
|
||||||
|
|
||||||
private constructor () {
|
private constructor() {
|
||||||
this.restore()
|
this.restore()
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInstance () {
|
static getInstance() {
|
||||||
if (!UpDownTaskQueue.instance) {
|
if (!UpDownTaskQueue.instance) {
|
||||||
UpDownTaskQueue.instance = new UpDownTaskQueue()
|
UpDownTaskQueue.instance = new UpDownTaskQueue()
|
||||||
}
|
}
|
||||||
return UpDownTaskQueue.instance
|
return UpDownTaskQueue.instance
|
||||||
}
|
}
|
||||||
|
|
||||||
getUploadTaskQueue () {
|
getUploadTaskQueue() {
|
||||||
return UpDownTaskQueue.getInstance().uploadTaskQueue
|
return UpDownTaskQueue.getInstance().uploadTaskQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
getDownloadTaskQueue () {
|
getDownloadTaskQueue() {
|
||||||
return UpDownTaskQueue.getInstance().downloadTaskQueue
|
return UpDownTaskQueue.getInstance().downloadTaskQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
getUploadTask (taskId: string) {
|
getUploadTask(taskId: string) {
|
||||||
return UpDownTaskQueue.getInstance().uploadTaskQueue.find(item => item.id === taskId)
|
return UpDownTaskQueue.getInstance().uploadTaskQueue.find(item => item.id === taskId)
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllUploadTask () {
|
getAllUploadTask() {
|
||||||
return UpDownTaskQueue.getInstance().uploadTaskQueue
|
return UpDownTaskQueue.getInstance().uploadTaskQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
addUploadTask (task: IUploadTask) {
|
addUploadTask(task: IUploadTask) {
|
||||||
UpDownTaskQueue.getInstance().uploadTaskQueue.push(task)
|
UpDownTaskQueue.getInstance().uploadTaskQueue.push(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUploadTask (task: Partial<IUploadTask>) {
|
updateUploadTask(task: Partial<IUploadTask>) {
|
||||||
const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === task.id)
|
const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === task.id)
|
||||||
if (taskIndex !== -1) {
|
if (taskIndex !== -1) {
|
||||||
const taskKeys = Object.keys(task)
|
const taskKeys = Object.keys(task)
|
||||||
@@ -61,33 +61,33 @@ class UpDownTaskQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUploadTask (taskId: string) {
|
removeUploadTask(taskId: string) {
|
||||||
const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === taskId)
|
const taskIndex = UpDownTaskQueue.getInstance().uploadTaskQueue.findIndex(item => item.id === taskId)
|
||||||
if (taskIndex !== -1) {
|
if (taskIndex !== -1) {
|
||||||
UpDownTaskQueue.getInstance().uploadTaskQueue.splice(taskIndex, 1)
|
UpDownTaskQueue.getInstance().uploadTaskQueue.splice(taskIndex, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeDownloadTask (taskId: string) {
|
removeDownloadTask(taskId: string) {
|
||||||
const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === taskId)
|
const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === taskId)
|
||||||
if (taskIndex !== -1) {
|
if (taskIndex !== -1) {
|
||||||
UpDownTaskQueue.getInstance().downloadTaskQueue.splice(taskIndex, 1)
|
UpDownTaskQueue.getInstance().downloadTaskQueue.splice(taskIndex, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getDownloadTask (taskId: string) {
|
getDownloadTask(taskId: string) {
|
||||||
return UpDownTaskQueue.getInstance().downloadTaskQueue.find(item => item.id === taskId)
|
return UpDownTaskQueue.getInstance().downloadTaskQueue.find(item => item.id === taskId)
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllDownloadTask () {
|
getAllDownloadTask() {
|
||||||
return UpDownTaskQueue.getInstance().downloadTaskQueue
|
return UpDownTaskQueue.getInstance().downloadTaskQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
addDownloadTask (task: IDownloadTask) {
|
addDownloadTask(task: IDownloadTask) {
|
||||||
UpDownTaskQueue.getInstance().downloadTaskQueue.push(task)
|
UpDownTaskQueue.getInstance().downloadTaskQueue.push(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDownloadTask (task: Partial<IDownloadTask>) {
|
updateDownloadTask(task: Partial<IDownloadTask>) {
|
||||||
const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === task.id)
|
const taskIndex = UpDownTaskQueue.getInstance().downloadTaskQueue.findIndex(item => item.id === task.id)
|
||||||
if (taskIndex !== -1) {
|
if (taskIndex !== -1) {
|
||||||
const taskKeys = Object.keys(task)
|
const taskKeys = Object.keys(task)
|
||||||
@@ -99,11 +99,11 @@ class UpDownTaskQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearUploadTaskQueue () {
|
clearUploadTaskQueue() {
|
||||||
UpDownTaskQueue.getInstance().uploadTaskQueue = []
|
UpDownTaskQueue.getInstance().uploadTaskQueue = []
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUploadedTask () {
|
removeUploadedTask() {
|
||||||
UpDownTaskQueue.getInstance().uploadTaskQueue = UpDownTaskQueue.getInstance().uploadTaskQueue.filter(
|
UpDownTaskQueue.getInstance().uploadTaskQueue = UpDownTaskQueue.getInstance().uploadTaskQueue.filter(
|
||||||
item =>
|
item =>
|
||||||
item.status !== uploadTaskSpecialStatus.uploaded &&
|
item.status !== uploadTaskSpecialStatus.uploaded &&
|
||||||
@@ -112,7 +112,7 @@ class UpDownTaskQueue {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
removeDownloadedTask () {
|
removeDownloadedTask() {
|
||||||
UpDownTaskQueue.getInstance().downloadTaskQueue = UpDownTaskQueue.getInstance().downloadTaskQueue.filter(
|
UpDownTaskQueue.getInstance().downloadTaskQueue = UpDownTaskQueue.getInstance().downloadTaskQueue.filter(
|
||||||
item =>
|
item =>
|
||||||
item.status !== downloadTaskSpecialStatus.downloaded &&
|
item.status !== downloadTaskSpecialStatus.downloaded &&
|
||||||
@@ -121,16 +121,16 @@ class UpDownTaskQueue {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
clearDownloadTaskQueue () {
|
clearDownloadTaskQueue() {
|
||||||
UpDownTaskQueue.getInstance().downloadTaskQueue = []
|
UpDownTaskQueue.getInstance().downloadTaskQueue = []
|
||||||
}
|
}
|
||||||
|
|
||||||
clearAllTaskQueue () {
|
clearAllTaskQueue() {
|
||||||
this.clearUploadTaskQueue()
|
this.clearUploadTaskQueue()
|
||||||
this.clearDownloadTaskQueue()
|
this.clearDownloadTaskQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
persist () {
|
persist() {
|
||||||
try {
|
try {
|
||||||
this.checkPersistPath()
|
this.checkPersistPath()
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
@@ -145,7 +145,7 @@ class UpDownTaskQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private restore () {
|
private restore() {
|
||||||
try {
|
try {
|
||||||
this.checkPersistPath()
|
this.checkPersistPath()
|
||||||
const persistData = JSON.parse(fs.readFileSync(this.persistPath, { encoding: 'utf-8' }))
|
const persistData = JSON.parse(fs.readFileSync(this.persistPath, { encoding: 'utf-8' }))
|
||||||
@@ -157,7 +157,7 @@ class UpDownTaskQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkPersistPath () {
|
private checkPersistPath() {
|
||||||
if (!fs.existsSync(this.persistPath)) {
|
if (!fs.existsSync(this.persistPath)) {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
this.persistPath,
|
this.persistPath,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
logger: ManageLogger
|
logger: ManageLogger
|
||||||
currentPicBedConfig: IPicBedMangeConfig
|
currentPicBedConfig: IPicBedMangeConfig
|
||||||
|
|
||||||
constructor (currentPicBed: string = '') {
|
constructor(currentPicBed: string = '') {
|
||||||
super()
|
super()
|
||||||
this.currentPicBed = currentPicBed || 'placeholder'
|
this.currentPicBed = currentPicBed || 'placeholder'
|
||||||
this.configPath = managePathChecker()
|
this.configPath = managePathChecker()
|
||||||
@@ -36,7 +36,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
this.currentPicBedConfig = this.getPicBedConfig(this.currentPicBed)
|
this.currentPicBedConfig = this.getPicBedConfig(this.currentPicBed)
|
||||||
}
|
}
|
||||||
|
|
||||||
getMsgParam (method: string) {
|
getMsgParam(method: string) {
|
||||||
return {
|
return {
|
||||||
class: 'ManageApi',
|
class: 'ManageApi',
|
||||||
method,
|
method,
|
||||||
@@ -44,11 +44,11 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorMsg (err: any, param: IStringKeyMap) {
|
errorMsg(err: any, param: IStringKeyMap) {
|
||||||
this.logger.error(formatError(err, param))
|
this.logger.error(formatError(err, param))
|
||||||
}
|
}
|
||||||
|
|
||||||
createClient () {
|
createClient() {
|
||||||
const name = this.currentPicBedConfig.picBedName
|
const name = this.currentPicBedConfig.picBedName
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'aliyun':
|
case 'aliyun':
|
||||||
@@ -127,11 +127,11 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPicBedConfig (picBedName: string): IPicBedMangeConfig {
|
private getPicBedConfig(picBedName: string): IPicBedMangeConfig {
|
||||||
return this.getConfig<IPicBedMangeConfig>(`picBed.${picBedName}`)
|
return this.getConfig<IPicBedMangeConfig>(`picBed.${picBedName}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
private initConfigPath (): void {
|
private initConfigPath(): void {
|
||||||
if (this.configPath === '') {
|
if (this.configPath === '') {
|
||||||
this.configPath = `${homedir()}/.piclist/manage.json`
|
this.configPath = `${homedir()}/.piclist/manage.json`
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initconfig (): void {
|
private initconfig(): void {
|
||||||
this.db = new ManageDB(this)
|
this.db = new ManageDB(this)
|
||||||
this._config = this.db.read(true) as IManageConfigType
|
this._config = this.db.read(true) as IManageConfigType
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
return get(this._config, name)
|
return get(this._config, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
saveConfig (config: IStringKeyMap): void {
|
saveConfig(config: IStringKeyMap): void {
|
||||||
if (!isInputConfigValid(config)) {
|
if (!isInputConfigValid(config)) {
|
||||||
this.logger.warn('the format of config is invalid, please provide object')
|
this.logger.warn('the format of config is invalid, please provide object')
|
||||||
return
|
return
|
||||||
@@ -167,7 +167,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
this.db.saveConfig(config)
|
this.db.saveConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
removeConfig (key: string, propName: string): void {
|
removeConfig(key: string, propName: string): void {
|
||||||
if (!key || !propName) {
|
if (!key || !propName) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
this.db.unset(key, propName)
|
this.db.unset(key, propName)
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfig (config: IStringKeyMap): void {
|
setConfig(config: IStringKeyMap): void {
|
||||||
if (!isInputConfigValid(config)) {
|
if (!isInputConfigValid(config)) {
|
||||||
this.logger.warn('the format of config is invalid, please provide object')
|
this.logger.warn('the format of config is invalid, please provide object')
|
||||||
return
|
return
|
||||||
@@ -185,12 +185,12 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsetConfig (key: string, propName: string): void {
|
unsetConfig(key: string, propName: string): void {
|
||||||
if (!key || !propName) return
|
if (!key || !propName) return
|
||||||
unset(this.getConfig(key), propName)
|
unset(this.getConfig(key), propName)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketList (param?: IStringKeyMap | undefined): Promise<any> {
|
async getBucketList(param?: IStringKeyMap | undefined): Promise<any> {
|
||||||
let client
|
let client
|
||||||
const name = this.currentPicBedConfig.picBedName.replace('plist', '')
|
const name = this.currentPicBedConfig.picBedName.replace('plist', '')
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
@@ -232,12 +232,12 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketInfo (param?: IStringKeyMap | undefined): Promise<IStringKeyMap | IManageError> {
|
async getBucketInfo(param?: IStringKeyMap | undefined): Promise<IStringKeyMap | IManageError> {
|
||||||
console.log(param)
|
console.log(param)
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketDomain (param: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
async getBucketDomain(param: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -262,7 +262,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBucket (param?: IStringKeyMap): Promise<boolean> {
|
async createBucket(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -281,32 +281,32 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucket (param?: IStringKeyMap): Promise<boolean> {
|
async deleteBucket(param?: IStringKeyMap): Promise<boolean> {
|
||||||
console.log(param)
|
console.log(param)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOperatorList (param?: IStringKeyMap): Promise<string[] | IManageError> {
|
async getOperatorList(param?: IStringKeyMap): Promise<string[] | IManageError> {
|
||||||
console.log(param)
|
console.log(param)
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
async addOperator (param?: IStringKeyMap): Promise<boolean> {
|
async addOperator(param?: IStringKeyMap): Promise<boolean> {
|
||||||
console.log(param)
|
console.log(param)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteOperator (param?: IStringKeyMap): Promise<boolean> {
|
async deleteOperator(param?: IStringKeyMap): Promise<boolean> {
|
||||||
console.log(param)
|
console.log(param)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketAclPolicy (param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
async getBucketAclPolicy(param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
||||||
console.log(param)
|
console.log(param)
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setBucketAclPolicy (param?: IStringKeyMap): Promise<boolean> {
|
async setBucketAclPolicy(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'qiniu':
|
case 'qiniu':
|
||||||
@@ -322,7 +322,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBucketListRecursively (param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
async getBucketListRecursively(param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
||||||
let client
|
let client
|
||||||
let window
|
let window
|
||||||
const defaultResult = {
|
const defaultResult = {
|
||||||
@@ -365,7 +365,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
* @param param
|
* @param param
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async getBucketListBackstage (param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
async getBucketListBackstage(param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
||||||
let client
|
let client
|
||||||
let window
|
let window
|
||||||
const defaultResult = {
|
const defaultResult = {
|
||||||
@@ -412,7 +412,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
* isDir: 是否是文件夹
|
* isDir: 是否是文件夹
|
||||||
* fileSize: 文件大小
|
* fileSize: 文件大小
|
||||||
**/
|
**/
|
||||||
async getBucketFileList (param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
async getBucketFileList(param?: IStringKeyMap): Promise<IStringKeyMap | IManageError> {
|
||||||
const defaultResponse = {
|
const defaultResponse = {
|
||||||
fullList: [] as any,
|
fullList: [] as any,
|
||||||
isTruncated: false,
|
isTruncated: false,
|
||||||
@@ -439,7 +439,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFile (param?: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFile(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -466,7 +466,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBucketFolder (param?: IStringKeyMap): Promise<boolean> {
|
async deleteBucketFolder(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -490,7 +490,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async renameBucketFile (param?: IStringKeyMap): Promise<boolean> {
|
async renameBucketFile(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -513,7 +513,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadBucketFile (param?: IStringKeyMap): Promise<boolean> {
|
async downloadBucketFile(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -540,12 +540,12 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async copyMoveBucketFile (param?: IStringKeyMap): Promise<boolean> {
|
async copyMoveBucketFile(param?: IStringKeyMap): Promise<boolean> {
|
||||||
console.log(param)
|
console.log(param)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBucketFolder (param?: IStringKeyMap): Promise<boolean> {
|
async createBucketFolder(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -569,7 +569,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadBucketFile (param?: IStringKeyMap): Promise<boolean> {
|
async uploadBucketFile(param?: IStringKeyMap): Promise<boolean> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
@@ -595,7 +595,7 @@ export class ManageApi extends EventEmitter implements IManageApiType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPreSignedUrl (param?: IStringKeyMap): Promise<string> {
|
async getPreSignedUrl(param?: IStringKeyMap): Promise<string> {
|
||||||
let client
|
let client
|
||||||
switch (this.currentPicBedConfig.picBedName) {
|
switch (this.currentPicBedConfig.picBedName) {
|
||||||
case 'tcyun':
|
case 'tcyun':
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export const getFSFile = async (filePath: string, stream: boolean = false): Prom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInputConfigValid (config: any): boolean {
|
export function isInputConfigValid(config: any): boolean {
|
||||||
return typeof config === 'object' && !Array.isArray(config) && Object.keys(config).length > 0
|
return typeof config === 'object' && !Array.isArray(config) && Object.keys(config).length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +280,7 @@ export const getInnerAgent = (proxy: any, sslEnabled: boolean = true) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOptions (
|
export function getOptions(
|
||||||
method?: string,
|
method?: string,
|
||||||
headers?: IStringKeyMap,
|
headers?: IStringKeyMap,
|
||||||
searchParams?: IStringKeyMap,
|
searchParams?: IStringKeyMap,
|
||||||
@@ -309,14 +309,14 @@ export class ConcurrencyPromisePool {
|
|||||||
runningNum: number
|
runningNum: number
|
||||||
results: any[]
|
results: any[]
|
||||||
|
|
||||||
constructor (limit: number) {
|
constructor(limit: number) {
|
||||||
this.limit = limit
|
this.limit = limit
|
||||||
this.queue = []
|
this.queue = []
|
||||||
this.runningNum = 0
|
this.runningNum = 0
|
||||||
this.results = []
|
this.results = []
|
||||||
}
|
}
|
||||||
|
|
||||||
all (promises: any[] = []) {
|
all(promises: any[] = []) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
for (const promise of promises) {
|
for (const promise of promises) {
|
||||||
this._run(promise, resolve, reject)
|
this._run(promise, resolve, reject)
|
||||||
@@ -324,7 +324,7 @@ export class ConcurrencyPromisePool {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_run (promise: any, resolve: any, reject: any) {
|
_run(promise: any, resolve: any, reject: any) {
|
||||||
if (this.runningNum >= this.limit) {
|
if (this.runningNum >= this.limit) {
|
||||||
this.queue.push(promise)
|
this.queue.push(promise)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export interface DogecloudToken {
|
|||||||
sessionToken: string
|
sessionToken: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function dogecloudApi (
|
export async function dogecloudApi(
|
||||||
apiPath: string,
|
apiPath: string,
|
||||||
data = {},
|
data = {},
|
||||||
jsonMode: boolean = false,
|
jsonMode: boolean = false,
|
||||||
@@ -45,7 +45,7 @@ export async function dogecloudApi (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTempToken (accessKey: string, secretKey: string): Promise<IObj | DogecloudToken> {
|
export async function getTempToken(accessKey: string, secretKey: string): Promise<IObj | DogecloudToken> {
|
||||||
const dogeTempToken = (await picgo.getConfig('Credentials.doge-token')) || ({} as any)
|
const dogeTempToken = (await picgo.getConfig('Credentials.doge-token')) || ({} as any)
|
||||||
if (dogeTempToken.token && dogeTempToken.expires > Date.now() + 7200000) {
|
if (dogeTempToken.token && dogeTempToken.expires > Date.now() + 7200000) {
|
||||||
return dogeTempToken.token
|
return dogeTempToken.token
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ export class ManageLogger implements ILogger {
|
|||||||
#logLevel!: string
|
#logLevel!: string
|
||||||
#logPath!: string
|
#logPath!: string
|
||||||
|
|
||||||
constructor (ctx: IManageApiType) {
|
constructor(ctx: IManageApiType) {
|
||||||
this.#ctx = ctx
|
this.#ctx = ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
#handleLog (type: string, ...msg: ILogArgvTypeWithError[]): void {
|
#handleLog(type: string, ...msg: ILogArgvTypeWithError[]): void {
|
||||||
const logHeader = chalk[this.#level[type] as ILogColor](`[PicList ${type.toUpperCase()}]`)
|
const logHeader = chalk[this.#level[type] as ILogColor](`[PicList ${type.toUpperCase()}]`)
|
||||||
console.log(logHeader, ...msg)
|
console.log(logHeader, ...msg)
|
||||||
this.#logLevel = this.#ctx.getConfig(configPaths.settings.logLevel)
|
this.#logLevel = this.#ctx.getConfig(configPaths.settings.logLevel)
|
||||||
@@ -53,7 +53,7 @@ export class ManageLogger implements ILogger {
|
|||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#checkLogFileIsLarge (logPath: string): {
|
#checkLogFileIsLarge(logPath: string): {
|
||||||
isLarge: boolean
|
isLarge: boolean
|
||||||
logFileSize?: number
|
logFileSize?: number
|
||||||
logFileSizeLimit?: number
|
logFileSizeLimit?: number
|
||||||
@@ -76,14 +76,14 @@ export class ManageLogger implements ILogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#recreateLogFile (logPath: string): void {
|
#recreateLogFile(logPath: string): void {
|
||||||
if (fs.existsSync(logPath)) {
|
if (fs.existsSync(logPath)) {
|
||||||
fs.unlinkSync(logPath)
|
fs.unlinkSync(logPath)
|
||||||
fs.createFileSync(logPath)
|
fs.createFileSync(logPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#handleWriteLog (logPath: string, type: string, ...msg: ILogArgvTypeWithError[]): void {
|
#handleWriteLog(logPath: string, type: string, ...msg: ILogArgvTypeWithError[]): void {
|
||||||
try {
|
try {
|
||||||
if (this.#checkLogLevel(type, this.#logLevel)) {
|
if (this.#checkLogLevel(type, this.#logLevel)) {
|
||||||
let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicList ${type.toUpperCase()}] `
|
let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicList ${type.toUpperCase()}] `
|
||||||
@@ -98,7 +98,7 @@ export class ManageLogger implements ILogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#formatLogItem (item: ILogArgvTypeWithError, type: string): string {
|
#formatLogItem(item: ILogArgvTypeWithError, type: string): string {
|
||||||
let result = ''
|
let result = ''
|
||||||
if (item instanceof Error && type === 'error') {
|
if (item instanceof Error && type === 'error') {
|
||||||
result += `\n------Error Stack Begin------\n${util.format(item?.stack)}\n-------Error Stack End------- `
|
result += `\n------Error Stack Begin------\n${util.format(item?.stack)}\n-------Error Stack End------- `
|
||||||
@@ -114,7 +114,7 @@ export class ManageLogger implements ILogger {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
#checkLogLevel (type: string, level: undefined | string | string[]): boolean {
|
#checkLogLevel(type: string, level: undefined | string | string[]): boolean {
|
||||||
if (level === undefined || level === 'all') {
|
if (level === undefined || level === 'all') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -124,23 +124,23 @@ export class ManageLogger implements ILogger {
|
|||||||
return type === level
|
return type === level
|
||||||
}
|
}
|
||||||
|
|
||||||
success (...msq: ILogArgvType[]): void {
|
success(...msq: ILogArgvType[]): void {
|
||||||
return this.#handleLog(ILogType.success, ...msq)
|
return this.#handleLog(ILogType.success, ...msq)
|
||||||
}
|
}
|
||||||
|
|
||||||
info (...msq: ILogArgvType[]): void {
|
info(...msq: ILogArgvType[]): void {
|
||||||
return this.#handleLog(ILogType.info, ...msq)
|
return this.#handleLog(ILogType.info, ...msq)
|
||||||
}
|
}
|
||||||
|
|
||||||
error (...msq: ILogArgvTypeWithError[]): void {
|
error(...msq: ILogArgvTypeWithError[]): void {
|
||||||
return this.#handleLog(ILogType.error, ...msq)
|
return this.#handleLog(ILogType.error, ...msq)
|
||||||
}
|
}
|
||||||
|
|
||||||
warn (...msq: ILogArgvType[]): void {
|
warn(...msq: ILogArgvType[]): void {
|
||||||
return this.#handleLog(ILogType.warn, ...msq)
|
return this.#handleLog(ILogType.warn, ...msq)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug (...msq: ILogArgvType[]): void {
|
debug(...msq: ILogArgvType[]): void {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
this.#handleLog(ILogType.info, ...msq)
|
this.#handleLog(ILogType.info, ...msq)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ class Server {
|
|||||||
#httpServer: http.Server
|
#httpServer: http.Server
|
||||||
#config: IServerConfig
|
#config: IServerConfig
|
||||||
|
|
||||||
constructor () {
|
constructor() {
|
||||||
this.#config = this.getConfigWithDefaults()
|
this.#config = this.getConfigWithDefaults()
|
||||||
this.#httpServer = http.createServer(this.#handleRequest)
|
this.#httpServer = http.createServer(this.#handleRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfigWithDefaults () {
|
getConfigWithDefaults() {
|
||||||
let config = picgo.getConfig<IServerConfig>(configPaths.settings.server)
|
let config = picgo.getConfig<IServerConfig>(configPaths.settings.server)
|
||||||
if (!this.#isValidConfig(config)) {
|
if (!this.#isValidConfig(config)) {
|
||||||
config = { port: DEFAULT_PORT, host: DEFAULT_HOST, enable: true }
|
config = { port: DEFAULT_PORT, host: DEFAULT_HOST, enable: true }
|
||||||
@@ -55,7 +55,7 @@ class Server {
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
#isValidConfig (config: IObj | undefined) {
|
#isValidConfig(config: IObj | undefined) {
|
||||||
return config && config.port && config.host && config.enable !== undefined
|
return config && config.port && config.host && config.enable !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,20 +198,20 @@ class Server {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
startup () {
|
startup() {
|
||||||
if (this.#config.enable) {
|
if (this.#config.enable) {
|
||||||
this.#listen(this.#config.port)
|
this.#listen(this.#config.port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown (hasStarted?: boolean) {
|
shutdown(hasStarted?: boolean) {
|
||||||
this.#httpServer.close()
|
this.#httpServer.close()
|
||||||
if (!hasStarted) {
|
if (!hasStarted) {
|
||||||
logger.info('[PicList Server] shutdown')
|
logger.info('[PicList Server] shutdown')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
restart () {
|
restart() {
|
||||||
this.shutdown()
|
this.shutdown()
|
||||||
this.#config = this.getConfigWithDefaults()
|
this.#config = this.getConfigWithDefaults()
|
||||||
this.startup()
|
this.startup()
|
||||||
|
|||||||
@@ -5,27 +5,27 @@ type HttpMethod = 'GET' | 'POST'
|
|||||||
class Router {
|
class Router {
|
||||||
#router = new Map<string, Map<HttpMethod, { handler: routeHandler; urlparams?: URLSearchParams }>>()
|
#router = new Map<string, Map<HttpMethod, { handler: routeHandler; urlparams?: URLSearchParams }>>()
|
||||||
|
|
||||||
#addRoute (method: HttpMethod, url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
#addRoute(method: HttpMethod, url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
||||||
if (!this.#router.has(url)) {
|
if (!this.#router.has(url)) {
|
||||||
this.#router.set(url, new Map())
|
this.#router.set(url, new Map())
|
||||||
}
|
}
|
||||||
this.#router.get(url)!.set(method, { handler: callback, urlparams })
|
this.#router.get(url)!.set(method, { handler: callback, urlparams })
|
||||||
}
|
}
|
||||||
|
|
||||||
get (url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
get(url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
||||||
this.#addRoute('GET', url, callback, urlparams)
|
this.#addRoute('GET', url, callback, urlparams)
|
||||||
}
|
}
|
||||||
|
|
||||||
post (url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
post(url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
||||||
this.#addRoute('POST', url, callback, urlparams)
|
this.#addRoute('POST', url, callback, urlparams)
|
||||||
}
|
}
|
||||||
|
|
||||||
any (url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
any(url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
|
||||||
this.#addRoute('GET', url, callback, urlparams)
|
this.#addRoute('GET', url, callback, urlparams)
|
||||||
this.#addRoute('POST', url, callback, urlparams)
|
this.#addRoute('POST', url, callback, urlparams)
|
||||||
}
|
}
|
||||||
|
|
||||||
getHandler (url: string, method: HttpMethod) {
|
getHandler(url: string, method: HttpMethod) {
|
||||||
if (this.#router.has(url)) {
|
if (this.#router.has(url)) {
|
||||||
const methods = this.#router.get(url)!
|
const methods = this.#router.get(url)!
|
||||||
if (methods.has(method)) {
|
if (methods.has(method)) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const LOG_PATH = path.join(STORE_PATH, 'piclist.log')
|
|||||||
const errorMessage = `upload error. see ${LOG_PATH} for more detail.`
|
const errorMessage = `upload error. see ${LOG_PATH} for more detail.`
|
||||||
const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.`
|
const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.`
|
||||||
|
|
||||||
async function responseForGet ({ response }: { response: http.ServerResponse }) {
|
async function responseForGet({ response }: { response: http.ServerResponse }) {
|
||||||
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
|
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
|
||||||
const htmlContent = marked(markdownContent)
|
const htmlContent = marked(markdownContent)
|
||||||
response.write(htmlContent)
|
response.write(htmlContent)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { configPaths } from '~/utils/configPaths'
|
|||||||
|
|
||||||
const defaultPath = process.platform === 'win32' ? 'C:\\Users' : '/'
|
const defaultPath = process.platform === 'win32' ? 'C:\\Users' : '/'
|
||||||
|
|
||||||
function generateDirectoryListingHtml (files: any[], requestPath: any) {
|
function generateDirectoryListingHtml(files: any[], requestPath: any) {
|
||||||
let html = '<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><h1>Directory Listing</h1><ul>'
|
let html = '<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><h1>Directory Listing</h1><ul>'
|
||||||
files.forEach((file: string) => {
|
files.forEach((file: string) => {
|
||||||
const filePath = path.join(requestPath, file)
|
const filePath = path.join(requestPath, file)
|
||||||
@@ -21,7 +21,7 @@ function generateDirectoryListingHtml (files: any[], requestPath: any) {
|
|||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
function serveDirectory (res: http.ServerResponse, filePath: fs.PathLike, requestPath: any) {
|
function serveDirectory(res: http.ServerResponse, filePath: fs.PathLike, requestPath: any) {
|
||||||
fs.readdir(filePath, (err, files) => {
|
fs.readdir(filePath, (err, files) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.writeHead(500)
|
res.writeHead(500)
|
||||||
@@ -33,7 +33,7 @@ function serveDirectory (res: http.ServerResponse, filePath: fs.PathLike, reques
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function serveFile (res: http.ServerResponse, filePath: fs.PathLike) {
|
function serveFile(res: http.ServerResponse, filePath: fs.PathLike) {
|
||||||
const readStream = fs.createReadStream(filePath)
|
const readStream = fs.createReadStream(filePath)
|
||||||
readStream.pipe(res)
|
readStream.pipe(res)
|
||||||
readStream.on('error', () => {
|
readStream.on('error', () => {
|
||||||
@@ -46,12 +46,12 @@ class WebServer {
|
|||||||
#server!: http.Server
|
#server!: http.Server
|
||||||
#config!: IStringKeyMap
|
#config!: IStringKeyMap
|
||||||
|
|
||||||
constructor () {
|
constructor() {
|
||||||
this.loadConfig()
|
this.loadConfig()
|
||||||
this.initServer()
|
this.initServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfig (): void {
|
loadConfig(): void {
|
||||||
this.#config = {
|
this.#config = {
|
||||||
enableWebServer: picgo.getConfig<boolean>(configPaths.settings.enableWebServer) || false,
|
enableWebServer: picgo.getConfig<boolean>(configPaths.settings.enableWebServer) || false,
|
||||||
webServerHost: picgo.getConfig<string>(configPaths.settings.webServerHost) || '0.0.0.0',
|
webServerHost: picgo.getConfig<string>(configPaths.settings.webServerHost) || '0.0.0.0',
|
||||||
@@ -60,7 +60,7 @@ class WebServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initServer (): void {
|
initServer(): void {
|
||||||
this.#server = http.createServer((req, res) => {
|
this.#server = http.createServer((req, res) => {
|
||||||
const requestPath = req.url?.split('?')[0]
|
const requestPath = req.url?.split('?')[0]
|
||||||
const filePath = path.join(this.#config.webServerPath, decodeURIComponent(requestPath || ''))
|
const filePath = path.join(this.#config.webServerPath, decodeURIComponent(requestPath || ''))
|
||||||
@@ -79,7 +79,7 @@ class WebServer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
start () {
|
start() {
|
||||||
if (this.#config.enableWebServer) {
|
if (this.#config.enableWebServer) {
|
||||||
this.#server
|
this.#server
|
||||||
.listen(
|
.listen(
|
||||||
@@ -99,13 +99,13 @@ class WebServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stop () {
|
stop() {
|
||||||
this.#server.close(() => {
|
this.#server.close(() => {
|
||||||
logger.info('Web server is stopped')
|
logger.info('Web server is stopped')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
restart () {
|
restart() {
|
||||||
this.stop()
|
this.stop()
|
||||||
this.loadConfig()
|
this.loadConfig()
|
||||||
this.initServer()
|
this.initServer()
|
||||||
|
|||||||
@@ -17,39 +17,27 @@ export class AESHelper {
|
|||||||
|
|
||||||
readonly key: Buffer
|
readonly key: Buffer
|
||||||
|
|
||||||
constructor (password?: string) {
|
constructor(password?: string) {
|
||||||
const pwd =
|
const pwd = password ?? picgo.getConfig<string>(configPaths.settings.aesPassword) ?? 'aesPassword'
|
||||||
password ??
|
|
||||||
picgo.getConfig<string>(configPaths.settings.aesPassword) ??
|
|
||||||
'aesPassword'
|
|
||||||
this.key = AESHelper.#deriveKey(pwd)
|
this.key = AESHelper.#deriveKey(pwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static #deriveKey (password: string): Buffer {
|
static #deriveKey(password: string): Buffer {
|
||||||
const cached = this.#keyCache.get(password)
|
const cached = this.#keyCache.get(password)
|
||||||
if (cached) return cached
|
if (cached) return cached
|
||||||
const key = crypto.pbkdf2Sync(
|
const key = crypto.pbkdf2Sync(password, this.#SALT, this.#ITERATIONS, this.#KEYLEN, this.#DIGEST)
|
||||||
password,
|
|
||||||
this.#SALT,
|
|
||||||
this.#ITERATIONS,
|
|
||||||
this.#KEYLEN,
|
|
||||||
this.#DIGEST
|
|
||||||
)
|
|
||||||
this.#keyCache.set(password, key)
|
this.#keyCache.set(password, key)
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
encrypt (plainText: string): string {
|
encrypt(plainText: string): string {
|
||||||
const iv = crypto.randomBytes(AESHelper.#IV_LENGTH)
|
const iv = crypto.randomBytes(AESHelper.#IV_LENGTH)
|
||||||
const cipher = crypto.createCipheriv(AESHelper.#ALGO, this.key, iv)
|
const cipher = crypto.createCipheriv(AESHelper.#ALGO, this.key, iv)
|
||||||
const encrypted = Buffer.concat([
|
const encrypted = Buffer.concat([cipher.update(plainText, 'utf8'), cipher.final()])
|
||||||
cipher.update(plainText, 'utf8'),
|
|
||||||
cipher.final()
|
|
||||||
])
|
|
||||||
return `${iv.toString('hex')}${AESHelper.#SEP}${encrypted.toString('hex')}`
|
return `${iv.toString('hex')}${AESHelper.#SEP}${encrypted.toString('hex')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt (encryptedData: string): string {
|
decrypt(encryptedData: string): string {
|
||||||
if (!encryptedData) return '{}'
|
if (!encryptedData) return '{}'
|
||||||
|
|
||||||
const sepIndex = encryptedData.indexOf(AESHelper.#SEP)
|
const sepIndex = encryptedData.indexOf(AESHelper.#SEP)
|
||||||
@@ -63,10 +51,7 @@ export class AESHelper {
|
|||||||
if (iv.length !== AESHelper.#IV_LENGTH) return '{}'
|
if (iv.length !== AESHelper.#IV_LENGTH) return '{}'
|
||||||
|
|
||||||
const decipher = crypto.createDecipheriv(AESHelper.#ALGO, this.key, iv)
|
const decipher = crypto.createDecipheriv(AESHelper.#ALGO, this.key, iv)
|
||||||
const decrypted = Buffer.concat([
|
const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedHex, 'hex')), decipher.final()])
|
||||||
decipher.update(Buffer.from(encryptedHex, 'hex')),
|
|
||||||
decipher.final()
|
|
||||||
])
|
|
||||||
return decrypted.toString('utf8')
|
return decrypted.toString('utf8')
|
||||||
} catch {
|
} catch {
|
||||||
return '{}'
|
return '{}'
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const configPath = dbPathChecker()
|
|||||||
const CONFIG_DIR = path.dirname(configPath)
|
const CONFIG_DIR = path.dirname(configPath)
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
function beforeOpen () {
|
function beforeOpen() {
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
resolveMacWorkFlow()
|
resolveMacWorkFlow()
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ function beforeOpen () {
|
|||||||
resolveOtherI18nFiles()
|
resolveOtherI18nFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyFileOutsideOfElectronAsar (sourceInAsarArchive: string, destOutsideAsarArchive: string) {
|
function copyFileOutsideOfElectronAsar(sourceInAsarArchive: string, destOutsideAsarArchive: string) {
|
||||||
if (fs.existsSync(sourceInAsarArchive)) {
|
if (fs.existsSync(sourceInAsarArchive)) {
|
||||||
// file will be copied
|
// file will be copied
|
||||||
if (fs.statSync(sourceInAsarArchive).isFile()) {
|
if (fs.statSync(sourceInAsarArchive).isFile()) {
|
||||||
@@ -45,16 +45,21 @@ function copyFileOutsideOfElectronAsar (sourceInAsarArchive: string, destOutside
|
|||||||
/**
|
/**
|
||||||
* macOS 右键菜单
|
* macOS 右键菜单
|
||||||
*/
|
*/
|
||||||
function resolveMacWorkFlow () {
|
function resolveMacWorkFlow() {
|
||||||
const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow`
|
const dest = `${os.homedir()}/Library/Services/Upload pictures with PicList.workflow`
|
||||||
try {
|
try {
|
||||||
copyFileOutsideOfElectronAsar(path.join(__dirname, '../../resources', 'Upload pictures with PicList.workflow').replace('app.asar', 'app.asar.unpacked'), dest)
|
copyFileOutsideOfElectronAsar(
|
||||||
|
path
|
||||||
|
.join(__dirname, '../../resources', 'Upload pictures with PicList.workflow')
|
||||||
|
.replace('app.asar', 'app.asar.unpacked'),
|
||||||
|
dest
|
||||||
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function diffFilesAndUpdate (filePath1: string, filePath2: string) {
|
function diffFilesAndUpdate(filePath1: string, filePath2: string) {
|
||||||
try {
|
try {
|
||||||
const file1 = fs.existsSync(filePath1) && fs.readFileSync(filePath1)
|
const file1 = fs.existsSync(filePath1) && fs.readFileSync(filePath1)
|
||||||
const file2 = fs.existsSync(filePath1) && fs.readFileSync(filePath2)
|
const file2 = fs.existsSync(filePath1) && fs.readFileSync(filePath2)
|
||||||
@@ -71,7 +76,7 @@ function diffFilesAndUpdate (filePath1: string, filePath2: string) {
|
|||||||
/**
|
/**
|
||||||
* 初始化剪贴板生成图片的脚本
|
* 初始化剪贴板生成图片的脚本
|
||||||
*/
|
*/
|
||||||
function resolveClipboardImageGenerator () {
|
function resolveClipboardImageGenerator() {
|
||||||
const clipboardFiles = getClipboardFiles()
|
const clipboardFiles = getClipboardFiles()
|
||||||
if (!fs.pathExistsSync(path.join(CONFIG_DIR, 'windows10.ps1'))) {
|
if (!fs.pathExistsSync(path.join(CONFIG_DIR, 'windows10.ps1'))) {
|
||||||
clipboardFiles.forEach(item => {
|
clipboardFiles.forEach(item => {
|
||||||
@@ -84,7 +89,7 @@ function resolveClipboardImageGenerator () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getClipboardFiles () {
|
function getClipboardFiles() {
|
||||||
const files = ['linux.sh', 'mac.applescript', 'windows.ps1', 'windows10.ps1', 'wsl.sh']
|
const files = ['linux.sh', 'mac.applescript', 'windows.ps1', 'windows10.ps1', 'wsl.sh']
|
||||||
|
|
||||||
return files.map(item => {
|
return files.map(item => {
|
||||||
@@ -99,7 +104,7 @@ function resolveClipboardImageGenerator () {
|
|||||||
/**
|
/**
|
||||||
* 初始化其他语言文件
|
* 初始化其他语言文件
|
||||||
*/
|
*/
|
||||||
function resolveOtherI18nFiles () {
|
function resolveOtherI18nFiles() {
|
||||||
const i18nFolder = path.join(CONFIG_DIR, 'i18n')
|
const i18nFolder = path.join(CONFIG_DIR, 'i18n')
|
||||||
if (!fs.pathExistsSync(i18nFolder)) {
|
if (!fs.pathExistsSync(i18nFolder)) {
|
||||||
fs.mkdirSync(i18nFolder)
|
fs.mkdirSync(i18nFolder)
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ class ClipboardWatcher extends EventEmitter {
|
|||||||
timer: NodeJS.Timeout | null
|
timer: NodeJS.Timeout | null
|
||||||
lastImageHash: string | null
|
lastImageHash: string | null
|
||||||
|
|
||||||
constructor () {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.lastImageHash = null
|
this.lastImageHash = null
|
||||||
this.timer = null
|
this.timer = null
|
||||||
}
|
}
|
||||||
|
|
||||||
startListening (watchDelay = 1000) {
|
startListening(watchDelay = 1000) {
|
||||||
this.stopListening(false)
|
this.stopListening(false)
|
||||||
|
|
||||||
this.timer = setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
@@ -34,7 +34,7 @@ class ClipboardWatcher extends EventEmitter {
|
|||||||
logger.info('Start to watch clipboard')
|
logger.info('Start to watch clipboard')
|
||||||
}
|
}
|
||||||
|
|
||||||
stopListening (isLog = true) {
|
stopListening(isLog = true) {
|
||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer)
|
||||||
this.timer = null
|
this.timer = null
|
||||||
@@ -43,7 +43,7 @@ class ClipboardWatcher extends EventEmitter {
|
|||||||
isLog && logger.info('Stop to watch clipboard')
|
isLog && logger.info('Stop to watch clipboard')
|
||||||
}
|
}
|
||||||
|
|
||||||
getImageHash (image: NativeImage): string {
|
getImageHash(image: NativeImage): string {
|
||||||
const buffer = image.toBitmap()
|
const buffer = image.toBitmap()
|
||||||
return crypto.createHash('md5').update(buffer).digest('hex')
|
return crypto.createHash('md5').update(buffer).digest('hex')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const setTray = (t: Tray) => {
|
|||||||
|
|
||||||
export const getTray = () => tray
|
export const getTray = () => tray
|
||||||
|
|
||||||
export function setTrayToolTip (title: string): void {
|
export function setTrayToolTip(title: string): void {
|
||||||
if (tray) {
|
if (tray) {
|
||||||
tray.setToolTip(title)
|
tray.setToolTip(title)
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,7 @@ export const formatHttpProxy = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function encodeFilePath (filePath: string) {
|
export function encodeFilePath(filePath: string) {
|
||||||
return filePath.replace(/\\/g, '/').split('/').map(encodeURIComponent).join('/')
|
return filePath.replace(/\\/g, '/').split('/').map(encodeURIComponent).join('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,24 @@
|
|||||||
import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
||||||
|
|
||||||
import type { IAliYunConfig, IAwsS3PListUserConfig, IGitHubConfig, IImgurConfig, ILocalConfig, ILskyConfig, IPicBedType, IQiniuConfig, IServerConfig, ISftpPlistConfig, IShortKeyConfig, ISMMSConfig, ISyncConfig, ITcYunConfig, IUploaderConfig, IUpYunConfig, IWebdavPlistConfig } from '#/types/types'
|
import type {
|
||||||
|
IAliYunConfig,
|
||||||
|
IAwsS3PListUserConfig,
|
||||||
|
IGitHubConfig,
|
||||||
|
IImgurConfig,
|
||||||
|
ILocalConfig,
|
||||||
|
ILskyConfig,
|
||||||
|
IPicBedType,
|
||||||
|
IQiniuConfig,
|
||||||
|
IServerConfig,
|
||||||
|
ISftpPlistConfig,
|
||||||
|
IShortKeyConfig,
|
||||||
|
ISMMSConfig,
|
||||||
|
ISyncConfig,
|
||||||
|
ITcYunConfig,
|
||||||
|
IUploaderConfig,
|
||||||
|
IUpYunConfig,
|
||||||
|
IWebdavPlistConfig
|
||||||
|
} from '#/types/types'
|
||||||
|
|
||||||
export type manualPageOpenType = 'window' | 'browser'
|
export type manualPageOpenType = 'window' | 'browser'
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const dogeRegionMap: IStringKeyMap = {
|
|||||||
'ap-chengdu': '3'
|
'ap-chengdu': '3'
|
||||||
}
|
}
|
||||||
|
|
||||||
async function dogecloudApi (
|
async function dogecloudApi(
|
||||||
apiPath: string,
|
apiPath: string,
|
||||||
data = {},
|
data = {},
|
||||||
jsonMode: boolean = false,
|
jsonMode: boolean = false,
|
||||||
@@ -69,7 +69,7 @@ async function dogecloudApi (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getDogeToken (accessKey: string, secretKey: string): Promise<IObj | DogecloudTokenFull> {
|
async function getDogeToken(accessKey: string, secretKey: string): Promise<IObj | DogecloudTokenFull> {
|
||||||
try {
|
try {
|
||||||
const data = await dogecloudApi(
|
const data = await dogecloudApi(
|
||||||
'/auth/tmp_token.json',
|
'/auth/tmp_token.json',
|
||||||
@@ -88,7 +88,7 @@ async function getDogeToken (accessKey: string, secretKey: string): Promise<IObj
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode: boolean = false) {
|
export async function removeFileFromS3InMain(configMap: IStringKeyMap, dogeMode: boolean = false) {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
url: rawUrl,
|
url: rawUrl,
|
||||||
@@ -145,21 +145,21 @@ export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode
|
|||||||
const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {}
|
const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {}
|
||||||
const handler = sslEnabled
|
const handler = sslEnabled
|
||||||
? new NodeHttpHandler({
|
? new NodeHttpHandler({
|
||||||
httpsAgent: agent.https
|
httpsAgent: agent.https
|
||||||
? agent.https
|
? agent.https
|
||||||
: new https.Agent({
|
: new https.Agent({
|
||||||
...commonOptions,
|
...commonOptions,
|
||||||
...extraOptions
|
...extraOptions
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
: new NodeHttpHandler({
|
: new NodeHttpHandler({
|
||||||
httpAgent: agent.http
|
httpAgent: agent.http
|
||||||
? agent.http
|
? agent.http
|
||||||
: new http.Agent({
|
: new http.Agent({
|
||||||
...commonOptions,
|
...commonOptions,
|
||||||
...extraOptions
|
...extraOptions
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const s3Options: S3ClientConfig = {
|
const s3Options: S3ClientConfig = {
|
||||||
credentials: {
|
credentials: {
|
||||||
accessKeyId: accessKeyID,
|
accessKeyId: accessKeyID,
|
||||||
@@ -205,7 +205,7 @@ export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeFileFromDogeInMain (configMap: IStringKeyMap) {
|
export async function removeFileFromDogeInMain(configMap: IStringKeyMap) {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
config: { bucketName, AccessKey, SecretKey }
|
config: { bucketName, AccessKey, SecretKey }
|
||||||
@@ -229,7 +229,7 @@ export async function removeFileFromDogeInMain (configMap: IStringKeyMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createHuaweiAuthorization (
|
function createHuaweiAuthorization(
|
||||||
bucketName: string,
|
bucketName: string,
|
||||||
path: string,
|
path: string,
|
||||||
fileName: string,
|
fileName: string,
|
||||||
@@ -242,7 +242,7 @@ function createHuaweiAuthorization (
|
|||||||
return `OBS ${accessKey}:${singature}`
|
return `OBS ${accessKey}:${singature}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
|
export async function removeFileFromHuaweiInMain(configMap: IStringKeyMap) {
|
||||||
const { fileName, config } = configMap
|
const { fileName, config } = configMap
|
||||||
const { accessKeyId, accessKeySecret, bucketName, endpoint } = config
|
const { accessKeyId, accessKeySecret, bucketName, endpoint } = config
|
||||||
let path = config.path || '/'
|
let path = config.path || '/'
|
||||||
@@ -268,7 +268,7 @@ export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileName: string) {
|
export async function removeFileFromSFTPInMain(config: ISftpPlistConfig, fileName: string) {
|
||||||
try {
|
try {
|
||||||
const client = SSHClient.instance
|
const client = SSHClient.instance
|
||||||
await client.connect(config)
|
await client.connect(config)
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ const AUTH_KEY_VALUE_RE = /(\w+)=["']?([^'"]{1,10000})["']?/
|
|||||||
let NC = 0
|
let NC = 0
|
||||||
const NC_PAD = '00000000'
|
const NC_PAD = '00000000'
|
||||||
|
|
||||||
function md5 (text: crypto.BinaryLike) {
|
function md5(text: crypto.BinaryLike) {
|
||||||
return crypto.createHash('md5').update(text).digest('hex')
|
return crypto.createHash('md5').update(text).digest('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function digestAuthHeader (
|
export function digestAuthHeader(
|
||||||
method: string,
|
method: string,
|
||||||
uri: string,
|
uri: string,
|
||||||
wwwAuthenticate: string,
|
wwwAuthenticate: string,
|
||||||
@@ -70,7 +70,7 @@ export function digestAuthHeader (
|
|||||||
return authstring
|
return authstring
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAuthHeader (method: string, host: string, uri: string, username: string, password: string) {
|
export async function getAuthHeader(method: string, host: string, uri: string, username: string, password: string) {
|
||||||
try {
|
try {
|
||||||
await axios.get(`${host}${uri}`)
|
await axios.get(`${host}${uri}`)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const parseVersion = (plist: string) => {
|
|||||||
return matches[1].replace('10.16', '11')
|
return matches[1].replace('10.16', '11')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function macOSVersion (): string {
|
export function macOSVersion(): string {
|
||||||
if (!isMacOS) return ''
|
if (!isMacOS) return ''
|
||||||
|
|
||||||
if (!version) {
|
if (!version) {
|
||||||
@@ -43,7 +43,7 @@ if (process.env.NODE_ENV === 'test') {
|
|||||||
macOSVersion._parseVersion = parseVersion
|
macOSVersion._parseVersion = parseVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMacOSVersion (semverRange: string) {
|
export function isMacOSVersion(semverRange: string) {
|
||||||
if (!isMacOS) {
|
if (!isMacOS) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ export function isMacOSVersion (semverRange: string) {
|
|||||||
return semver.satisfies(macOSVersion(), clean(semverRange))
|
return semver.satisfies(macOSVersion(), clean(semverRange))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMacOSVersionGreaterThanOrEqualTo (version: string) {
|
export function isMacOSVersionGreaterThanOrEqualTo(version: string) {
|
||||||
if (!isMacOS) {
|
if (!isMacOS) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ export function isMacOSVersionGreaterThanOrEqualTo (version: string) {
|
|||||||
return semver.gte(macOSVersion(), clean(version))
|
return semver.gte(macOSVersion(), clean(version))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertMacOSVersion (semverRange: string) {
|
export function assertMacOSVersion(semverRange: string) {
|
||||||
semverRange = semverRange.replace('10.16', '11')
|
semverRange = semverRange.replace('10.16', '11')
|
||||||
|
|
||||||
if (!isMacOSVersion(semverRange)) {
|
if (!isMacOSVersion(semverRange)) {
|
||||||
@@ -71,7 +71,7 @@ export function assertMacOSVersion (semverRange: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertMacOSVersionGreaterThanOrEqualTo (version: string) {
|
export function assertMacOSVersionGreaterThanOrEqualTo(version: string) {
|
||||||
version = version.replace('10.16', '11')
|
version = version.replace('10.16', '11')
|
||||||
|
|
||||||
if (!isMacOSVersionGreaterThanOrEqualTo(version)) {
|
if (!isMacOSVersionGreaterThanOrEqualTo(version)) {
|
||||||
@@ -79,7 +79,7 @@ export function assertMacOSVersionGreaterThanOrEqualTo (version: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertMacOS () {
|
export function assertMacOS() {
|
||||||
if (!isMacOS) {
|
if (!isMacOS) {
|
||||||
throw new Error('Requires macOS')
|
throw new Error('Requires macOS')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import picgo from '@core/picgo'
|
import picgo from '@core/picgo'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
|
|
||||||
import type { IPicGoPluginConfig, IPicGoPluginOriginConfig, IStringKeyMap, IUploaderConfigItem, IUploaderConfigListItem } from '#/types/types'
|
import type {
|
||||||
|
IPicGoPluginConfig,
|
||||||
|
IPicGoPluginOriginConfig,
|
||||||
|
IStringKeyMap,
|
||||||
|
IUploaderConfigItem,
|
||||||
|
IUploaderConfigListItem
|
||||||
|
} from '#/types/types'
|
||||||
import { setTrayToolTip, trimValues } from '~/utils/common'
|
import { setTrayToolTip, trimValues } from '~/utils/common'
|
||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export class MemoryMonitor {
|
|||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
private static interval: NodeJS.Timeout | null = null
|
private static interval: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
static start (intervalMs: number = 30000) {
|
static start(intervalMs: number = 30000) {
|
||||||
if (this.interval) return
|
if (this.interval) return
|
||||||
|
|
||||||
this.interval = setInterval(() => {
|
this.interval = setInterval(() => {
|
||||||
@@ -13,7 +13,9 @@ export class MemoryMonitor {
|
|||||||
heapUsed: Math.round(memUsage.heapUsed / 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`)
|
console.log(
|
||||||
|
`[Memory] RSS: ${mbUsage.rss}MB, Heap: ${mbUsage.heapUsed}/${mbUsage.heapTotal}MB, External: ${mbUsage.external}MB`
|
||||||
|
)
|
||||||
|
|
||||||
if (mbUsage.heapUsed / mbUsage.heapTotal > 0.8 && global.gc) {
|
if (mbUsage.heapUsed / mbUsage.heapTotal > 0.8 && global.gc) {
|
||||||
console.log('[Memory] Triggering garbage collection')
|
console.log('[Memory] Triggering garbage collection')
|
||||||
@@ -22,7 +24,7 @@ export class MemoryMonitor {
|
|||||||
}, intervalMs)
|
}, intervalMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
static stop () {
|
static stop() {
|
||||||
if (this.interval) {
|
if (this.interval) {
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
this.interval = null
|
this.interval = null
|
||||||
|
|||||||
@@ -11,19 +11,19 @@ class SSHClient {
|
|||||||
private static _client: NodeSSH
|
private static _client: NodeSSH
|
||||||
private _isConnected = false
|
private _isConnected = false
|
||||||
|
|
||||||
static get instance (): SSHClient {
|
static get instance(): SSHClient {
|
||||||
return this._instance || (this._instance = new this())
|
return this._instance || (this._instance = new this())
|
||||||
}
|
}
|
||||||
|
|
||||||
static get client (): NodeSSH {
|
static get client(): NodeSSH {
|
||||||
return this._client || (this._client = new NodeSSH())
|
return this._client || (this._client = new NodeSSH())
|
||||||
}
|
}
|
||||||
|
|
||||||
private changeWinStylePathToUnix (path: string): string {
|
private changeWinStylePathToUnix(path: string): string {
|
||||||
return path.replace(/\\/g, '/')
|
return path.replace(/\\/g, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect (config: ISftpPlistConfig): Promise<boolean> {
|
async connect(config: ISftpPlistConfig): Promise<boolean> {
|
||||||
const { username, password, privateKey, passphrase } = config
|
const { username, password, privateKey, passphrase } = config
|
||||||
const loginInfo: Config = privateKey
|
const loginInfo: Config = privateKey
|
||||||
? {
|
? {
|
||||||
@@ -45,7 +45,7 @@ class SSHClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFileSFTP (config: ISftpPlistConfig, remote: string): Promise<boolean> {
|
async deleteFileSFTP(config: ISftpPlistConfig, remote: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const client = new Client()
|
const client = new Client()
|
||||||
const { username, password, privateKey, passphrase } = config
|
const { username, password, privateKey, passphrase } = config
|
||||||
@@ -92,17 +92,17 @@ class SSHClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async exec (script: string): Promise<boolean> {
|
private async exec(script: string): Promise<boolean> {
|
||||||
const execResult = await SSHClient.client.execCommand(script)
|
const execResult = await SSHClient.client.execCommand(script)
|
||||||
return execResult.code === 0
|
return execResult.code === 0
|
||||||
}
|
}
|
||||||
|
|
||||||
async execCommand (script: string): Promise<SSHExecCommandResponse> {
|
async execCommand(script: string): Promise<SSHExecCommandResponse> {
|
||||||
const execResult = await SSHClient.client.execCommand(script)
|
const execResult = await SSHClient.client.execCommand(script)
|
||||||
return execResult || { code: 1, stdout: '', stderr: '' }
|
return execResult || { code: 1, stdout: '', stderr: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFile (local: string, remote: string): Promise<boolean> {
|
async getFile(local: string, remote: string): Promise<boolean> {
|
||||||
if (!this._isConnected) {
|
if (!this._isConnected) {
|
||||||
throw new Error('SSH 未连接')
|
throw new Error('SSH 未连接')
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ class SSHClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async putFile (
|
async putFile(
|
||||||
local: string,
|
local: string,
|
||||||
remote: string,
|
remote: string,
|
||||||
config: {
|
config: {
|
||||||
@@ -146,7 +146,7 @@ class SSHClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async mkdir (
|
async mkdir(
|
||||||
dirPath: string,
|
dirPath: string,
|
||||||
config: {
|
config: {
|
||||||
dirMode?: string
|
dirMode?: string
|
||||||
@@ -181,11 +181,11 @@ class SSHClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get isConnected (): boolean {
|
get isConnected(): boolean {
|
||||||
return SSHClient.client.isConnected()
|
return SSHClient.client.isConnected()
|
||||||
}
|
}
|
||||||
|
|
||||||
close (): void {
|
close(): void {
|
||||||
SSHClient.client.dispose()
|
SSHClient.client.dispose()
|
||||||
this._isConnected = false
|
this._isConnected = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,16 +37,16 @@ const getSyncConfig = () => {
|
|||||||
const getProxyagent = (proxy: string | undefined) => {
|
const getProxyagent = (proxy: string | undefined) => {
|
||||||
return proxy
|
return proxy
|
||||||
? new HttpsProxyAgent({
|
? new HttpsProxyAgent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 1000,
|
keepAliveMsecs: 1000,
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
proxy: proxy.replace('127.0.0.1', 'localhost'),
|
proxy: proxy.replace('127.0.0.1', 'localhost'),
|
||||||
scheduling: 'lifo'
|
scheduling: 'lifo'
|
||||||
})
|
})
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOctokit (syncConfig: ISyncConfig) {
|
function getOctokit(syncConfig: ISyncConfig) {
|
||||||
const { token, proxy } = syncConfig
|
const { token, proxy } = syncConfig
|
||||||
return new Octokit({
|
return new Octokit({
|
||||||
auth: token,
|
auth: token,
|
||||||
@@ -83,7 +83,7 @@ const isSyncConfigValidate = ({
|
|||||||
return type && username && repo && branch && token
|
return type && username && repo && branch && token
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
|
async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
|
||||||
const localFilePath = path.join(STORE_PATH, fileName)
|
const localFilePath = path.join(STORE_PATH, fileName)
|
||||||
if (!fs.existsSync(localFilePath)) {
|
if (!fs.existsSync(localFilePath)) {
|
||||||
return false
|
return false
|
||||||
@@ -161,7 +161,7 @@ async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
|
async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
|
||||||
const localFilePath = path.join(STORE_PATH, fileName)
|
const localFilePath = path.join(STORE_PATH, fileName)
|
||||||
if (!fs.existsSync(localFilePath)) {
|
if (!fs.existsSync(localFilePath)) {
|
||||||
return false
|
return false
|
||||||
@@ -277,7 +277,7 @@ async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadFile (fileName: string[]): Promise<number> {
|
async function uploadFile(fileName: string[]): Promise<number> {
|
||||||
const syncConfig = getSyncConfig()
|
const syncConfig = getSyncConfig()
|
||||||
if (!isSyncConfigValidate(syncConfig)) {
|
if (!isSyncConfigValidate(syncConfig)) {
|
||||||
logger.error('sync config is invalid')
|
logger.error('sync config is invalid')
|
||||||
@@ -302,7 +302,7 @@ async function uploadFile (fileName: string[]): Promise<number> {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadAndWriteFile (url: string, localFilePath: string, config: any, isWriteJson = false) {
|
async function downloadAndWriteFile(url: string, localFilePath: string, config: any, isWriteJson = false) {
|
||||||
const res = await axios.get(url, config)
|
const res = await axios.get(url, config)
|
||||||
if (isHttpResSuccess(res)) {
|
if (isHttpResSuccess(res)) {
|
||||||
await fs.writeFile(
|
await fs.writeFile(
|
||||||
@@ -314,7 +314,7 @@ async function downloadAndWriteFile (url: string, localFilePath: string, config:
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) {
|
async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string) {
|
||||||
const localFilePath = path.join(STORE_PATH, fileName)
|
const localFilePath = path.join(STORE_PATH, fileName)
|
||||||
const { username, repo, branch, token, proxy, type } = syncConfig
|
const { username, repo, branch, token, proxy, type } = syncConfig
|
||||||
try {
|
try {
|
||||||
@@ -394,7 +394,7 @@ async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadFile (fileName: string[]): Promise<number> {
|
async function downloadFile(fileName: string[]): Promise<number> {
|
||||||
const syncConfig = getSyncConfig()
|
const syncConfig = getSyncConfig()
|
||||||
if (!isSyncConfigValidate(syncConfig)) {
|
if (!isSyncConfigValidate(syncConfig)) {
|
||||||
logger.error('sync config is invalid')
|
logger.error('sync config is invalid')
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { screen } from 'electron'
|
|||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
import { IWindowList } from '~/utils/enum'
|
import { IWindowList } from '~/utils/enum'
|
||||||
|
|
||||||
export function openMiniWindow (hideSettingWindow: boolean = true) {
|
export function openMiniWindow(hideSettingWindow: boolean = true) {
|
||||||
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
|
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
|
||||||
|
|
||||||
miniWindow.removeAllListeners('close')
|
miniWindow.removeAllListeners('close')
|
||||||
@@ -24,9 +24,15 @@ export function openMiniWindow (hideSettingWindow: boolean = true) {
|
|||||||
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
if (lastPosition[0] < 0 || lastPosition[0] > width || lastPosition[1] < 0 || lastPosition[1] > height) {
|
||||||
miniWindow.setPosition(width - 100, height - 100)
|
miniWindow.setPosition(width - 100, height - 100)
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
db.set(configPaths.settings.miniWindowPosition, [width - 100, height - 100])
|
||||||
} else if (lastPosition[0] + miniWindow.getSize()[0] > width || lastPosition[1] + miniWindow.getSize()[1] > height) {
|
} else if (
|
||||||
|
lastPosition[0] + miniWindow.getSize()[0] > width ||
|
||||||
|
lastPosition[1] + miniWindow.getSize()[1] > height
|
||||||
|
) {
|
||||||
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
miniWindow.setPosition(width - miniWindow.getSize()[0], height - miniWindow.getSize()[1])
|
||||||
db.set(configPaths.settings.miniWindowPosition, [width - miniWindow.getSize()[0], height - miniWindow.getSize()[1]])
|
db.set(configPaths.settings.miniWindowPosition, [
|
||||||
|
width - miniWindow.getSize()[0],
|
||||||
|
height - miniWindow.getSize()[1]
|
||||||
|
])
|
||||||
} else {
|
} else {
|
||||||
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
miniWindow.setPosition(lastPosition[0], lastPosition[1])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,19 +21,19 @@ export const getRawData = (args: any): any => {
|
|||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendToMain (channel: string, ...args: any[]) {
|
function sendToMain(channel: string, ...args: any[]) {
|
||||||
ipcRenderer.send(channel, ...getRawData(args))
|
ipcRenderer.send(channel, ...getRawData(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendRPC (action: string, ...args: any[]): void {
|
function sendRPC(action: string, ...args: any[]): void {
|
||||||
ipcRenderer.send('RPC_ACTIONS', action, getRawData(args))
|
ipcRenderer.send('RPC_ACTIONS', action, getRawData(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function triggerRPC<T> (action: string, ...args: any[]): Promise<T | undefined> {
|
async function triggerRPC<T>(action: string, ...args: any[]): Promise<T | undefined> {
|
||||||
return await ipcRenderer.invoke('RPC_ACTIONS_INVOKE', action, getRawData(args))
|
return await ipcRenderer.invoke('RPC_ACTIONS_INVOKE', action, getRawData(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendRpcSync (action: string, ...args: any[]): any {
|
function sendRpcSync(action: string, ...args: any[]): any {
|
||||||
return ipcRenderer.sendSync('RPC_ACTIONS', action, getRawData(args))
|
return ipcRenderer.sendSync('RPC_ACTIONS', action, getRawData(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ try {
|
|||||||
ipcRendererRemoveAllListeners: (channel: string) => {
|
ipcRendererRemoveAllListeners: (channel: string) => {
|
||||||
ipcRenderer.removeAllListeners(channel)
|
ipcRenderer.removeAllListeners(channel)
|
||||||
},
|
},
|
||||||
showFilePath (file: File) {
|
showFilePath(file: File) {
|
||||||
return webUtils.getPathForFile(file)
|
return webUtils.getPathForFile(file)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div id="app" :key="pageReloadCount">
|
||||||
id="app"
|
|
||||||
:key="pageReloadCount"
|
|
||||||
>
|
|
||||||
<router-view />
|
<router-view />
|
||||||
<UIServiceProvider />
|
<UIServiceProvider />
|
||||||
</div>
|
</div>
|
||||||
@@ -39,7 +36,6 @@ onMounted(async () => {
|
|||||||
console.error('Failed to load settings:', error)
|
console.error('Failed to load settings:', error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { IRPCActionType } from '@/utils/enum'
|
|||||||
import type { IStringKeyMap } from '#/types/types'
|
import type { IStringKeyMap } from '#/types/types'
|
||||||
|
|
||||||
export default class ALLApi {
|
export default class ALLApi {
|
||||||
static async delete (configMap: IStringKeyMap): Promise<boolean> {
|
static async delete(configMap: IStringKeyMap): Promise<boolean> {
|
||||||
return (await window.electron.triggerRPC(IRPCActionType.DELETE_ALL_API, getRawData(configMap))) || false
|
return (await window.electron.triggerRPC(IRPCActionType.DELETE_ALL_API, getRawData(configMap))) || false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<div
|
<div v-if="isLoading" class="loading-placeholder">
|
||||||
v-if="isLoading"
|
|
||||||
class="loading-placeholder"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
v-else-if="!hasError"
|
v-else-if="!hasError"
|
||||||
:src="
|
:src="isShowThumbnail && item.isImage ? base64Image : `./assets/icons/${getFileIconPath(item.fileName ?? '')}`"
|
||||||
isShowThumbnail && item.isImage
|
|
||||||
? base64Image
|
|
||||||
: `./assets/icons/${getFileIconPath(item.fileName ?? '')}`
|
|
||||||
"
|
|
||||||
alt=""
|
alt=""
|
||||||
class="image"
|
class="image"
|
||||||
@load="handleImageLoad"
|
@load="handleImageLoad"
|
||||||
@error="handleImageError"
|
@error="handleImageError"
|
||||||
>
|
/>
|
||||||
<img
|
<img v-else :src="`./assets/icons/${getFileIconPath(item.fileName ?? '')}`" alt="" class="image" />
|
||||||
v-else
|
|
||||||
:src="`./assets/icons/${getFileIconPath(item.fileName ?? '')}`"
|
|
||||||
alt=""
|
|
||||||
class="image"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -109,7 +97,11 @@ onBeforeMount(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<div
|
<div v-if="isLoading" class="loading-placeholder">
|
||||||
v-if="isLoading"
|
|
||||||
class="loading-placeholder"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
@@ -13,13 +10,8 @@
|
|||||||
class="image"
|
class="image"
|
||||||
@load="handleImageLoad"
|
@load="handleImageLoad"
|
||||||
@error="handleImageError"
|
@error="handleImageError"
|
||||||
>
|
/>
|
||||||
<img
|
<img v-else :src="iconPath" alt="" class="image" />
|
||||||
v-else
|
|
||||||
:src="iconPath"
|
|
||||||
alt=""
|
|
||||||
class="image"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -53,11 +45,15 @@ const imageSource = computed(() => {
|
|||||||
|
|
||||||
const iconPath = computed(() => `./assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
const iconPath = computed(() => `./assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||||
|
|
||||||
async function getUrl () {
|
async function getUrl() {
|
||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
hasError.value = false
|
hasError.value = false
|
||||||
preSignedUrl.value = await window.electron.triggerRPC<any>(IRPCActionType.MANAGE_GET_PRE_SIGNED_URL, props.alias, props.config)
|
preSignedUrl.value = await window.electron.triggerRPC<any>(
|
||||||
|
IRPCActionType.MANAGE_GET_PRE_SIGNED_URL,
|
||||||
|
props.alias,
|
||||||
|
props.config
|
||||||
|
)
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to get pre-signed URL:', error)
|
console.error('Failed to get pre-signed URL:', error)
|
||||||
@@ -117,7 +113,11 @@ onMounted(getUrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,26 +3,17 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="settings-header">
|
<div class="settings-header">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<Settings
|
<Settings :size="24" class="header-icon" />
|
||||||
:size="24"
|
|
||||||
class="header-icon"
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<h1>{{ $t('pages.imageProcess.title') }}</h1>
|
<h1>{{ $t('pages.imageProcess.title') }}</h1>
|
||||||
<p>{{ $t('pages.imageProcess.description') }}</p>
|
<p>{{ $t('pages.imageProcess.description') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button
|
<button class="btn btn-secondary" @click="closeDialog">
|
||||||
class="btn btn-secondary"
|
|
||||||
@click="closeDialog"
|
|
||||||
>
|
|
||||||
{{ $t('pages.imageProcess.cancel') }}
|
{{ $t('pages.imageProcess.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn btn-primary" @click="handleSaveConfig">
|
||||||
class="btn btn-primary"
|
|
||||||
@click="handleSaveConfig"
|
|
||||||
>
|
|
||||||
<Save :size="16" />
|
<Save :size="16" />
|
||||||
{{ $t('pages.imageProcess.confirm') }}
|
{{ $t('pages.imageProcess.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -38,10 +29,7 @@
|
|||||||
:class="{ active: activeTab === tab.id }"
|
:class="{ active: activeTab === tab.id }"
|
||||||
@click="activeTab = tab.id"
|
@click="activeTab = tab.id"
|
||||||
>
|
>
|
||||||
<component
|
<component :is="tab.icon" :size="18" />
|
||||||
:is="tab.icon"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
<span>{{ tab.label }}</span>
|
<span>{{ tab.label }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,10 +37,7 @@
|
|||||||
<!-- Settings Content -->
|
<!-- Settings Content -->
|
||||||
<div class="settings-content">
|
<div class="settings-content">
|
||||||
<!-- General Settings Tab -->
|
<!-- General Settings Tab -->
|
||||||
<div
|
<div v-if="activeTab === 'general'" class="tab-content">
|
||||||
v-if="activeTab === 'general'"
|
|
||||||
class="tab-content"
|
|
||||||
>
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h2>{{ $t('pages.imageProcess.general.skipProcessExtList') }}</h2>
|
<h2>{{ $t('pages.imageProcess.general.skipProcessExtList') }}</h2>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -73,11 +58,7 @@
|
|||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isRemoveExif" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isRemoveExif"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.general.isRemoveExif') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.general.isRemoveExif') }}</span>
|
||||||
@@ -87,16 +68,8 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.general.quality') }}</label>
|
<label>{{ $t('pages.imageProcess.general.quality') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.quality" type="range" min="1" max="100" class="form-range" />
|
||||||
v-model.number="compressForm.quality"
|
<div class="range-value">{{ compressForm.quality }}%</div>
|
||||||
type="range"
|
|
||||||
min="1"
|
|
||||||
max="100"
|
|
||||||
class="form-range"
|
|
||||||
>
|
|
||||||
<div class="range-value">
|
|
||||||
{{ compressForm.quality }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,11 +79,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isConvert" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isConvert"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.general.isConvert') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.general.isConvert') }}</span>
|
||||||
@@ -118,21 +87,11 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isConvert" class="form-grid">
|
||||||
v-if="compressForm.isConvert"
|
|
||||||
class="form-grid"
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.general.destinationFormat') }}</label>
|
<label>{{ $t('pages.imageProcess.general.destinationFormat') }}</label>
|
||||||
<select
|
<select v-model="compressForm.convertFormat" class="form-input">
|
||||||
v-model="compressForm.convertFormat"
|
<option v-for="format in availableFormat" :key="format" :value="format">
|
||||||
class="form-input"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
v-for="format in availableFormat"
|
|
||||||
:key="format"
|
|
||||||
:value="format"
|
|
||||||
>
|
|
||||||
{{ format.toUpperCase() }}
|
{{ format.toUpperCase() }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -144,7 +103,7 @@
|
|||||||
v-model="formatConvertObj"
|
v-model="formatConvertObj"
|
||||||
class="form-textarea"
|
class="form-textarea"
|
||||||
rows="3"
|
rows="3"
|
||||||
placeholder="{"jpg": "png", "png": "jpg"}"
|
placeholder='{"jpg": "png", "png": "jpg"}'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -152,21 +111,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Watermark Tab -->
|
<!-- Watermark Tab -->
|
||||||
<div
|
<div v-if="activeTab === 'watermark'" class="tab-content">
|
||||||
v-if="activeTab === 'watermark'"
|
|
||||||
class="tab-content"
|
|
||||||
>
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h2>{{ $t('pages.imageProcess.watermark.title') }}</h2>
|
<h2>{{ $t('pages.imageProcess.watermark.title') }}</h2>
|
||||||
<p>{{ $t('pages.imageProcess.watermark.description') }}</p>
|
<p>{{ $t('pages.imageProcess.watermark.description') }}</p>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="waterMarkForm.isAddWatermark" type="checkbox" class="switch-input" />
|
||||||
v-model="waterMarkForm.isAddWatermark"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isAdd') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isAdd') }}</span>
|
||||||
@@ -174,30 +126,17 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="waterMarkForm.isAddWatermark" class="watermark-settings">
|
||||||
v-if="waterMarkForm.isAddWatermark"
|
|
||||||
class="watermark-settings"
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.watermark.type') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.type') }}</label>
|
||||||
<div class="radio-group">
|
<div class="radio-group">
|
||||||
<label class="radio-option">
|
<label class="radio-option">
|
||||||
<input
|
<input v-model="waterMarkForm.watermarkType" type="radio" value="text" class="radio-input" />
|
||||||
v-model="waterMarkForm.watermarkType"
|
|
||||||
type="radio"
|
|
||||||
value="text"
|
|
||||||
class="radio-input"
|
|
||||||
>
|
|
||||||
<span class="radio-indicator" />
|
<span class="radio-indicator" />
|
||||||
<span class="radio-label">{{ $t('pages.imageProcess.watermark.text') }}</span>
|
<span class="radio-label">{{ $t('pages.imageProcess.watermark.text') }}</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="radio-option">
|
<label class="radio-option">
|
||||||
<input
|
<input v-model="waterMarkForm.watermarkType" type="radio" value="image" class="radio-input" />
|
||||||
v-model="waterMarkForm.watermarkType"
|
|
||||||
type="radio"
|
|
||||||
value="image"
|
|
||||||
class="radio-input"
|
|
||||||
>
|
|
||||||
<span class="radio-indicator" />
|
<span class="radio-indicator" />
|
||||||
<span class="radio-label">{{ $t('pages.imageProcess.watermark.image') }}</span>
|
<span class="radio-label">{{ $t('pages.imageProcess.watermark.image') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -207,11 +146,7 @@
|
|||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="waterMarkForm.isFullScreenWatermark" type="checkbox" class="switch-input" />
|
||||||
v-model="waterMarkForm.isFullScreenWatermark"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isFullScreen') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.watermark.isFullScreen') }}</span>
|
||||||
@@ -227,10 +162,8 @@
|
|||||||
min="-360"
|
min="-360"
|
||||||
max="360"
|
max="360"
|
||||||
class="form-range"
|
class="form-range"
|
||||||
>
|
/>
|
||||||
<div class="range-value">
|
<div class="range-value">{{ waterMarkForm.watermarkDegree }}°</div>
|
||||||
{{ waterMarkForm.watermarkDegree }}°
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -242,18 +175,13 @@
|
|||||||
max="1"
|
max="1"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
class="form-range"
|
class="form-range"
|
||||||
>
|
/>
|
||||||
<div class="range-value">
|
<div class="range-value">{{ Math.round((waterMarkForm.watermarkScaleRatio || 0) * 100) }}%</div>
|
||||||
{{ Math.round((waterMarkForm.watermarkScaleRatio || 0) * 100) }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Text Watermark Settings -->
|
<!-- Text Watermark Settings -->
|
||||||
<div
|
<div v-if="waterMarkForm.watermarkType === 'text'" class="form-grid">
|
||||||
v-if="waterMarkForm.watermarkType === 'text'"
|
|
||||||
class="form-grid"
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.watermark.inputText') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.inputText') }}</label>
|
||||||
<input
|
<input
|
||||||
@@ -261,7 +189,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="$t('pages.imageProcess.watermark.inputTextPlaceholder')"
|
:placeholder="$t('pages.imageProcess.watermark.inputTextPlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -271,45 +199,35 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="$t('pages.imageProcess.watermark.textFontPathPlaceholder')"
|
:placeholder="$t('pages.imageProcess.watermark.textFontPathPlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.watermark.color') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.color') }}</label>
|
||||||
<div class="color-input-group">
|
<div class="color-input-group">
|
||||||
<input
|
<input v-model="waterMarkForm.watermarkColor" type="color" class="form-color" />
|
||||||
v-model="waterMarkForm.watermarkColor"
|
|
||||||
type="color"
|
|
||||||
class="form-color"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
v-model="waterMarkForm.watermarkColor"
|
v-model="waterMarkForm.watermarkColor"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
placeholder="#CCCCCC73"
|
placeholder="#CCCCCC73"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Image Watermark Settings -->
|
<!-- Image Watermark Settings -->
|
||||||
<div
|
<div v-if="waterMarkForm.watermarkType === 'image'" class="form-group">
|
||||||
v-if="waterMarkForm.watermarkType === 'image'"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.watermark.imagePath') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.imagePath') }}</label>
|
||||||
<input
|
<input
|
||||||
v-model="waterMarkForm.watermarkImagePath"
|
v-model="waterMarkForm.watermarkImagePath"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
:placeholder="$t('pages.imageProcess.watermark.imagePathPlaceholder')"
|
:placeholder="$t('pages.imageProcess.watermark.imagePathPlaceholder')"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="waterMarkForm.watermarkType === 'image'" class="form-group">
|
||||||
v-if="waterMarkForm.watermarkType === 'image'"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.watermark.imageOpacity') }}</label>
|
<label>{{ $t('pages.imageProcess.watermark.imageOpacity') }}</label>
|
||||||
<input
|
<input
|
||||||
v-model.number="waterMarkForm.watermarkImageOpacity"
|
v-model.number="waterMarkForm.watermarkImageOpacity"
|
||||||
@@ -318,7 +236,7 @@
|
|||||||
max="255"
|
max="255"
|
||||||
step="1"
|
step="1"
|
||||||
class="form-range"
|
class="form-range"
|
||||||
>
|
/>
|
||||||
<div class="range-value">
|
<div class="range-value">
|
||||||
{{ waterMarkForm.watermarkImageOpacity || 0 }}
|
{{ waterMarkForm.watermarkImageOpacity || 0 }}
|
||||||
</div>
|
</div>
|
||||||
@@ -345,10 +263,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Transform Tab -->
|
<!-- Transform Tab -->
|
||||||
<div
|
<div v-if="activeTab === 'transform'" class="tab-content">
|
||||||
v-if="activeTab === 'transform'"
|
|
||||||
class="tab-content"
|
|
||||||
>
|
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h2>{{ $t('pages.imageProcess.transform.title') }}</h2>
|
<h2>{{ $t('pages.imageProcess.transform.title') }}</h2>
|
||||||
<p>{{ $t('pages.imageProcess.transform.description') }}</p>
|
<p>{{ $t('pages.imageProcess.transform.description') }}</p>
|
||||||
@@ -356,11 +271,7 @@
|
|||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isFlip" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isFlip"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlip') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlip') }}</span>
|
||||||
@@ -370,11 +281,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isFlop" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isFlop"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlop') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isFlop') }}</span>
|
||||||
@@ -390,11 +297,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isRotate" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isRotate"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isRotate') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isRotate') }}</span>
|
||||||
@@ -402,21 +305,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isRotate" class="form-group">
|
||||||
v-if="compressForm.isRotate"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.transform.rotationDegree') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.rotationDegree') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.rotateDegree" type="range" min="-360" max="360" class="form-range" />
|
||||||
v-model.number="compressForm.rotateDegree"
|
<div class="range-value">{{ compressForm.rotateDegree }}°</div>
|
||||||
type="range"
|
|
||||||
min="-360"
|
|
||||||
max="360"
|
|
||||||
class="form-range"
|
|
||||||
>
|
|
||||||
<div class="range-value">
|
|
||||||
{{ compressForm.rotateDegree }}°
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -426,11 +318,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isReSize" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isReSize"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResize') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResize') }}</span>
|
||||||
@@ -438,42 +326,28 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isReSize" class="resize-settings">
|
||||||
v-if="compressForm.isReSize"
|
|
||||||
class="resize-settings"
|
|
||||||
>
|
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.transform.resizeWidth') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.resizeWidth') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.reSizeWidth" type="number" min="0" class="form-input" />
|
||||||
v-model.number="compressForm.reSizeWidth"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
class="form-input"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>{{ $t('pages.imageProcess.transform.resizeHeight') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.resizeHeight') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.reSizeHeight" type="number" min="0" class="form-input" />
|
||||||
v-model.number="compressForm.reSizeHeight"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
class="form-input"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="((compressForm.reSizeHeight || 0) > 0 && (compressForm.reSizeWidth || 0) === 0) || ((compressForm.reSizeWidth || 0) > 0 && (compressForm.reSizeHeight || 0) === 0)"
|
v-if="
|
||||||
|
((compressForm.reSizeHeight || 0) > 0 && (compressForm.reSizeWidth || 0) === 0) ||
|
||||||
|
((compressForm.reSizeWidth || 0) > 0 && (compressForm.reSizeHeight || 0) === 0)
|
||||||
|
"
|
||||||
class="form-group"
|
class="form-group"
|
||||||
>
|
>
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.skipReSizeOfSmallImg" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.skipReSizeOfSmallImg"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.skipResizeOfSmallImgHeight') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.skipResizeOfSmallImgHeight') }}</span>
|
||||||
@@ -488,11 +362,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<input
|
<input v-model="compressForm.isReSizeByPercent" type="checkbox" class="switch-input" />
|
||||||
v-model="compressForm.isReSizeByPercent"
|
|
||||||
type="checkbox"
|
|
||||||
class="switch-input"
|
|
||||||
>
|
|
||||||
<span class="switch-slider" />
|
<span class="switch-slider" />
|
||||||
<div class="switch-content">
|
<div class="switch-content">
|
||||||
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResizeByPercent') }}</span>
|
<span class="switch-title">{{ $t('pages.imageProcess.transform.isResizeByPercent') }}</span>
|
||||||
@@ -501,21 +371,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="compressForm.isReSizeByPercent" class="form-group">
|
||||||
v-if="compressForm.isReSizeByPercent"
|
|
||||||
class="form-group"
|
|
||||||
>
|
|
||||||
<label>{{ $t('pages.imageProcess.transform.resizePercent') }}</label>
|
<label>{{ $t('pages.imageProcess.transform.resizePercent') }}</label>
|
||||||
<input
|
<input v-model.number="compressForm.reSizePercent" type="range" min="1" max="500" class="form-range" />
|
||||||
v-model.number="compressForm.reSizePercent"
|
<div class="range-value">{{ compressForm.reSizePercent }}%</div>
|
||||||
type="range"
|
|
||||||
min="1"
|
|
||||||
max="500"
|
|
||||||
class="form-range"
|
|
||||||
>
|
|
||||||
<div class="range-value">
|
|
||||||
{{ compressForm.reSizePercent }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -631,7 +490,7 @@ const waterMarkFormKeys = Object.keys(waterMarkForm) as (keyof typeof waterMarkF
|
|||||||
const compressFormKeys = Object.keys(compressForm) as (keyof typeof compressForm)[]
|
const compressFormKeys = Object.keys(compressForm) as (keyof typeof compressForm)[]
|
||||||
const skipProcessFormKeys = Object.keys(skipProcessForm) as (keyof typeof skipProcessForm)[]
|
const skipProcessFormKeys = Object.keys(skipProcessForm) as (keyof typeof skipProcessForm)[]
|
||||||
|
|
||||||
function handleSaveConfig () {
|
function handleSaveConfig() {
|
||||||
let iformatConvertObj = {}
|
let iformatConvertObj = {}
|
||||||
try {
|
try {
|
||||||
iformatConvertObj = JSON.parse(formatConvertObj.value)
|
iformatConvertObj = JSON.parse(formatConvertObj.value)
|
||||||
@@ -649,7 +508,7 @@ function handleSaveConfig () {
|
|||||||
closeDialog()
|
closeDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initData () {
|
async function initData() {
|
||||||
const compress = await getConfig<any>(configPaths.buildIn.compress)
|
const compress = await getConfig<any>(configPaths.buildIn.compress)
|
||||||
const watermark = await getConfig<any>(configPaths.buildIn.watermark)
|
const watermark = await getConfig<any>(configPaths.buildIn.watermark)
|
||||||
const skipProcess = await getConfig<any>(configPaths.buildIn.skipProcess)
|
const skipProcess = await getConfig<any>(configPaths.buildIn.skipProcess)
|
||||||
@@ -680,7 +539,7 @@ async function initData () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDialog () {
|
function closeDialog() {
|
||||||
imageProcessDialogVisible.value = false
|
imageProcessDialogVisible.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<div
|
<div v-if="isLoading" class="loading-placeholder">
|
||||||
v-if="isLoading"
|
|
||||||
class="loading-placeholder"
|
|
||||||
>
|
|
||||||
<div class="loading-spinner" />
|
<div class="loading-spinner" />
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
@@ -13,13 +10,8 @@
|
|||||||
class="image"
|
class="image"
|
||||||
@load="handleImageLoad"
|
@load="handleImageLoad"
|
||||||
@error="handleImageError"
|
@error="handleImageError"
|
||||||
>
|
/>
|
||||||
<img
|
<img v-else :src="iconPath" alt="" class="image" />
|
||||||
v-else
|
|
||||||
:src="iconPath"
|
|
||||||
alt=""
|
|
||||||
class="image"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -54,7 +46,7 @@ const imageSource = computed(() => {
|
|||||||
|
|
||||||
const iconPath = computed(() => `./assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
const iconPath = computed(() => `./assets/icons/${getFileIconPath(props.item.fileName ?? '')}`)
|
||||||
|
|
||||||
async function getWebdavHeader (key: string) {
|
async function getWebdavHeader(key: string) {
|
||||||
let headers = {} as any
|
let headers = {} as any
|
||||||
if (props.config.authType === 'digest') {
|
if (props.config.authType === 'digest') {
|
||||||
const authHeader = await getAuthHeader(
|
const authHeader = await getAuthHeader(
|
||||||
@@ -148,7 +140,11 @@ onMounted(fetchImage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% { transform: rotate(0deg); }
|
0% {
|
||||||
100% { transform: rotate(360deg); }
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,22 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div
|
<div v-if="showInputBoxVisible" class="inputbox-overlay" @click="handleInputBoxCancel">
|
||||||
v-if="showInputBoxVisible"
|
<div class="inputbox-container" @click.stop>
|
||||||
class="inputbox-overlay"
|
|
||||||
@click="handleInputBoxCancel"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="inputbox-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="inputbox-header">
|
<div class="inputbox-header">
|
||||||
<h3 class="inputbox-title">
|
<h3 class="inputbox-title">
|
||||||
{{ inputBoxOptions.title || t('pages.inputBox.title') }}
|
{{ inputBoxOptions.title || t('pages.inputBox.title') }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button class="inputbox-close" @click="handleInputBoxCancel">
|
||||||
class="inputbox-close"
|
|
||||||
@click="handleInputBoxCancel"
|
|
||||||
>
|
|
||||||
<X :size="20" />
|
<X :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,19 +18,13 @@
|
|||||||
type="text"
|
type="text"
|
||||||
@keyup.enter="handleInputBoxConfirm"
|
@keyup.enter="handleInputBoxConfirm"
|
||||||
@keyup.escape="handleInputBoxCancel"
|
@keyup.escape="handleInputBoxCancel"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="inputbox-actions">
|
<div class="inputbox-actions">
|
||||||
<button
|
<button class="inputbox-btn cancel-btn" @click="handleInputBoxCancel">
|
||||||
class="inputbox-btn cancel-btn"
|
|
||||||
@click="handleInputBoxCancel"
|
|
||||||
>
|
|
||||||
{{ t('common.cancel') }}
|
{{ t('common.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="inputbox-btn confirm-btn primary" @click="handleInputBoxConfirm">
|
||||||
class="inputbox-btn confirm-btn primary"
|
|
||||||
@click="handleInputBoxConfirm"
|
|
||||||
>
|
|
||||||
{{ t('common.confirm') }}
|
{{ t('common.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,27 +50,27 @@ const inputBoxOptions = reactive({
|
|||||||
placeholder: ''
|
placeholder: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
let removeInputBoxListenerCallback: (() => void) = () => {}
|
let removeInputBoxListenerCallback: () => void = () => {}
|
||||||
|
|
||||||
function handleIpcInputBoxEvent (options: IShowInputBoxOption) {
|
function handleIpcInputBoxEvent(options: IShowInputBoxOption) {
|
||||||
initInputBoxValue(options)
|
initInputBoxValue(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
function initInputBoxValue (options: IShowInputBoxOption) {
|
function initInputBoxValue(options: IShowInputBoxOption) {
|
||||||
inputBoxValue.value = options.value || ''
|
inputBoxValue.value = options.value || ''
|
||||||
inputBoxOptions.title = options.title || ''
|
inputBoxOptions.title = options.title || ''
|
||||||
inputBoxOptions.placeholder = options.placeholder || ''
|
inputBoxOptions.placeholder = options.placeholder || ''
|
||||||
showInputBoxVisible.value = true
|
showInputBoxVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInputBoxCancel () {
|
function handleInputBoxCancel() {
|
||||||
// TODO: RPCServer
|
// TODO: RPCServer
|
||||||
showInputBoxVisible.value = false
|
showInputBoxVisible.value = false
|
||||||
window.electron.sendToMain(SHOW_INPUT_BOX, '')
|
window.electron.sendToMain(SHOW_INPUT_BOX, '')
|
||||||
$bus.emit(SHOW_INPUT_BOX_RESPONSE, '')
|
$bus.emit(SHOW_INPUT_BOX_RESPONSE, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInputBoxConfirm () {
|
function handleInputBoxConfirm() {
|
||||||
showInputBoxVisible.value = false
|
showInputBoxVisible.value = false
|
||||||
window.electron.sendToMain(SHOW_INPUT_BOX, inputBoxValue.value)
|
window.electron.sendToMain(SHOW_INPUT_BOX, inputBoxValue.value)
|
||||||
$bus.emit(SHOW_INPUT_BOX_RESPONSE, inputBoxValue.value)
|
$bus.emit(SHOW_INPUT_BOX_RESPONSE, inputBoxValue.value)
|
||||||
@@ -126,7 +110,9 @@ export default {
|
|||||||
.inputbox-container {
|
.inputbox-container {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
max-width: 32rem;
|
max-width: 32rem;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
|
|||||||
@@ -1,36 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav
|
<nav class="navigation" :class="{ collapsed: isCollapsed }">
|
||||||
class="navigation"
|
|
||||||
:class="{ collapsed: isCollapsed }"
|
|
||||||
>
|
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
<div
|
<div v-if="!isCollapsed" class="app-title">
|
||||||
v-if="!isCollapsed"
|
<div class="app-text" @click="openGithubPage">
|
||||||
class="app-title"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="app-text"
|
|
||||||
@click="openGithubPage"
|
|
||||||
>
|
|
||||||
{{ t('app.title') }}
|
{{ t('app.title') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="app-version">
|
<div class="app-version">v{{ version }}</div>
|
||||||
v{{ version }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
:title="isCollapsed ? t('navigation.expand') : t('navigation.collapse')"
|
:title="isCollapsed ? t('navigation.expand') : t('navigation.collapse')"
|
||||||
class="collapse-button"
|
class="collapse-button"
|
||||||
@click="isCollapsed = !isCollapsed"
|
@click="isCollapsed = !isCollapsed"
|
||||||
>
|
>
|
||||||
<ChevronLeftIcon
|
<ChevronLeftIcon v-if="!isCollapsed" :size="20" />
|
||||||
v-if="!isCollapsed"
|
<ChevronRightIcon v-else :size="20" />
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
<ChevronRightIcon
|
|
||||||
v-else
|
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -47,33 +30,18 @@
|
|||||||
:title="`${item.name}`"
|
:title="`${item.name}`"
|
||||||
>
|
>
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<component
|
<component :is="item.icon" :size="18" />
|
||||||
:is="item.icon"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span v-if="!isCollapsed" class="nav-label">{{ item.name }}</span>
|
||||||
v-if="!isCollapsed"
|
|
||||||
class="nav-label"
|
|
||||||
>{{ item.name }}</span>
|
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<Disclosure
|
<Disclosure v-if="!isCollapsed" v-slot="{ open }" as="div" class="nav-submenu">
|
||||||
v-if="!isCollapsed"
|
|
||||||
v-slot="{ open }"
|
|
||||||
as="div"
|
|
||||||
class="nav-submenu"
|
|
||||||
>
|
|
||||||
<DisclosureButton class="nav-item submenu-trigger">
|
<DisclosureButton class="nav-item submenu-trigger">
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<DatabaseIcon :size="18" />
|
<DatabaseIcon :size="18" />
|
||||||
</div>
|
</div>
|
||||||
<span class="nav-label">{{ t('navigation.picbed') }}</span>
|
<span class="nav-label">{{ t('navigation.picbed') }}</span>
|
||||||
<ChevronDownIcon
|
<ChevronDownIcon :size="16" class="submenu-arrow" :class="{ 'rotate-180': open }" />
|
||||||
:size="16"
|
|
||||||
class="submenu-arrow"
|
|
||||||
:class="{ 'rotate-180': open }"
|
|
||||||
/>
|
|
||||||
</DisclosureButton>
|
</DisclosureButton>
|
||||||
<DisclosurePanel class="submenu-panel">
|
<DisclosurePanel class="submenu-panel">
|
||||||
<router-link
|
<router-link
|
||||||
@@ -86,12 +54,7 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</DisclosurePanel>
|
</DisclosurePanel>
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
<div
|
<div v-else class="nav-item collapsed-picbed" :title="t('navigation.picbed')" @click="isCollapsed = !isCollapsed">
|
||||||
v-else
|
|
||||||
class="nav-item collapsed-picbed"
|
|
||||||
:title="t('navigation.picbed')"
|
|
||||||
@click="isCollapsed = !isCollapsed"
|
|
||||||
>
|
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<DatabaseIcon :size="18" />
|
<DatabaseIcon :size="18" />
|
||||||
</div>
|
</div>
|
||||||
@@ -105,37 +68,19 @@
|
|||||||
:title="`${item.name}`"
|
:title="`${item.name}`"
|
||||||
>
|
>
|
||||||
<div class="nav-icon-container">
|
<div class="nav-icon-container">
|
||||||
<component
|
<component :is="item.icon" :size="18" />
|
||||||
:is="item.icon"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span v-if="!isCollapsed" class="nav-label">{{ item.name }}</span>
|
||||||
v-if="!isCollapsed"
|
|
||||||
class="nav-label"
|
|
||||||
>{{ item.name }}</span>
|
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-footer">
|
<div class="sidebar-footer">
|
||||||
<button
|
<button class="footer-button" :title="t('navigation.moreOptions')" @click="openMenu">
|
||||||
class="footer-button"
|
|
||||||
:title="t('navigation.moreOptions')"
|
|
||||||
@click="openMenu"
|
|
||||||
>
|
|
||||||
<Info :size="20" />
|
<Info :size="20" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<TransitionRoot
|
<TransitionRoot appear :show="qrcodeVisible" as="template">
|
||||||
appear
|
<Dialog as="div" class="qr-dialog" @close="qrcodeVisible = false">
|
||||||
:show="qrcodeVisible"
|
|
||||||
as="template"
|
|
||||||
>
|
|
||||||
<Dialog
|
|
||||||
as="div"
|
|
||||||
class="qr-dialog"
|
|
||||||
@close="qrcodeVisible = false"
|
|
||||||
>
|
|
||||||
<div class="dialog-container">
|
<div class="dialog-container">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as="template"
|
as="template"
|
||||||
@@ -154,28 +99,16 @@
|
|||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">{{ t('navigation.choosePicBed') }}</label>
|
<label class="form-label">{{ t('navigation.choosePicBed') }}</label>
|
||||||
<Listbox
|
<Listbox v-model="choosedPicBedForQRCode" multiple>
|
||||||
v-model="choosedPicBedForQRCode"
|
|
||||||
multiple
|
|
||||||
>
|
|
||||||
<div class="listbox-container">
|
<div class="listbox-container">
|
||||||
<ListboxButton class="listbox-button">
|
<ListboxButton class="listbox-button">
|
||||||
<span
|
<span v-if="choosedPicBedForQRCode.length === 0" class="placeholder">
|
||||||
v-if="choosedPicBedForQRCode.length === 0"
|
|
||||||
class="placeholder"
|
|
||||||
>
|
|
||||||
{{ t('navigation.selectPicBeds') }}
|
{{ t('navigation.selectPicBeds') }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span v-else class="selected-count">
|
||||||
v-else
|
|
||||||
class="selected-count"
|
|
||||||
>
|
|
||||||
{{ choosedPicBedForQRCode.length }} {{ t('navigation.selected') }}
|
{{ choosedPicBedForQRCode.length }} {{ t('navigation.selected') }}
|
||||||
</span>
|
</span>
|
||||||
<ChevronDownIcon
|
<ChevronDownIcon :size="16" class="listbox-arrow" />
|
||||||
:size="16"
|
|
||||||
class="listbox-arrow"
|
|
||||||
/>
|
|
||||||
</ListboxButton>
|
</ListboxButton>
|
||||||
|
|
||||||
<transition
|
<transition
|
||||||
@@ -190,15 +123,9 @@
|
|||||||
v-slot="{ active, selected }"
|
v-slot="{ active, selected }"
|
||||||
:value="picbed.type"
|
:value="picbed.type"
|
||||||
>
|
>
|
||||||
<li
|
<li class="listbox-option" :class="{ active, selected }">
|
||||||
class="listbox-option"
|
|
||||||
:class="{ active, selected }"
|
|
||||||
>
|
|
||||||
<span>{{ picbed.name }}</span>
|
<span>{{ picbed.name }}</span>
|
||||||
<CheckIcon
|
<CheckIcon v-if="selected" :size="16" />
|
||||||
v-if="selected"
|
|
||||||
:size="16"
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</ListboxOption>
|
</ListboxOption>
|
||||||
</ListboxOptions>
|
</ListboxOptions>
|
||||||
@@ -206,33 +133,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</Listbox>
|
</Listbox>
|
||||||
|
|
||||||
<button
|
<button v-if="choosedPicBedForQRCode.length > 0" class="copy-button" @click="handleCopyPicBedConfig">
|
||||||
v-if="choosedPicBedForQRCode.length > 0"
|
|
||||||
class="copy-button"
|
|
||||||
@click="handleCopyPicBedConfig"
|
|
||||||
>
|
|
||||||
<CopyIcon :size="16" />
|
<CopyIcon :size="16" />
|
||||||
{{ t('navigation.copyPicBedConfig') }}
|
{{ t('navigation.copyPicBedConfig') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="choosedPicBedForQRCode.length > 0" class="qr-container">
|
||||||
v-if="choosedPicBedForQRCode.length > 0"
|
<qrcode-vue :size="280" :value="picBedConfigString" class="qr-code" />
|
||||||
class="qr-container"
|
|
||||||
>
|
|
||||||
<qrcode-vue
|
|
||||||
:size="280"
|
|
||||||
:value="picBedConfigString"
|
|
||||||
class="qr-code"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dialog-actions">
|
<div class="dialog-actions">
|
||||||
<button
|
<button class="cancel-button" @click="qrcodeVisible = false">
|
||||||
class="cancel-button"
|
|
||||||
@click="qrcodeVisible = false"
|
|
||||||
>
|
|
||||||
{{ $t('navigation.close') }}
|
{{ $t('navigation.close') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -259,7 +172,20 @@ import {
|
|||||||
TransitionRoot
|
TransitionRoot
|
||||||
} from '@headlessui/vue'
|
} from '@headlessui/vue'
|
||||||
import { pick } from 'lodash-es'
|
import { pick } from 'lodash-es'
|
||||||
import { BriefcaseBusiness, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CopyIcon, DatabaseIcon, ImagesIcon, Info, PlugIcon, Settings, UploadIcon } from 'lucide-vue-next'
|
import {
|
||||||
|
BriefcaseBusiness,
|
||||||
|
CheckIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
ChevronLeftIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
CopyIcon,
|
||||||
|
DatabaseIcon,
|
||||||
|
ImagesIcon,
|
||||||
|
Info,
|
||||||
|
PlugIcon,
|
||||||
|
Settings,
|
||||||
|
UploadIcon
|
||||||
|
} from 'lucide-vue-next'
|
||||||
import QrcodeVue from 'qrcode.vue'
|
import QrcodeVue from 'qrcode.vue'
|
||||||
import pkg from 'root/package.json'
|
import pkg from 'root/package.json'
|
||||||
import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, Ref, ref, watch } from 'vue'
|
import { computed, nextTick, onBeforeMount, onBeforeUnmount, reactive, Ref, ref, watch } from 'vue'
|
||||||
@@ -286,7 +212,7 @@ const picBedConfigString = ref('')
|
|||||||
let removeIpcListener: () => void = () => {}
|
let removeIpcListener: () => void = () => {}
|
||||||
|
|
||||||
// Save collapsed state to localStorage when it changes
|
// Save collapsed state to localStorage when it changes
|
||||||
watch(isCollapsed, (newValue) => {
|
watch(isCollapsed, newValue => {
|
||||||
localStorage.setItem('navigation-collapsed', JSON.stringify(newValue))
|
localStorage.setItem('navigation-collapsed', JSON.stringify(newValue))
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -304,19 +230,17 @@ watch(
|
|||||||
{ deep: true }
|
{ deep: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
const visiblePicBeds = computed(() =>
|
const visiblePicBeds = computed(() => picBedGlobal.value.filter(item => item.visible))
|
||||||
picBedGlobal.value.filter(item => item.visible)
|
|
||||||
)
|
|
||||||
|
|
||||||
const qrCodeHandler = () => {
|
const qrCodeHandler = () => {
|
||||||
qrcodeVisible.value = true
|
qrcodeVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function openMenu () {
|
function openMenu() {
|
||||||
window.electron.sendRPC(IRPCActionType.SHOW_MAIN_PAGE_MENU)
|
window.electron.sendRPC(IRPCActionType.SHOW_MAIN_PAGE_MENU)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCopyPicBedConfig () {
|
function handleCopyPicBedConfig() {
|
||||||
window.electron.clipboard.writeText(picBedConfigString.value)
|
window.electron.clipboard.writeText(picBedConfigString.value)
|
||||||
message.success(t('navigation.copySuccess'))
|
message.success(t('navigation.copySuccess'))
|
||||||
}
|
}
|
||||||
@@ -333,7 +257,7 @@ const navigationItems = computed(() => [
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
function openGithubPage () {
|
function openGithubPage() {
|
||||||
window.electron.sendRPC(IRPCActionType.OPEN_URL, 'https://github.com/Kuingsmile/PicList')
|
window.electron.sendRPC(IRPCActionType.OPEN_URL, 'https://github.com/Kuingsmile/PicList')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,7 +275,6 @@ onBeforeMount(() => {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
removeIpcListener()
|
removeIpcListener()
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="toolbox-handler">
|
<div class="toolbox-handler">
|
||||||
<button
|
<button class="handler-button" @click="() => props.handler(value)">
|
||||||
class="handler-button"
|
|
||||||
@click="() => props.handler(value)"
|
|
||||||
>
|
|
||||||
{{ props.handlerText }}
|
{{ props.handlerText }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
status: string
|
status: string
|
||||||
value: any
|
value: any
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<component
|
<component :is="icon" class="toolbox-status-icon" :style="{ color }" />
|
||||||
:is="icon"
|
|
||||||
class="toolbox-status-icon"
|
|
||||||
:style="{ color }"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div id="config-form" :class="[{ white: props.colorMode === 'white' }]">
|
||||||
id="config-form"
|
<form ref="$form" class="config-form" @submit.prevent>
|
||||||
:class="[{ white: props.colorMode === 'white' }]"
|
|
||||||
>
|
|
||||||
<form
|
|
||||||
ref="$form"
|
|
||||||
class="config-form"
|
|
||||||
@submit.prevent
|
|
||||||
>
|
|
||||||
<!-- Config Name Field -->
|
<!-- Config Name Field -->
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label class="form-label">{{ t('pages.configForm.configName') }}</label>
|
<label class="form-label">{{ t('pages.configForm.configName') }}</label>
|
||||||
@@ -20,11 +13,8 @@
|
|||||||
:placeholder="t('pages.configForm.configNamePlaceholder')"
|
:placeholder="t('pages.configForm.configNamePlaceholder')"
|
||||||
:class="{ error: validationErrors._configName }"
|
:class="{ error: validationErrors._configName }"
|
||||||
@input="clearFieldError('_configName')"
|
@input="clearFieldError('_configName')"
|
||||||
>
|
/>
|
||||||
<div
|
<div v-if="validationErrors._configName" class="error-message">
|
||||||
v-if="validationErrors._configName"
|
|
||||||
class="error-message"
|
|
||||||
>
|
|
||||||
{{ validationErrors._configName }}
|
{{ validationErrors._configName }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,14 +29,8 @@
|
|||||||
>
|
>
|
||||||
<div class="form-label-wrapper">
|
<div class="form-label-wrapper">
|
||||||
<label class="form-label">{{ item.alias || item.name }}</label>
|
<label class="form-label">{{ item.alias || item.name }}</label>
|
||||||
<div
|
<div v-if="showTooltips && item.tips" class="tooltip-wrapper">
|
||||||
v-if="showTooltips && item.tips"
|
<div class="info-icon" @click="toggleTooltip(item.name + index)">
|
||||||
class="tooltip-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="info-icon"
|
|
||||||
@click="toggleTooltip(item.name + index)"
|
|
||||||
>
|
|
||||||
<Info :size="20" />
|
<Info :size="20" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -67,23 +51,17 @@
|
|||||||
:placeholder="item.message || item.name"
|
:placeholder="item.message || item.name"
|
||||||
:class="{ error: validationErrors[item.name] }"
|
:class="{ error: validationErrors[item.name] }"
|
||||||
@input="clearFieldError(item.name)"
|
@input="clearFieldError(item.name)"
|
||||||
>
|
/>
|
||||||
|
|
||||||
<!-- Select (Single) -->
|
<!-- Select (Single) -->
|
||||||
<div
|
<div v-else-if="item.type === 'list' && item.choices" class="select-wrapper">
|
||||||
v-else-if="item.type === 'list' && item.choices"
|
|
||||||
class="select-wrapper"
|
|
||||||
>
|
|
||||||
<select
|
<select
|
||||||
v-model="ruleForm[item.name]"
|
v-model="ruleForm[item.name]"
|
||||||
class="form-select"
|
class="form-select"
|
||||||
:class="{ error: validationErrors[item.name] }"
|
:class="{ error: validationErrors[item.name] }"
|
||||||
@change="clearFieldError(item.name)"
|
@change="clearFieldError(item.name)"
|
||||||
>
|
>
|
||||||
<option
|
<option value="" disabled>
|
||||||
value=""
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
{{ item.message || item.name }}
|
{{ item.message || item.name }}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
@@ -100,15 +78,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Multi-Select (Checkbox style) -->
|
<!-- Multi-Select (Checkbox style) -->
|
||||||
<div
|
<div v-else-if="item.type === 'checkbox' && item.choices" class="checkbox-group">
|
||||||
v-else-if="item.type === 'checkbox' && item.choices"
|
<div v-for="choice in item.choices" :key="choice.value || choice" class="checkbox-item">
|
||||||
class="checkbox-group"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="choice in item.choices"
|
|
||||||
:key="choice.value || choice"
|
|
||||||
class="checkbox-item"
|
|
||||||
>
|
|
||||||
<label class="checkbox-label">
|
<label class="checkbox-label">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -116,7 +87,7 @@
|
|||||||
:checked="Array.isArray(ruleForm[item.name]) && ruleForm[item.name].includes(choice.value || choice)"
|
:checked="Array.isArray(ruleForm[item.name]) && ruleForm[item.name].includes(choice.value || choice)"
|
||||||
class="checkbox-input"
|
class="checkbox-input"
|
||||||
@change="handleCheckboxChange(item.name, choice.value || choice, $event)"
|
@change="handleCheckboxChange(item.name, choice.value || choice, $event)"
|
||||||
>
|
/>
|
||||||
<span class="checkbox-custom" />
|
<span class="checkbox-custom" />
|
||||||
<span class="checkbox-text">{{ choice.name || choice.value || choice }}</span>
|
<span class="checkbox-text">{{ choice.name || choice.value || choice }}</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -124,29 +95,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Switch/Toggle -->
|
<!-- Switch/Toggle -->
|
||||||
<label
|
<label v-else-if="item.type === 'confirm'" class="switch-label">
|
||||||
v-else-if="item.type === 'confirm'"
|
|
||||||
class="switch-label"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
v-model="ruleForm[item.name]"
|
v-model="ruleForm[item.name]"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="switch-input"
|
class="switch-input"
|
||||||
@change="clearFieldError(item.name)"
|
@change="clearFieldError(item.name)"
|
||||||
>
|
/>
|
||||||
<span class="switch-slider">
|
<span class="switch-slider">
|
||||||
<span class="switch-button" />
|
<span class="switch-button" />
|
||||||
</span>
|
</span>
|
||||||
<span class="switch-text">
|
<span class="switch-text">
|
||||||
{{ ruleForm[item.name] ? (item.confirmText || 'Yes') : (item.cancelText || 'No') }}
|
{{ ruleForm[item.name] ? item.confirmText || 'Yes' : item.cancelText || 'No' }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<!-- Validation Error -->
|
<!-- Validation Error -->
|
||||||
<div
|
<div v-if="validationErrors[item.name]" class="error-message">
|
||||||
v-if="validationErrors[item.name]"
|
|
||||||
class="error-message"
|
|
||||||
>
|
|
||||||
{{ validationErrors[item.name] }}
|
{{ validationErrors[item.name] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -203,11 +168,11 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
function handleConfigChange (val: any) {
|
function handleConfigChange(val: any) {
|
||||||
handleConfig(val)
|
handleConfig(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateField (fieldName: string, value: any, _?: IPicGoPluginConfig): string | null {
|
function validateField(fieldName: string, value: any, _?: IPicGoPluginConfig): string | null {
|
||||||
if (fieldName === '_configName') {
|
if (fieldName === '_configName') {
|
||||||
if (!value || value.trim() === '') {
|
if (!value || value.trim() === '') {
|
||||||
return 'Configuration name is required'
|
return 'Configuration name is required'
|
||||||
@@ -218,7 +183,7 @@ function validateField (fieldName: string, value: any, _?: IPicGoPluginConfig):
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateForm (): boolean {
|
function validateForm(): boolean {
|
||||||
const errors: IStringKeyMap = {}
|
const errors: IStringKeyMap = {}
|
||||||
|
|
||||||
const configNameError = validateField('_configName', ruleForm._configName)
|
const configNameError = validateField('_configName', ruleForm._configName)
|
||||||
@@ -242,13 +207,13 @@ function validateForm (): boolean {
|
|||||||
return Object.keys(errors).length === 0
|
return Object.keys(errors).length === 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearFieldError (fieldName: string) {
|
function clearFieldError(fieldName: string) {
|
||||||
if (validationErrors[fieldName]) {
|
if (validationErrors[fieldName]) {
|
||||||
delete validationErrors[fieldName]
|
delete validationErrors[fieldName]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleTooltip (key: string) {
|
function toggleTooltip(key: string) {
|
||||||
visibleTooltips[key] = !visibleTooltips[key]
|
visibleTooltips[key] = !visibleTooltips[key]
|
||||||
|
|
||||||
Object.keys(visibleTooltips).forEach(otherKey => {
|
Object.keys(visibleTooltips).forEach(otherKey => {
|
||||||
@@ -258,7 +223,7 @@ function toggleTooltip (key: string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCheckboxChange (fieldName: string, value: any, event: Event) {
|
function handleCheckboxChange(fieldName: string, value: any, event: Event) {
|
||||||
const target = event.target as HTMLInputElement
|
const target = event.target as HTMLInputElement
|
||||||
const currentValues = Array.isArray(ruleForm[fieldName]) ? [...ruleForm[fieldName]] : []
|
const currentValues = Array.isArray(ruleForm[fieldName]) ? [...ruleForm[fieldName]] : []
|
||||||
|
|
||||||
@@ -277,7 +242,7 @@ function handleCheckboxChange (fieldName: string, value: any, event: Event) {
|
|||||||
clearFieldError(fieldName)
|
clearFieldError(fieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validate (): Promise<IStringKeyMap | false> {
|
async function validate(): Promise<IStringKeyMap | false> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const isValid = validateForm()
|
const isValid = validateForm()
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
@@ -288,7 +253,7 @@ async function validate (): Promise<IStringKeyMap | false> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformMarkdownToHTML (markdown: string) {
|
function transformMarkdownToHTML(markdown: string) {
|
||||||
try {
|
try {
|
||||||
return marked.parse(markdown)
|
return marked.parse(markdown)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -296,7 +261,7 @@ function transformMarkdownToHTML (markdown: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getConfigType () {
|
function getConfigType() {
|
||||||
switch (props.type) {
|
switch (props.type) {
|
||||||
case 'plugin': {
|
case 'plugin': {
|
||||||
return props.id
|
return props.id
|
||||||
@@ -312,7 +277,7 @@ function getConfigType () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleConfig (val: IPicGoPluginConfig[]) {
|
async function handleConfig(val: IPicGoPluginConfig[]) {
|
||||||
const config = await getCurConfigFormData()
|
const config = await getCurConfigFormData()
|
||||||
const configId = props.mode === 'picbed' ? $route.params.configId : null
|
const configId = props.mode === 'picbed' ? $route.params.configId : null
|
||||||
|
|
||||||
@@ -325,10 +290,7 @@ async function handleConfig (val: IPicGoPluginConfig[]) {
|
|||||||
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
||||||
|
|
||||||
if (item.type === 'checkbox') {
|
if (item.type === 'checkbox') {
|
||||||
const defaults =
|
const defaults = item.choices?.filter((i: any) => i.checked).map((i: any) => i.value) || []
|
||||||
item.choices
|
|
||||||
?.filter((i: any) => i.checked)
|
|
||||||
.map((i: any) => i.value) || []
|
|
||||||
defaultValue = union(defaultValue, defaults)
|
defaultValue = union(defaultValue, defaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,10 +305,7 @@ async function handleConfig (val: IPicGoPluginConfig[]) {
|
|||||||
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
let defaultValue = item.default !== undefined ? item.default : item.type === 'checkbox' ? [] : null
|
||||||
|
|
||||||
if (item.type === 'checkbox') {
|
if (item.type === 'checkbox') {
|
||||||
const defaults =
|
const defaults = item.choices?.filter((i: any) => i.checked).map((i: any) => i.value) || []
|
||||||
item.choices
|
|
||||||
?.filter((i: any) => i.checked)
|
|
||||||
.map((i: any) => i.value) || []
|
|
||||||
defaultValue = union(defaultValue, defaults)
|
defaultValue = union(defaultValue, defaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +319,7 @@ async function handleConfig (val: IPicGoPluginConfig[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCurConfigFormData () {
|
async function getCurConfigFormData() {
|
||||||
if (props.mode === 'plugin') {
|
if (props.mode === 'plugin') {
|
||||||
return (await getConfig<IStringKeyMap>(`${props.id}`)) || {}
|
return (await getConfig<IStringKeyMap>(`${props.id}`)) || {}
|
||||||
} else {
|
} else {
|
||||||
@@ -370,7 +329,7 @@ async function getCurConfigFormData () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateRuleForm (key: string, value: any) {
|
function updateRuleForm(key: string, value: any) {
|
||||||
try {
|
try {
|
||||||
ruleForm[key] = value
|
ruleForm[key] = value
|
||||||
clearFieldError(key)
|
clearFieldError(key)
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div ref="containerRef" class="virtual-scroller" :style="{ height: `${containerHeight}px` }" @scroll="handleScroll">
|
||||||
ref="containerRef"
|
<div class="virtual-scroller-content" :style="contentStyles">
|
||||||
class="virtual-scroller"
|
|
||||||
:style="{ height: `${containerHeight}px` }"
|
|
||||||
@scroll="handleScroll"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="virtual-scroller-content"
|
|
||||||
:style="contentStyles"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="virtual-scroller-viewport"
|
class="virtual-scroller-viewport"
|
||||||
:class="{ 'is-grid': isGridMode, 'is-list': !isGridMode }"
|
:class="{ 'is-grid': isGridMode, 'is-list': !isGridMode }"
|
||||||
@@ -16,14 +8,15 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="realIndex in visibleIndexes"
|
v-for="realIndex in visibleIndexes"
|
||||||
:key="itemsRef[realIndex] && itemsRef[realIndex][props.keyField || 'id'] ? itemsRef[realIndex][props.keyField || 'id'] : realIndex"
|
:key="
|
||||||
|
itemsRef[realIndex] && itemsRef[realIndex][props.keyField || 'id']
|
||||||
|
? itemsRef[realIndex][props.keyField || 'id']
|
||||||
|
: realIndex
|
||||||
|
"
|
||||||
class="virtual-scroller-item"
|
class="virtual-scroller-item"
|
||||||
:style="itemStyle"
|
:style="itemStyle"
|
||||||
>
|
>
|
||||||
<slot
|
<slot :item="itemsRef[realIndex]" :index="realIndex" />
|
||||||
:item="itemsRef[realIndex]"
|
|
||||||
:index="realIndex"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,29 +29,35 @@ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|||||||
import { useVirtualGrid } from '@/hooks/useVirtualGrid'
|
import { useVirtualGrid } from '@/hooks/useVirtualGrid'
|
||||||
|
|
||||||
type Item = any
|
type Item = any
|
||||||
interface Breakpoint { min: number; cols: number }
|
interface Breakpoint {
|
||||||
|
min: number
|
||||||
|
cols: number
|
||||||
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(
|
||||||
items: Item[]
|
defineProps<{
|
||||||
itemHeight: number
|
items: Item[]
|
||||||
height?: number
|
itemHeight: number
|
||||||
gridItems?: number
|
height?: number
|
||||||
gridBreakpoints?: Breakpoint[]
|
gridItems?: number
|
||||||
bufferFactor?: number
|
gridBreakpoints?: Breakpoint[]
|
||||||
pageMode?: boolean
|
bufferFactor?: number
|
||||||
keyField?: string
|
pageMode?: boolean
|
||||||
itemPadding?: number
|
keyField?: string
|
||||||
viewMode?: 'list' | 'grid'
|
itemPadding?: number
|
||||||
}>(), {
|
viewMode?: 'list' | 'grid'
|
||||||
height: 400,
|
}>(),
|
||||||
gridItems: 1,
|
{
|
||||||
gridBreakpoints: () => [],
|
height: 400,
|
||||||
bufferFactor: 0.5,
|
gridItems: 1,
|
||||||
pageMode: false,
|
gridBreakpoints: () => [],
|
||||||
keyField: 'id',
|
bufferFactor: 0.5,
|
||||||
itemPadding: 0,
|
pageMode: false,
|
||||||
viewMode: 'grid'
|
keyField: 'id',
|
||||||
})
|
itemPadding: 0,
|
||||||
|
viewMode: 'grid'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const containerRef = ref<HTMLElement | null>(null)
|
const containerRef = ref<HTMLElement | null>(null)
|
||||||
const containerHeight = ref<number>(props.pageMode ? 0 : props.height)
|
const containerHeight = ref<number>(props.pageMode ? 0 : props.height)
|
||||||
@@ -66,15 +65,23 @@ const containerWidth = ref<number>(0)
|
|||||||
const parentScrollListeners = ref<HTMLElement[]>([])
|
const parentScrollListeners = ref<HTMLElement[]>([])
|
||||||
|
|
||||||
const itemsRef = ref<Item[]>(props.items)
|
const itemsRef = ref<Item[]>(props.items)
|
||||||
watch(() => props.items, v => { itemsRef.value = v })
|
watch(
|
||||||
|
() => props.items,
|
||||||
const localViewMode = ref< 'list' | 'grid'>(props.viewMode)
|
v => {
|
||||||
watch(() => props.viewMode, v => { localViewMode.value = v })
|
itemsRef.value = v
|
||||||
|
}
|
||||||
const sortedBreakpoints = computed<Breakpoint[]>(() =>
|
|
||||||
[...props.gridBreakpoints].sort((a, b) => a.min - b.min)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const localViewMode = ref<'list' | 'grid'>(props.viewMode)
|
||||||
|
watch(
|
||||||
|
() => props.viewMode,
|
||||||
|
v => {
|
||||||
|
localViewMode.value = v
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const sortedBreakpoints = computed<Breakpoint[]>(() => [...props.gridBreakpoints].sort((a, b) => a.min - b.min))
|
||||||
|
|
||||||
const isForcedList = computed(() => localViewMode.value === 'list')
|
const isForcedList = computed(() => localViewMode.value === 'list')
|
||||||
|
|
||||||
const effectiveCols = computed<number>(() => {
|
const effectiveCols = computed<number>(() => {
|
||||||
@@ -92,19 +99,14 @@ const effectiveCols = computed<number>(() => {
|
|||||||
|
|
||||||
const isGridMode = computed(() => effectiveCols.value > 1)
|
const isGridMode = computed(() => effectiveCols.value > 1)
|
||||||
|
|
||||||
const {
|
const { gridCalculations, visibleIndexes, viewportOffset, updateScrollTop, scrollToItem, scrollToTop, scrollToBottom } =
|
||||||
gridCalculations,
|
useVirtualGrid({
|
||||||
visibleIndexes,
|
items: itemsRef,
|
||||||
viewportOffset,
|
itemHeight: props.itemHeight,
|
||||||
updateScrollTop,
|
containerHeight,
|
||||||
scrollToItem, scrollToTop, scrollToBottom
|
gridItems: effectiveCols,
|
||||||
} = useVirtualGrid({
|
bufferFactor: props.bufferFactor
|
||||||
items: itemsRef,
|
})
|
||||||
itemHeight: props.itemHeight,
|
|
||||||
containerHeight,
|
|
||||||
gridItems: effectiveCols,
|
|
||||||
bufferFactor: props.bufferFactor
|
|
||||||
})
|
|
||||||
|
|
||||||
const contentStyles = computed(() => ({
|
const contentStyles = computed(() => ({
|
||||||
height: `${gridCalculations.value.totalHeight}px`
|
height: `${gridCalculations.value.totalHeight}px`
|
||||||
@@ -122,19 +124,15 @@ const viewportStyle = computed(() => {
|
|||||||
return base
|
return base
|
||||||
})
|
})
|
||||||
|
|
||||||
const itemStyle = computed(() =>
|
const itemStyle = computed(() => (isGridMode.value ? {} : { height: `${props.itemHeight}px` }))
|
||||||
isGridMode.value
|
|
||||||
? {}
|
|
||||||
: { height: `${props.itemHeight}px` }
|
|
||||||
)
|
|
||||||
|
|
||||||
function handleScroll () {
|
function handleScroll() {
|
||||||
const c = containerRef.value
|
const c = containerRef.value
|
||||||
if (!c) return
|
if (!c) return
|
||||||
updateScrollTop(c.scrollTop)
|
updateScrollTop(c.scrollTop)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePageScroll () {
|
function handlePageScroll() {
|
||||||
if (!props.pageMode) return
|
if (!props.pageMode) return
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
if (now - lastScrollTime.value < 16) return
|
if (now - lastScrollTime.value < 16) return
|
||||||
@@ -159,7 +157,7 @@ function handlePageScroll () {
|
|||||||
let ro: ResizeObserver | null = null
|
let ro: ResizeObserver | null = null
|
||||||
const lastScrollTime = ref(0)
|
const lastScrollTime = ref(0)
|
||||||
|
|
||||||
function updateContainerMetrics () {
|
function updateContainerMetrics() {
|
||||||
const el = containerRef.value
|
const el = containerRef.value
|
||||||
if (!el) return
|
if (!el) return
|
||||||
const rect = el.getBoundingClientRect()
|
const rect = el.getBoundingClientRect()
|
||||||
@@ -206,16 +204,18 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function scrollTo (index: number) { scrollToItem(index) }
|
function scrollTo(index: number) {
|
||||||
|
scrollToItem(index)
|
||||||
|
}
|
||||||
|
|
||||||
function setViewMode (mode: 'list' | 'grid') {
|
function setViewMode(mode: 'list' | 'grid') {
|
||||||
localViewMode.value = mode
|
localViewMode.value = mode
|
||||||
}
|
}
|
||||||
function toggleViewMode () {
|
function toggleViewMode() {
|
||||||
setViewMode(isGridMode.value ? 'list' : 'grid')
|
setViewMode(isGridMode.value ? 'list' : 'grid')
|
||||||
}
|
}
|
||||||
|
|
||||||
function refresh () {
|
function refresh() {
|
||||||
updateContainerMetrics()
|
updateContainerMetrics()
|
||||||
if (containerRef.value) {
|
if (containerRef.value) {
|
||||||
updateScrollTop(containerRef.value.scrollTop)
|
updateScrollTop(containerRef.value.scrollTop)
|
||||||
@@ -266,5 +266,4 @@ defineExpose({ scrollTo, scrollToTop, scrollToBottom, setViewMode, toggleViewMod
|
|||||||
.virtual-scroller-viewport.is-grid .virtual-scroller-item {
|
.virtual-scroller-viewport.is-grid .virtual-scroller-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,72 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div v-if="isOpen" class="messagebox-overlay" @click="onCancel">
|
||||||
v-if="isOpen"
|
<div class="messagebox-container" @click.stop>
|
||||||
class="messagebox-overlay"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="messagebox-container"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<div class="messagebox-header">
|
<div class="messagebox-header">
|
||||||
<h3 class="messagebox-title">
|
<h3 class="messagebox-title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button v-if="showClose" class="messagebox-close" @click="onCancel">×</button>
|
||||||
v-if="showClose"
|
|
||||||
class="messagebox-close"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="messagebox-content">
|
<div class="messagebox-content">
|
||||||
<div
|
<div v-if="type" class="messagebox-icon">
|
||||||
v-if="type"
|
<component :is="iconComponent" :size="48" />
|
||||||
class="messagebox-icon"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="iconComponent"
|
|
||||||
:size="48"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="messagebox-message">
|
<div class="messagebox-message">
|
||||||
<p>{{ message }}</p>
|
<p>{{ message }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="center" class="messagebox-actions center">
|
||||||
v-if="center"
|
<button class="messagebox-btn cancel-btn" @click="onCancel">
|
||||||
class="messagebox-actions center"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="messagebox-btn cancel-btn"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
{{ cancelButtonText }}
|
{{ cancelButtonText }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="messagebox-btn confirm-btn" :class="confirmButtonClass" @click="onConfirm">
|
||||||
class="messagebox-btn confirm-btn"
|
|
||||||
:class="confirmButtonClass"
|
|
||||||
@click="onConfirm"
|
|
||||||
>
|
|
||||||
{{ confirmButtonText }}
|
{{ confirmButtonText }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-else class="messagebox-actions">
|
||||||
v-else
|
<button class="messagebox-btn confirm-btn" :class="confirmButtonClass" @click="onConfirm">
|
||||||
class="messagebox-actions"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="messagebox-btn confirm-btn"
|
|
||||||
:class="confirmButtonClass"
|
|
||||||
@click="onConfirm"
|
|
||||||
>
|
|
||||||
{{ confirmButtonText }}
|
{{ confirmButtonText }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="messagebox-btn cancel-btn" @click="onCancel">
|
||||||
class="messagebox-btn cancel-btn"
|
|
||||||
@click="onCancel"
|
|
||||||
>
|
|
||||||
{{ cancelButtonText }}
|
{{ cancelButtonText }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,7 +125,9 @@ export default {
|
|||||||
.messagebox-container {
|
.messagebox-container {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
max-width: 32rem;
|
max-width: 32rem;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
@@ -239,19 +202,19 @@ export default {
|
|||||||
color: rgb(107 114 128);
|
color: rgb(107 114 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="alert-triangle"] {
|
.messagebox-icon svg[data-lucide='alert-triangle'] {
|
||||||
color: rgb(245 158 11);
|
color: rgb(245 158 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="info"] {
|
.messagebox-icon svg[data-lucide='info'] {
|
||||||
color: rgb(59 130 246);
|
color: rgb(59 130 246);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="check-circle"] {
|
.messagebox-icon svg[data-lucide='check-circle'] {
|
||||||
color: rgb(34 197 94);
|
color: rgb(34 197 94);
|
||||||
}
|
}
|
||||||
|
|
||||||
.messagebox-icon svg[data-lucide="x-circle"] {
|
.messagebox-icon svg[data-lucide='x-circle'] {
|
||||||
color: rgb(239 68 68);
|
color: rgb(239 68 68);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="message-container">
|
<div class="message-container">
|
||||||
<TransitionGroup
|
<TransitionGroup name="message" tag="div">
|
||||||
name="message"
|
<div v-for="message in messages" :key="message.id" class="message-toast" :class="getMessageClass(message.type)">
|
||||||
tag="div"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="message in messages"
|
|
||||||
:key="message.id"
|
|
||||||
class="message-toast"
|
|
||||||
:class="getMessageClass(message.type)"
|
|
||||||
>
|
|
||||||
<div class="message-icon">
|
<div class="message-icon">
|
||||||
<component
|
<component :is="getIconComponent(message.type)" :size="20" />
|
||||||
:is="getIconComponent(message.type)"
|
|
||||||
:size="20"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="message-content">
|
<div class="message-content">
|
||||||
{{ message.message }}
|
{{ message.message }}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button v-if="message.showClose" class="message-close" @click="removeMessage(message.id)">
|
||||||
v-if="message.showClose"
|
|
||||||
class="message-close"
|
|
||||||
@click="removeMessage(message.id)"
|
|
||||||
>
|
|
||||||
<X :size="16" />
|
<X :size="16" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,7 +134,9 @@ export default {
|
|||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
box-shadow:
|
||||||
|
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
||||||
|
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||||
max-width: 24rem;
|
max-width: 24rem;
|
||||||
min-width: 20rem;
|
min-width: 20rem;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user