Merge branch 'dev' into release

This commit is contained in:
Kuingsmile 2024-05-26 21:14:06 +08:00
commit aac13e1c39
64 changed files with 781 additions and 703 deletions

View File

@ -34,13 +34,6 @@ jobs:
- name: Check out git repository - name: Check out git repository
uses: actions/checkout@v2 uses: actions/checkout@v2
# step2: sign
- name: Install the Apple certificates
if: matrix.os == 'macos-11'
run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
# step3: install node env # step3: install node env
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v2
@ -52,20 +45,6 @@ jobs:
run: | run: |
sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils
# step3: yarn
- name: Yarn install macos
if: matrix.os == 'macos-11'
run: |
yarn
yarn global add xvfb-maybe
npm rebuild --platform=darwin --arch=arm64 sharp
- name: Yarn install windows
if: matrix.os == 'windows-latest'
run: |
yarn
yarn global add xvfb-maybe
- name: Yarn install linux - name: Yarn install linux
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
run: | run: |

View File

@ -21,7 +21,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-11] os: [macos-12]
steps: steps:
- name: Check out git repository - name: Check out git repository
@ -29,7 +29,7 @@ jobs:
# step2: sign # step2: sign
- name: Install the Apple certificates - name: Install the Apple certificates
if: matrix.os == 'macos-11' if: matrix.os == 'macos-12'
run: | run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
@ -47,7 +47,7 @@ jobs:
# step3: yarn # step3: yarn
- name: Yarn install macos - name: Yarn install macos
if: matrix.os == 'macos-11' if: matrix.os == 'macos-12'
run: | run: |
yarn yarn
yarn global add xvfb-maybe yarn global add xvfb-maybe

View File

@ -26,7 +26,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-11] os: [macos-12]
# create steps # create steps
steps: steps:
@ -36,7 +36,7 @@ jobs:
# step2: sign # step2: sign
- name: Install the Apple certificates - name: Install the Apple certificates
if: matrix.os == 'macos-11' if: matrix.os == 'macos-12'
run: | run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
@ -47,31 +47,14 @@ jobs:
with: with:
node-version: '16.x' node-version: '16.x'
- name: Install system deps
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils
# step3: yarn # step3: yarn
- name: Yarn install macos - name: Yarn install macos
if: matrix.os == 'macos-11' if: matrix.os == 'macos-12'
run: | run: |
yarn yarn
yarn global add xvfb-maybe yarn global add xvfb-maybe
npm rebuild --platform=darwin --arch=arm64 sharp npm rebuild --platform=darwin --arch=arm64 sharp
- name: Yarn install windows
if: matrix.os == 'windows-latest'
run: |
yarn
yarn global add xvfb-maybe
- name: Yarn install linux
if: matrix.os == 'ubuntu-latest'
run: |
yarn
yarn global add xvfb-maybe
- name: Build & release app - name: Build & release app
run: | run: |
yarn build yarn build

View File

@ -24,7 +24,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, macos-11, windows-latest] os: [ubuntu-latest, macos-12, windows-latest]
steps: steps:
- name: Check out git repository - name: Check out git repository
@ -32,7 +32,7 @@ jobs:
# step2: sign # step2: sign
- name: Install the Apple certificates - name: Install the Apple certificates
if: matrix.os == 'macos-11' if: matrix.os == 'macos-12'
run: | run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
@ -50,7 +50,7 @@ jobs:
# step3: yarn # step3: yarn
- name: Yarn install macos - name: Yarn install macos
if: matrix.os == 'macos-11' if: matrix.os == 'macos-12'
run: | run: |
yarn yarn
yarn global add xvfb-maybe yarn global add xvfb-maybe

View File

@ -26,7 +26,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-11] os: [macos-12]
# create steps # create steps
steps: steps:
@ -36,7 +36,7 @@ jobs:
# step2: sign # step2: sign
- name: Install the Apple certificates - name: Install the Apple certificates
if: matrix.os == 'macos-11' if: matrix.os == 'macos-12'
run: | run: |
PP_PATH=$RUNNER_TEMP/build/piclistmas.provisionprofile PP_PATH=$RUNNER_TEMP/build/piclistmas.provisionprofile
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH

View File

@ -34,44 +34,18 @@ jobs:
- name: Check out git repository - name: Check out git repository
uses: actions/checkout@v2 uses: actions/checkout@v2
# step2: sign
- name: Install the Apple certificates
if: matrix.os == 'macos-11'
run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
# step3: install node env # step3: install node env
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: '16.x' node-version: '16.x'
- name: Install system deps
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils
# step3: yarn
- name: Yarn install macos
if: matrix.os == 'macos-11'
run: |
yarn
yarn global add xvfb-maybe
npm rebuild --platform=darwin --arch=arm64 sharp
- name: Yarn install windows - name: Yarn install windows
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
run: | run: |
yarn yarn
yarn global add xvfb-maybe yarn global add xvfb-maybe
- name: Yarn install linux
if: matrix.os == 'ubuntu-latest'
run: |
yarn
yarn global add xvfb-maybe
- name: Build & release app - name: Build & release app
run: | run: |
yarn release yarn release

View File

@ -1,3 +1,37 @@
## :tada: 2.8.6 (2024-05-26)
### :sparkles: Features
* **custom:** add ipc event handlers for mini window icon and set on top ([892a147](https://github.com/Kuingsmile/piclist/commit/892a147))
* **custom:** improve speed of download config files ([e16737e](https://github.com/Kuingsmile/piclist/commit/e16737e))
* **custom:** update manual source URL based on language configuration ([3587bc5](https://github.com/Kuingsmile/piclist/commit/3587bc5))
* **custom:** update manual url for en language ([e6ee325](https://github.com/Kuingsmile/piclist/commit/e6ee325))
* **custom:** write delete msg to log file ([16d6a19](https://github.com/Kuingsmile/piclist/commit/16d6a19))
### :bug: Bug Fixes
* **custom:** fix el-select option display problem ([4f95014](https://github.com/Kuingsmile/piclist/commit/4f95014))
* **custom:** remove listener before unmount ([8b21e84](https://github.com/Kuingsmile/piclist/commit/8b21e84))
### :pencil: Documentation
* **custom:** prepare for 2.8.6 ([4887090](https://github.com/Kuingsmile/piclist/commit/4887090))
### :zap: Performance Improvements
* **custom:** improve the performance of clipboard watching ([4a0a882](https://github.com/Kuingsmile/piclist/commit/4a0a882))
### :package: Chore
* **custom:** update to macos-12 for action ([5eb3c9d](https://github.com/Kuingsmile/piclist/commit/5eb3c9d))
## :tada: 2.8.5 (2024-05-13) ## :tada: 2.8.5 (2024-05-13)

View File

@ -4,7 +4,7 @@ This FAQ has been modified from PicGo's FAQ, and thanks to the author Molunerfin
## Common Questions ## Common Questions
> Please refer to [user manual](https://piclist.cn) for general configuration issues. > Please refer to [user manual](https://piclist.cn/en) for general configuration issues.
## 1. What is the relationship between PicList and PicGo? ## 1. What is the relationship between PicList and PicGo?

View File

@ -1,14 +1,19 @@
### ✨ Features ### ✨ Features
- 现在`upload`接口只传递`picbed`参数时,使用对应图床的默认配置,而不是`Default`配置 - 现在从相册删除云端图片时的日志记录于日志文件中,而不是打印到控制台
- 优化了对smms图床的备用域名的处理逻辑 - 现在软件内窗口打开手册和打开图床手册时,会根据软件语言自动设置语言
- 内置aws S3图床现在设置权限时使用下拉选择框同时`disableBucketPrefixToURL`现在修改为布尔类型 - 现在设置自定义mini窗口图标和保持置顶后会即时生效不再需要重启软件
- 高级重命名现在支持`{str-number}`格式其中number为任意数字新增`{ms}`(毫秒)的支持 - 优化了同步配置时的下载速度
- 管理功能中,上传自定义重命名新增对`{h}`(小时)`{i}`(分钟)`{s}`(秒),,同时`{timestamp}`修改为毫秒,新增对`{str-number}`的支持 - 优化了监听剪贴板功能的性能表现
- 管理功能中,阿里云图床新增对创建`oss-cn-wuhan(华南1-武汉)`地域存储桶的支持
- 优化了重命名占位符说明页面的排版
- Docker版本PicList-core现在修改时区为东八区
### 🐛 Bug Fixes ### 🐛 Bug Fixes
- 修正了高级重命名中时间戳的说明,由秒修改为毫秒 - 修复了第一次进入页面时,下拉选择项显示的默认值是后台值而非标签的问题
- 修复了tray页面监听器没有正确移除的问题
### 📦Chore
- 优化了[官网](https://piclist.cn)的加载速度,添加了`配置文件结构`的说明
- mac打包平台迁移至`macos-12`
- 移除了已废弃的配置项相关的代码
- 移除了管理配置中试剂未使用的`currentPicBedConfig`配置项

View File

@ -1,14 +1,19 @@
### ✨ Features ### ✨ Features
- Now when the `upload` interface only passes the `picbed` parameter, the default configuration of the corresponding image bed is used instead of the `Default` configuration - Now when deleting cloud images from the album, the log is recorded in the log file instead of being printed to the console
- Optimized the processing logic of the backup domain name of the smms image bed - Now when opening the manual and the image bed manual in the software window, the language will be automatically set according to the software language
- The built-in aws S3 image bed now uses a drop-down box when setting permissions, and `disableBucketPrefixToURL` is now modified to a boolean type - Now the custom mini window icon and keep top will take effect immediately after setting, no need to restart the software
- Advanced renaming now supports the `{str-number}` format, where number is any number, and adds support for `{ms}` (milliseconds) - Optimized the download speed of synchronizing configuration
- In the management function, the upload custom renaming adds support for `{h}` (hour), `{i}` (minute), `{s}` (second), and `{timestamp}` is modified to milliseconds, and adds support for `{str-number}` - Optimized the performance of listening to the clipboard function
- In the management function, the Alibaba Cloud image bed adds support for creating `oss-cn-wuhan (South China 1-Wuhan)` regional storage buckets
- Optimized the layout of the placeholder description page for renaming
- The Docker version of PicList-core now changes the time zone to East Eight District
### 🐛 Bug Fixes ### 🐛 Bug Fixes
- Fixed the description of the timestamp in advanced renaming, changed from seconds to milliseconds - Fixed the problem that the default value displayed in the drop-down selection when entering the page for the first time is the background value rather than the label
- Fixed the problem that the tray page listener was not correctly removed
### 📦Chore
- Optimized the loading speed of [official website](https://piclist.cn), added the description of `configuration file structure`
- Mac packaging platform migrated to `macos-12`
- Removed the code related to the deprecated configuration items
- Removed the `currentPicBedConfig` configuration item that is not used in the management configuration

View File

@ -1,6 +1,6 @@
{ {
"name": "piclist", "name": "piclist",
"version": "2.8.5", "version": "2.8.6",
"author": { "author": {
"name": "Kuingsmile", "name": "Kuingsmile",
"email": "pkukuing@gmail.com" "email": "pkukuing@gmail.com"

View File

@ -54,7 +54,7 @@ TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: "Please create the folder yourself
MANUAL_PAGE_OPEN_TIP: Please select the way to open the manual MANUAL_PAGE_OPEN_TIP: Please select the way to open the manual
MANUAL_PAGE_OPEN_TIP_TITLE: Tips MANUAL_PAGE_OPEN_TIP_TITLE: Tips
MANUAL_PAGE_OPEN_BY_BROWSER: Browser MANUAL_PAGE_OPEN_BY_BROWSER: Browser
MANUAL_PAGE_OPEN_BY_BUILD_IN: Built-in MANUAL_PAGE_OPEN_BY_BUILD_IN: Built-in Window
MANUAL_PAGE_OPEN_SETTING_TIP: Select the way to open the manual MANUAL_PAGE_OPEN_SETTING_TIP: Select the way to open the manual
# ---renderer i18n begin--- # ---renderer i18n begin---

View File

@ -54,7 +54,7 @@ TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: 请自行创建文件夹:${path}
MANUAL_PAGE_OPEN_TIP: 请选择打开方式 MANUAL_PAGE_OPEN_TIP: 请选择打开方式
MANUAL_PAGE_OPEN_TIP_TITLE: Tips MANUAL_PAGE_OPEN_TIP_TITLE: Tips
MANUAL_PAGE_OPEN_BY_BROWSER: 浏览器 MANUAL_PAGE_OPEN_BY_BROWSER: 浏览器
MANUAL_PAGE_OPEN_BY_BUILD_IN: 内置 MANUAL_PAGE_OPEN_BY_BUILD_IN: 内置窗口
MANUAL_PAGE_OPEN_SETTING_TIP: 选择手册打开方式 MANUAL_PAGE_OPEN_SETTING_TIP: 选择手册打开方式
# ---renderer i18n begin--- # ---renderer i18n begin---

View File

@ -54,7 +54,7 @@ TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: 請自行創建文件夾:${path}
MANUAL_PAGE_OPEN_TIP: 請選擇打開方式 MANUAL_PAGE_OPEN_TIP: 請選擇打開方式
MANUAL_PAGE_OPEN_TIP_TITLE: Tips MANUAL_PAGE_OPEN_TIP_TITLE: Tips
MANUAL_PAGE_OPEN_BY_BROWSER: 瀏覽器 MANUAL_PAGE_OPEN_BY_BROWSER: 瀏覽器
MANUAL_PAGE_OPEN_BY_BUILD_IN: 內置 MANUAL_PAGE_OPEN_BY_BUILD_IN: 內置窗口s
MANUAL_PAGE_OPEN_SETTING_TIP: 選擇打開手冊方式 MANUAL_PAGE_OPEN_SETTING_TIP: 選擇打開手冊方式
# ---renderer i18n begin--- # ---renderer i18n begin---

View File

@ -140,7 +140,7 @@ async function deleteSFTPFile (config: ISftpPlistConfig, fileName: string) {
client.close() client.close()
return deleteResult return deleteResult
} catch (err: any) { } catch (err: any) {
console.error(err) picgo.log.error(err)
return false return false
} }
} }

View File

@ -38,7 +38,7 @@ import { configPaths } from '~/universal/utils/configPaths'
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => { const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
return new Promise((resolve) => { return new Promise((resolve) => {
const windowId = window.id const windowId = window.id
ipcMain.once(`${RENAME_FILE_NAME}${id}`, (evt: Event, newName: string) => { ipcMain.once(`${RENAME_FILE_NAME}${id}`, (_: Event, newName: string) => {
resolve(newName) resolve(newName)
window.close() window.close()
}) })

View File

@ -14,7 +14,7 @@ import {
import windowManager from 'apis/app/window/windowManager' import windowManager from 'apis/app/window/windowManager'
// 枚举类型声明 // 枚举类型声明
import { IPasteStyle, IWindowList } from '#/types/enum' import { ILogType, IPasteStyle, IWindowList } from '#/types/enum'
// 上传器 // 上传器
import uploader from 'apis/app/uploader' import uploader from 'apis/app/uploader'
@ -91,8 +91,11 @@ import { ISftpPlistConfig } from 'piclist'
import { removeFileFromS3InMain, removeFileFromDogeInMain, removeFileFromHuaweiInMain } from '~/main/utils/deleteFunc' import { removeFileFromS3InMain, removeFileFromDogeInMain, removeFileFromHuaweiInMain } from '~/main/utils/deleteFunc'
import webServer from '../server/webServer' import webServer from '../server/webServer'
import { configPaths } from '~/universal/utils/configPaths' import { configPaths } from '~/universal/utils/configPaths'
import logger from '../apis/core/picgo/logger'
const STORE_PATH = app.getPath('userData') const STORE_PATH = app.getPath('userData')
const commonConfigList = ['data.json', 'data.bak.json']
const manageConfigList = ['manage.json', 'manage.bak.json']
export default { export default {
listen () { listen () {
@ -152,7 +155,7 @@ export default {
} }
}) })
ipcMain.on('bindOrUnbindShortKey', (evt: IpcMainEvent, item: IShortKeyConfig, from: string) => { ipcMain.on('bindOrUnbindShortKey', (_: IpcMainEvent, item: IShortKeyConfig, from: string) => {
const result = shortKeyHandler.bindOrUnbindShortKey(item, from) const result = shortKeyHandler.bindOrUnbindShortKey(item, from)
if (result) { if (result) {
const notification = new Notification({ const notification = new Notification({
@ -170,7 +173,12 @@ export default {
}) })
// Gallery image cloud delete IPC // Gallery image cloud delete IPC
ipcMain.handle('delete-sftp-file', async (_evt: IpcMainInvokeEvent, config: ISftpPlistConfig, fileName: string) => {
ipcMain.on('logDeleteMsg', async (_: IpcMainEvent, msg: string, logLevel: ILogType) => {
logger[logLevel](msg)
})
ipcMain.handle('delete-sftp-file', async (_: IpcMainInvokeEvent, config: ISftpPlistConfig, fileName: string) => {
try { try {
const client = SSHClient.instance const client = SSHClient.instance
await client.connect(config) await client.connect(config)
@ -180,22 +188,22 @@ export default {
client.close() client.close()
return deleteResult return deleteResult
} catch (err: any) { } catch (err: any) {
console.error(err) logger.error(err)
return false return false
} }
}) })
ipcMain.handle('delete-aws-s3-file', async (_evt: IpcMainInvokeEvent, configMap: IStringKeyMap) => { ipcMain.handle('delete-aws-s3-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
const result = await removeFileFromS3InMain(configMap) const result = await removeFileFromS3InMain(configMap)
return result return result
}) })
ipcMain.handle('delete-doge-file', async (_evt: IpcMainInvokeEvent, configMap: IStringKeyMap) => { ipcMain.handle('delete-doge-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
const result = await removeFileFromDogeInMain(configMap) const result = await removeFileFromDogeInMain(configMap)
return result return result
}) })
ipcMain.handle('delete-huaweicloud-file', async (_evt: IpcMainInvokeEvent, configMap: IStringKeyMap) => { ipcMain.handle('delete-huaweicloud-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
const result = await removeFileFromHuaweiInMain(configMap) const result = await removeFileFromHuaweiInMain(configMap)
return result return result
}) })
@ -204,27 +212,23 @@ export default {
ipcMain.handle('migrateFromPicGo', async () => { ipcMain.handle('migrateFromPicGo', async () => {
const picGoConfigPath = STORE_PATH.replace('piclist', 'picgo') const picGoConfigPath = STORE_PATH.replace('piclist', 'picgo')
const fileToMigration = [ const files = [
'data.json', 'data.json',
'data.bak.json', 'data.bak.json',
'picgo.db', 'picgo.db',
'picgo.bak.db' 'picgo.bak.db'
] ]
const targetFileNames = [
'data.json',
'data.bak.json',
'piclist.db',
'piclist.bak.db'
]
try { try {
for (let i = 0; i < fileToMigration.length; i++) { await Promise.all(files.map(async file => {
if (fs.existsSync(path.join(picGoConfigPath, fileToMigration[i]))) { const sourcePath = path.join(picGoConfigPath, file)
fs.removeSync(path.join(STORE_PATH, targetFileNames[i])) const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist'))
fs.copyFileSync(path.join(picGoConfigPath, fileToMigration[i]), path.join(STORE_PATH, targetFileNames[i])) await fs.remove(targetPath)
} await fs.copy(sourcePath, targetPath, { overwrite: true })
} }
))
return true return true
} catch (e) { } catch (err: any) {
logger.error(err)
return false return false
} }
}) })
@ -239,55 +243,39 @@ export default {
notification.show() notification.show()
}) })
ipcMain.on('autoStart', (evt: IpcMainEvent, val: boolean) => { ipcMain.on('autoStart', (_: IpcMainEvent, val: boolean) => {
app.setLoginItemSettings({ app.setLoginItemSettings({
openAtLogin: val openAtLogin: val
}) })
}) })
ipcMain.handle('getShortUrl', async (evt: IpcMainInvokeEvent, url: string) => { ipcMain.handle('getShortUrl', async (_: IpcMainInvokeEvent, url: string) => {
const shortUrl = await generateShortUrl(url) const shortUrl = await generateShortUrl(url)
return shortUrl return shortUrl
}) })
ipcMain.handle('uploadCommonConfig', async () => { ipcMain.handle('uploadCommonConfig', async () => {
const dataResult = await uploadFile('data.json') return await uploadFile(commonConfigList)
const bakResult = await uploadFile('data.bak.json')
return dataResult + bakResult
}) })
ipcMain.handle('downloadCommonConfig', async () => { ipcMain.handle('downloadCommonConfig', async () => {
const dataResult = await downloadFile('data.json') return await downloadFile(commonConfigList)
const bakResult = await downloadFile('data.bak.json')
return dataResult + bakResult
}) })
ipcMain.handle('uploadManageConfig', async () => { ipcMain.handle('uploadManageConfig', async () => {
const manageResult = await uploadFile('manage.json') return await uploadFile(manageConfigList)
const bakResult = await uploadFile('manage.bak.json')
return manageResult + bakResult
}) })
ipcMain.handle('downloadManageConfig', async () => { ipcMain.handle('downloadManageConfig', async () => {
const manageResult = await downloadFile('manage.json') return await downloadFile(manageConfigList)
const bakResult = await downloadFile('manage.bak.json')
return manageResult + bakResult
}) })
ipcMain.handle('uploadAllConfig', async () => { ipcMain.handle('uploadAllConfig', async () => {
const dataResult = await uploadFile('data.json') return await uploadFile([...commonConfigList, ...manageConfigList])
const bakResult = await uploadFile('data.bak.json')
const manageResult = await uploadFile('manage.json')
const manageBakResult = await uploadFile('manage.bak.json')
return dataResult + bakResult + manageResult + manageBakResult
}) })
ipcMain.handle('downloadAllConfig', async () => { ipcMain.handle('downloadAllConfig', async () => {
const dataResult = await downloadFile('data.json') return await downloadFile([...commonConfigList, ...manageConfigList])
const bakResult = await downloadFile('data.bak.json')
const manageResult = await downloadFile('manage.json')
const manageBakResult = await downloadFile('manage.bak.json')
return dataResult + bakResult + manageResult + manageBakResult
}) })
ipcMain.on('toggleMainWindowAlwaysOnTop', () => { ipcMain.on('toggleMainWindowAlwaysOnTop', () => {
@ -337,6 +325,16 @@ export default {
settingWindow.hide() settingWindow.hide()
}) })
ipcMain.on('updateMiniIcon', (_: IpcMainEvent, iconPath: string) => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.webContents.send('updateMiniIcon', iconPath)
})
ipcMain.on('miniWindowOntop', (_: IpcMainEvent, val: boolean) => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.setAlwaysOnTop(val)
})
ipcMain.on('refreshSettingWindow', () => { ipcMain.on('refreshSettingWindow', () => {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
settingWindow.webContents.reloadIgnoringCache() settingWindow.webContents.reloadIgnoringCache()
@ -355,7 +353,7 @@ export default {
evt.returnValue = picBeds evt.returnValue = picBeds
}) })
ipcMain.on(TOGGLE_SHORTKEY_MODIFIED_MODE, (evt: IpcMainEvent, val: boolean) => { ipcMain.on(TOGGLE_SHORTKEY_MODIFIED_MODE, (_: IpcMainEvent, val: boolean) => {
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, val) bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, val)
}) })
@ -393,7 +391,7 @@ export default {
window window
}) })
}) })
ipcMain.on(SHOW_PLUGIN_PAGE_MENU, (evt: IpcMainEvent, plugin: IPicGoPlugin) => { ipcMain.on(SHOW_PLUGIN_PAGE_MENU, (_: IpcMainEvent, plugin: IPicGoPlugin) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)! const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildPluginPageMenu(plugin) const menu = buildPluginPageMenu(plugin)
menu.popup({ menu.popup({
@ -412,22 +410,22 @@ export default {
window?.close() window?.close()
} }
}) })
ipcMain.on(OPEN_USER_STORE_FILE, (evt: IpcMainEvent, filePath: string) => { ipcMain.on(OPEN_USER_STORE_FILE, (_: IpcMainEvent, filePath: string) => {
const abFilePath = path.join(STORE_PATH, filePath) const abFilePath = path.join(STORE_PATH, filePath)
shell.openPath(abFilePath) shell.openPath(abFilePath)
}) })
ipcMain.on(OPEN_URL, (evt: IpcMainEvent, url: string) => { ipcMain.on(OPEN_URL, (_: IpcMainEvent, url: string) => {
shell.openExternal(url) shell.openExternal(url)
}) })
ipcMain.on(RELOAD_APP, () => { ipcMain.on(RELOAD_APP, () => {
app.relaunch() app.relaunch()
app.exit(0) app.exit(0)
}) })
ipcMain.on(SET_MINI_WINDOW_POS, (evt: IpcMainEvent, pos: IMiniWindowPos) => { ipcMain.on(SET_MINI_WINDOW_POS, (_: IpcMainEvent, pos: IMiniWindowPos) => {
const window = BrowserWindow.getFocusedWindow() const window = BrowserWindow.getFocusedWindow()
window?.setBounds(pos) window?.setBounds(pos)
}) })
ipcMain.on(HIDE_DOCK, (_evt: IpcMainEvent, val: boolean) => { ipcMain.on(HIDE_DOCK, (_: IpcMainEvent, val: boolean) => {
if (val) { if (val) {
app.dock.hide() app.dock.hide()
} else { } else {

View File

@ -180,8 +180,8 @@ class LifeCycle {
shortKeyHandler.init() shortKeyHandler.init()
}) })
server.startup() server.startup()
startFileServer()
webServer.start() webServer.start()
startFileServer()
if (process.env.NODE_ENV !== 'development') { if (process.env.NODE_ENV !== 'development') {
handleStartUpFiles(process.argv, process.cwd()) handleStartUpFiles(process.argv, process.cwd())
} }
@ -229,7 +229,7 @@ class LifeCycle {
} }
#onRunning () { #onRunning () {
app.on('second-instance', (event, 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)
if (!result) { if (!result) {

View File

@ -217,7 +217,7 @@ class AliyunApi {
const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com`
let marker let marker
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -264,7 +264,7 @@ class AliyunApi {
const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com` const urlPrefix = configMap.customUrl || `https://${bucket}.${region}.aliyuncs.com`
let marker let marker
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -154,7 +154,7 @@ class GithubApi {
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, '')
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -205,7 +205,7 @@ class GithubApi {
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, '')
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -99,7 +99,7 @@ class ImgurApi {
const window = windowManager.get(IWindowList.SETTING_WINDOW)! const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const { bucketConfig: { Location: albumHash }, cancelToken } = configMap const { bucketConfig: { Location: albumHash }, cancelToken } = configMap
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -93,7 +93,7 @@ class LocalApi {
const { prefix, customUrl = '', cancelToken } = configMap const { prefix, customUrl = '', cancelToken } = configMap
const urlPrefix = customUrl.replace(/\/+$/, '') const urlPrefix = customUrl.replace(/\/+$/, '')
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -140,7 +140,7 @@ class LocalApi {
} }
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -252,7 +252,7 @@ class QiniuApi {
let marker = undefined as any let marker = undefined as any
const slicedPrefix = prefix.slice(1) const slicedPrefix = prefix.slice(1)
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -308,7 +308,7 @@ class QiniuApi {
let marker = undefined as any let marker = undefined as any
const slicedPrefix = prefix.slice(1) const slicedPrefix = prefix.slice(1)
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -247,7 +247,7 @@ class S3plistApi {
const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com`
let marker let marker
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -305,7 +305,7 @@ class S3plistApi {
const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com` const urlPrefix = configMap.customUrl || `https://${bucket}.s3.amazonaws.com`
let marker let marker
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -173,7 +173,7 @@ class SftpApi {
const { prefix, customUrl, cancelToken } = configMap const { prefix, customUrl, cancelToken } = configMap
const urlPrefix = customUrl || `${this.host}:${this.port}` const urlPrefix = customUrl || `${this.host}:${this.port}`
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -244,7 +244,7 @@ class SftpApi {
webPath = webPath.replace(/^\/+|\/+$/, '') webPath = webPath.replace(/^\/+|\/+$/, '')
} }
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -76,7 +76,7 @@ class SmmsApi {
const { cancelToken } = configMap const { cancelToken } = configMap
let marker = 1 let marker = 1
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -129,7 +129,7 @@ class TcyunApi {
const cancelTask = [false] const cancelTask = [false]
let marker let marker
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -174,7 +174,7 @@ class TcyunApi {
const cancelTask = [false] const cancelTask = [false]
let marker let marker
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -129,7 +129,7 @@ class UpyunApi {
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`
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -182,7 +182,7 @@ class UpyunApi {
const urlPrefix = configMap.customUrl || `http://${bucket}.test.upcdn.net` const urlPrefix = configMap.customUrl || `http://${bucket}.test.upcdn.net`
let marker = '' let marker = ''
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -119,7 +119,7 @@ class WebdavplistApi {
const { prefix, customUrl, cancelToken } = configMap const { prefix, customUrl, cancelToken } = configMap
const urlPrefix = customUrl || this.endpoint const urlPrefix = customUrl || this.endpoint
const cancelTask = [false] const cancelTask = [false]
ipcMain.on(cancelDownloadLoadingFileList, (_evt: IpcMainEvent, token: string) => { ipcMain.on(cancelDownloadLoadingFileList, (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners(cancelDownloadLoadingFileList) ipcMain.removeAllListeners(cancelDownloadLoadingFileList)
@ -164,7 +164,7 @@ class WebdavplistApi {
webPath = webPath.replace(/^\/+|\/+$/, '') webPath = webPath.replace(/^\/+|\/+$/, '')
} }
const cancelTask = [false] const cancelTask = [false]
ipcMain.on('cancelLoadingFileList', (_evt: IpcMainEvent, token: string) => { ipcMain.on('cancelLoadingFileList', (_: IpcMainEvent, token: string) => {
if (token === cancelToken) { if (token === cancelToken) {
cancelTask[0] = true cancelTask[0] = true
ipcMain.removeAllListeners('cancelLoadingFileList') ipcMain.removeAllListeners('cancelLoadingFileList')

View File

@ -11,8 +11,7 @@ class ManageDB {
this.#db = new JSONStore(this.#ctx.configPath) this.#db = new JSONStore(this.#ctx.configPath)
let initParams: IStringKeyMap = { let initParams: IStringKeyMap = {
picBed: {}, picBed: {},
settings: {}, settings: {}
currentPicBed: 'placeholder'
} }
for (let key in initParams) { for (let key in initParams) {
if (!this.#db.has(key)) { if (!this.#db.has(key)) {

View File

@ -11,58 +11,58 @@ export const manageIpcList = {
listen () { listen () {
manageCoreIPC.listen() manageCoreIPC.listen()
ipcMain.handle('getBucketList', async (_evt: IpcMainInvokeEvent, currentPicBed: string) => { ipcMain.handle('getBucketList', async (_: IpcMainInvokeEvent, currentPicBed: string) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.getBucketList() return manage.getBucketList()
}) })
ipcMain.handle('createBucket', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('createBucket', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.createBucket(param) return manage.createBucket(param)
}) })
ipcMain.handle('getBucketFileList', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('getBucketFileList', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.getBucketFileList(param) return manage.getBucketFileList(param)
}) })
ipcMain.handle('getBucketDomain', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('getBucketDomain', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
const result = await manage.getBucketDomain(param) const result = await manage.getBucketDomain(param)
return result return result
}) })
ipcMain.handle('setBucketAclPolicy', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('setBucketAclPolicy', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.setBucketAclPolicy(param) return manage.setBucketAclPolicy(param)
}) })
ipcMain.handle('renameBucketFile', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('renameBucketFile', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.renameBucketFile(param) return manage.renameBucketFile(param)
}) })
ipcMain.handle('deleteBucketFile', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('deleteBucketFile', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.deleteBucketFile(param) return manage.deleteBucketFile(param)
}) })
ipcMain.handle('deleteBucketFolder', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('deleteBucketFolder', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.deleteBucketFolder(param) return manage.deleteBucketFolder(param)
}) })
ipcMain.on('getBucketListBackstage', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.on('getBucketListBackstage', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.getBucketListBackstage(param) return manage.getBucketListBackstage(param)
}) })
ipcMain.on('getBucketListRecursively', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.on('getBucketListRecursively', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.getBucketListRecursively(param) return manage.getBucketListRecursively(param)
}) })
ipcMain.handle('convertPathToBase64', async (_evt: IpcMainInvokeEvent, filePath: string) => { ipcMain.handle('convertPathToBase64', async (_: IpcMainInvokeEvent, filePath: string) => {
const res = fs.readFileSync(filePath, 'base64') const res = fs.readFileSync(filePath, 'base64')
return res return res
}) })
@ -78,7 +78,7 @@ export const manageIpcList = {
} }
}) })
ipcMain.handle('getPreSignedUrl', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('getPreSignedUrl', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.getPreSignedUrl(param) return manage.getPreSignedUrl(param)
}) })
@ -91,17 +91,17 @@ export const manageIpcList = {
return UpDownTaskQueue.getInstance().getAllDownloadTask() return UpDownTaskQueue.getInstance().getAllDownloadTask()
}) })
ipcMain.on('uploadBucketFile', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.on('uploadBucketFile', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.uploadBucketFile(param) return manage.uploadBucketFile(param)
}) })
ipcMain.on('downloadBucketFile', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.on('downloadBucketFile', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.downloadBucketFile(param) return manage.downloadBucketFile(param)
}) })
ipcMain.handle('createBucketFolder', async (_evt: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => { ipcMain.handle('createBucketFolder', async (_: IpcMainInvokeEvent, currentPicBed: string, param: IStringKeyMap) => {
const manage = new ManageApi(currentPicBed) const manage = new ManageApi(currentPicBed)
return manage.createBucketFolder(param) return manage.createBucketFolder(param)
}) })
@ -133,7 +133,7 @@ export const manageIpcList = {
return app.getPath('downloads') return app.getPath('downloads')
}) })
ipcMain.on('OpenDownloadedFolder', async (_evt: IpcMainInvokeEvent, path: string | undefined) => { ipcMain.on('OpenDownloadedFolder', async (_: IpcMainInvokeEvent, path: string | undefined) => {
if (path) { if (path) {
shell.showItemInFolder(path) shell.showItemInFolder(path)
} else { } else {
@ -141,11 +141,11 @@ export const manageIpcList = {
} }
}) })
ipcMain.on('OpenLocalFile', async (_evt: IpcMainInvokeEvent, fullPath: string) => { ipcMain.on('OpenLocalFile', async (_: IpcMainInvokeEvent, fullPath: string) => {
fs.existsSync(fullPath) ? shell.showItemInFolder(fullPath) : shell.openPath(path.dirname(fullPath)) fs.existsSync(fullPath) ? shell.showItemInFolder(fullPath) : shell.openPath(path.dirname(fullPath))
}) })
ipcMain.handle('downloadFileFromUrl', async (_evt: IpcMainInvokeEvent, urls: string[]) => { ipcMain.handle('downloadFileFromUrl', async (_: IpcMainInvokeEvent, urls: string[]) => {
const res = await downloadFileFromUrl(urls) const res = await downloadFileFromUrl(urls)
return res return res
}) })

View File

@ -31,7 +31,7 @@ export class ManageApi extends EventEmitter implements ManageApiType {
constructor (currentPicBed: string = '') { constructor (currentPicBed: string = '') {
super() super()
this.currentPicBed = currentPicBed || (this.getConfig('currentPicBed') ?? 'placeholder') this.currentPicBed = currentPicBed || 'placeholder'
this.configPath = managePathChecker() this.configPath = managePathChecker()
this.initConfigPath() this.initConfigPath()
this.logger = new ManageLogger(this) this.logger = new ManageLogger(this)

View File

@ -1,51 +1,49 @@
import { clipboard, nativeImage } from 'electron' import { clipboard } from 'electron'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import crypto from 'crypto'
import logger from '../apis/core/picgo/logger'
class ClipboardWatcher extends EventEmitter { class ClipboardWatcher extends EventEmitter {
lastImage: Electron.NativeImage | null
timer: NodeJS.Timeout | null timer: NodeJS.Timeout | null
lastImageHash: string | null
constructor () { constructor () {
super() super()
this.lastImage = null this.lastImageHash = null
this.timer = null this.timer = null
} }
startListening (watchDelay = 500) { startListening (watchDelay = 500) {
this.stopListening() this.stopListening(false)
const image = clipboard.readImage()
if (!image.isEmpty()) {
const dataUrl = image.toDataURL()
this.lastImage = nativeImage.createFromDataURL(dataUrl)
}
this.timer = setInterval(() => { this.timer = setInterval(() => {
const image = clipboard.readImage() const image = clipboard.readImage()
if (image.isEmpty()) { if (image.isEmpty()) return
const currentImageHash = this.getImageHash(image)
if (this.lastImageHash === null || this.lastImageHash === currentImageHash) {
this.lastImageHash = currentImageHash
return return
} }
const dataUrl = image.toDataURL() this.lastImageHash = currentImageHash
const currentImage = nativeImage.createFromDataURL(dataUrl) this.emit('change')
if (this.lastImage) {
const lastDataUrl = this.lastImage.toDataURL()
if (lastDataUrl === dataUrl) {
return
}
}
this.lastImage = currentImage
this.emit('change', currentImage)
}, watchDelay) }, watchDelay)
logger.info('Start to watch clipboard')
} }
stopListening () { stopListening (isLog = true) {
if (this.timer) { if (this.timer) {
clearInterval(this.timer) clearInterval(this.timer)
this.timer = null this.timer = null
this.lastImageHash = null
} }
isLog && logger.info('Stop to watch clipboard')
}
getImageHash (image: Electron.NativeImage): string {
const buffer = image.toBitmap()
return crypto.createHash('md5').update(buffer).digest('hex')
} }
} }

View File

@ -59,25 +59,15 @@ export const showMessageBox = (options: any) => {
} }
export const calcDurationRange = (duration: number) => { export const calcDurationRange = (duration: number) => {
if (duration < 1000) { if (duration < 1000) return 500
return 500 if (duration < 1500) return 1000
} else if (duration < 1500) { if (duration < 3000) return 2000
return 1000 if (duration < 5000) return 3000
} else if (duration < 3000) { if (duration < 7000) return 5000
return 2000 if (duration < 10000) return 8000
} else if (duration < 5000) { if (duration < 12000) return 10000
return 3000 if (duration < 20000) return 15000
} else if (duration < 7000) { if (duration < 30000) return 20000
return 5000
} else if (duration < 10000) {
return 8000
} else if (duration < 12000) {
return 10000
} else if (duration < 20000) {
return 15000
} else if (duration < 30000) {
return 20000
}
// max range // max range
return 100000 return 100000
} }
@ -105,22 +95,19 @@ export const ensureFilePath = (filePath: string, prefix = 'file://'): string =>
export const getClipboardFilePath = (): string => { export const getClipboardFilePath = (): string => {
// TODO: linux support // TODO: linux support
const img = clipboard.readImage() const img = clipboard.readImage()
if (img.isEmpty()) { const platform = process.platform
if (process.platform === 'win32') {
const imgPath = clipboard.readBuffer('FileNameW')?.toString('ucs2')?.replace(RegExp(String.fromCharCode(0), 'g'), '') if (!img.isEmpty() && platform === 'darwin') {
if (imgPath) { let imgPath = clipboard.read('public.file-url') // will get file://xxx/xxx
return imgPath imgPath = ensureFilePath(imgPath)
} return imgPath ? imgPath.replace('file://', '') : ''
}
} else {
if (process.platform === 'darwin') {
let imgPath = clipboard.read('public.file-url') // will get file://xxx/xxx
imgPath = ensureFilePath(imgPath)
if (imgPath) {
return imgPath.replace('file://', '')
}
}
} }
if (img.isEmpty() && platform === 'win32') {
const imgPath = clipboard.readBuffer('FileNameW')?.toString('ucs2')?.replace(RegExp(String.fromCharCode(0), 'g'), '')
return imgPath || ''
}
return '' return ''
} }
@ -128,66 +115,86 @@ export const handleUrlEncodeWithSetting = (url: string) => db.get(configPaths.se
const c1nApi = 'https://c1n.cn/link/short' const c1nApi = 'https://c1n.cn/link/short'
export const generateShortUrl = async (url: string) => { const generateC1NShortUrl = async (url: string) => {
const server = db.get(configPaths.settings.shortUrlServer) || IShortUrlServer.C1N const c1nToken = db.get(configPaths.settings.c1nToken) || ''
if (server === IShortUrlServer.C1N) { if (!c1nToken) {
logger.warn('c1n token is not set')
return url
}
try {
const form = new FormData() const form = new FormData()
form.append('url', url) form.append('url', url)
const c1nToken = db.get(configPaths.settings.c1nToken) || '' const res = await axios.post(c1nApi, form, {
if (!c1nToken) { headers: {
logger.warn('c1n token is not set') token: c1nToken
return url
}
try {
const res = await axios.post(c1nApi, form, {
headers: {
token: c1nToken
}
})
if (res.status >= 200 && res.status < 300 && res.data?.code === 0) {
return res.data.data
} }
} catch (e: any) { })
logger.error(e) if (res.status >= 200 && res.status < 300 && res.data?.code === 0) {
} return res.data.data
} else if (server === IShortUrlServer.YOURLS) {
let domain = db.get(configPaths.settings.yourlsDomain) || ''
const signature = db.get(configPaths.settings.yourlsSignature) || ''
if (domain && signature) {
if (!/^https?:\/\//.test(domain)) {
domain = `http://${domain}`
}
try {
const res = await axios.get(`${domain}/yourls-api.php?signature=${signature}&action=shorturl&format=json&url=${url}`)
if (res.data.shorturl) {
return res.data.shorturl
}
} catch (e: any) {
if (e.response.data.message.indexOf('already exists in database') !== -1) {
return e.response.data.shorturl
}
logger.error(e)
}
} else {
logger.warn('Yourls server or signature is not set')
}
} else if (server === IShortUrlServer.CFWORKER) {
let cfWorkerHost = db.get(configPaths.settings.cfWorkerHost) || ''
cfWorkerHost = cfWorkerHost.replace(/\/$/, '')
if (cfWorkerHost) {
try {
const res = await axios.post(cfWorkerHost, {
url
})
if (res.data.status === 200 && res.data.key.startsWith('/')) {
return `${cfWorkerHost}${res.data.key}`
}
} catch (e: any) {
logger.error(e)
}
} else {
logger.warn('CF Worker host is not set')
} }
} catch (e: any) {
logger.error(e)
} }
return url return url
} }
const generateYOURLSShortUrl = async (url: string) => {
let domain = db.get(configPaths.settings.yourlsDomain) || ''
const signature = db.get(configPaths.settings.yourlsSignature) || ''
if (!domain || !signature) {
logger.warn('Yourls server or signature is not set')
return url
}
if (!/^https?:\/\//.test(domain)) {
domain = `http://${domain}`
}
const params = new URLSearchParams({ signature, action: 'shorturl', format: 'json', url })
try {
const res = await axios.get(`${domain}/yourls-api.php?${params.toString()}`)
if (res.data?.shorturl) {
return res.data.shorturl
}
} catch (e: any) {
if (e.response?.data?.message?.includes('already exists in database')) {
return e.response.data.shorturl
}
logger.error(e)
}
return url
}
const generateCFWORKERShortUrl = async (url: string) => {
let cfWorkerHost = db.get(configPaths.settings.cfWorkerHost) || ''
cfWorkerHost = cfWorkerHost.replace(/\/$/, '')
if (!cfWorkerHost) {
logger.warn('CF Worker host is not set')
return url
}
try {
const res = await axios.post(cfWorkerHost, { url })
if (res.data?.status === 200 && res.data?.key?.startsWith('/')) {
return `${cfWorkerHost}${res.data.key}`
}
} catch (e: any) {
logger.error(e)
}
return url
}
export const generateShortUrl = async (url: string) => {
const server = db.get(configPaths.settings.shortUrlServer) || IShortUrlServer.C1N
switch (server) {
case IShortUrlServer.C1N:
return generateC1NShortUrl(url)
case IShortUrlServer.YOURLS:
return generateYOURLSShortUrl(url)
case IShortUrlServer.CFWORKER:
return generateCFWORKERShortUrl(url)
default:
return url
}
}

View File

@ -10,32 +10,12 @@ import { configPaths } from '~/universal/utils/configPaths'
const STORE_PATH = app.getPath('userData') const STORE_PATH = app.getPath('userData')
const configFileNames = [ const readFileAsBase64 = (filePath: string) => fs.readFileSync(filePath, { encoding: 'base64' })
'data.json',
'data.bak.json',
'manage.json',
'manage.bak.json'
]
function getOctokit (syncConfig: ISyncConfig) { const isHttpResSuccess = (res: any) => res.status >= 200 && res.status < 300
const { token, proxy } = syncConfig const uploadOrUpdateMsg = (fileName: string, isUpdate: boolean = true) => isUpdate ? `update ${fileName} from PicList` : `upload ${fileName} from PicList`
return new Octokit({
auth: token,
request: {
agent: proxy
? new HttpsProxyAgent({
keepAlive: true,
keepAliveMsecs: 1000,
rejectUnauthorized: false,
proxy: proxy.replace('127.0.0.1', 'localhost'),
scheduling: 'lifo'
})
: undefined
}
})
}
function getSyncConfig () { const getSyncConfig = () => {
return db.get(configPaths.settings.sync) || { return db.get(configPaths.settings.sync) || {
type: 'github', type: 'github',
username: '', username: '',
@ -46,8 +26,35 @@ function getSyncConfig () {
} }
} }
function syncConfigValidator (syncConfig: ISyncConfig) { const getProxyagent = (proxy: string | undefined) => {
const { type, username, repo, branch, token } = syncConfig return proxy
? new HttpsProxyAgent({
keepAlive: true,
keepAliveMsecs: 1000,
rejectUnauthorized: false,
proxy: proxy.replace('127.0.0.1', 'localhost'),
scheduling: 'lifo'
})
: undefined
}
function getOctokit (syncConfig: ISyncConfig) {
const { token, proxy } = syncConfig
return new Octokit({
auth: token,
request: {
agent: getProxyagent(proxy)
}
})
}
const isSyncConfigValidate = ({
type,
username,
repo,
branch,
token
}: ISyncConfig) => {
return type && username && repo && branch && token return type && username && repo && branch && token
} }
@ -57,55 +64,46 @@ async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
return false return false
} }
const { username, repo, branch, token, type } = syncConfig const { username, repo, branch, token, type } = syncConfig
if (type === 'gitee') { const defaultConfig = {
try { content: readFileAsBase64(localFilePath),
const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${fileName}` message: uploadOrUpdateMsg(fileName, false),
const res = await axios.post(url, { branch
access_token: token, }
branch, try {
content: fs.readFileSync(localFilePath, { encoding: 'base64' }), switch (type) {
message: `upload ${fileName} from PicList` case 'gitee': {
}) const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${fileName}`
return res.status >= 200 && res.status < 300 const res = await axios.post(url, {
} catch (error: any) { ...defaultConfig,
logger.error(error) access_token: token
return false })
} return isHttpResSuccess(res)
} else if (type === 'github') {
const octokit = getOctokit(syncConfig)
try {
const res = await octokit.rest.repos.createOrUpdateFileContents({
owner: username,
repo,
path: fileName,
message: `upload ${fileName} from PicList`,
content: fs.readFileSync(localFilePath, { encoding: 'base64' }),
branch
})
return res.status >= 200 && res.status < 300
} catch (error: any) {
logger.error(error)
return false
}
} else {
const { endpoint = '' } = syncConfig
const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}`
try {
const headers = {
Authorization: `token ${token}`
} }
const res = await axios.post(apiUrl, { case 'github': {
message: `upload ${fileName} from PicList`, const octokit = getOctokit(syncConfig)
content: fs.readFileSync(localFilePath, { encoding: 'base64' }), const res = await octokit.rest.repos.createOrUpdateFileContents({
branch ...defaultConfig,
}, { owner: username,
headers repo,
}) path: fileName
return res.status >= 200 && res.status < 300 })
} catch (error: any) { return isHttpResSuccess(res)
logger.error(error) }
return false case 'gitea': {
const { endpoint = '' } = syncConfig
const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}`
const headers = {
Authorization: `token ${token}`
}
const res = await axios.post(apiUrl, defaultConfig, { headers })
return isHttpResSuccess(res)
}
default:
return false
} }
} catch (error: any) {
logger.error(error)
return false
} }
} }
@ -115,231 +113,183 @@ async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
return false return false
} }
const { username, repo, branch, token, type } = syncConfig const { username, repo, branch, token, type } = syncConfig
if (type === 'gitee') { const defaultConfig = {
const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${fileName}` branch,
const shaRes = await axios.get(url, { message: uploadOrUpdateMsg(fileName),
params: { content: readFileAsBase64(localFilePath)
access_token: token,
ref: branch
}
})
if (shaRes.status < 200 || shaRes.status > 300) {
return false
}
const sha = shaRes.data.sha
const res = await axios.put(url, {
owner: username,
repo,
path: fileName,
message: `update ${fileName} from PicList`,
content: fs.readFileSync(localFilePath, { encoding: 'base64' }),
branch,
sha,
access_token: token
})
if (res.status >= 200 && res.status < 300) {
return true
}
return false
} else if (type === 'github') {
const octokit = getOctokit(syncConfig)
const shaRes = await octokit.rest.repos.getContent({
owner: username,
repo,
path: fileName,
ref: branch
})
if (shaRes.status !== 200) {
throw new Error('get sha failed')
}
const data = shaRes.data as any
const sha = data.sha
const res = await octokit.rest.repos.createOrUpdateFileContents({
owner: username,
repo,
path: fileName,
message: `update ${fileName} from PicList`,
content: fs.readFileSync(localFilePath, { encoding: 'base64' }),
branch,
sha
})
return res.status === 200
} else {
const { endpoint = '' } = syncConfig
const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}`
const headers = {
Authorization: `token ${token}`
}
const shaRes = await axios.get(apiUrl, {
headers
})
if (shaRes.status < 200 || shaRes.status > 300) {
throw new Error('get sha failed')
}
const data = shaRes.data as any
const sha = data.sha
const res = await axios.put(apiUrl, {
message: `update ${fileName} from PicList`,
content: fs.readFileSync(localFilePath, { encoding: 'base64' }),
branch,
sha
}, {
headers
})
return res.status >= 200 && res.status < 300
} }
} switch (type) {
case 'gitee': {
async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) {
const localFilePath = path.join(STORE_PATH, fileName)
const { username, repo, branch, token, proxy, type } = syncConfig
if (type === 'gitee') {
try {
const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${fileName}` const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${fileName}`
const res = await axios.get(url, { const shaRes = await axios.get(url, {
params: { params: {
access_token: token, access_token: token,
ref: branch ref: branch
} }
}) })
if (res.status >= 200 && res.status < 300) { if (!isHttpResSuccess(shaRes)) {
const content = res.data.content return false
await fs.writeFile(localFilePath, Buffer.from(content, 'base64'))
return true
} }
return false const sha = shaRes.data.sha
} catch (error: any) { const res = await axios.put(url, {
logger.error(error) ...defaultConfig,
return false owner: username,
repo,
path: fileName,
sha,
access_token: token
})
return isHttpResSuccess(res)
} }
} else if (type === 'github') { case 'github': {
const octokit = getOctokit(syncConfig) const octokit = getOctokit(syncConfig)
try { const shaRes = await octokit.rest.repos.getContent({
const res = await octokit.rest.repos.getContent({
owner: username, owner: username,
repo, repo,
path: fileName, path: fileName,
ref: branch ref: branch
}) })
if (res.status === 200) { if (shaRes.status !== 200) {
const data = res.data as any throw new Error('get sha failed')
const downloadUrl = data.download_url
const downloadRes = await axios.get(downloadUrl, {
httpsAgent: proxy
? new HttpsProxyAgent({
keepAlive: true,
keepAliveMsecs: 1000,
rejectUnauthorized: false,
proxy: proxy.replace('127.0.0.1', 'localhost'),
scheduling: 'lifo'
})
: undefined
})
if (downloadRes.status >= 200 && downloadRes.status < 300) {
await fs.writeFile(localFilePath, JSON.stringify(downloadRes.data, null, 2))
return true
}
} }
return false const data = shaRes.data as any
} catch (error: any) { const sha = data.sha
logger.error(error) const res = await octokit.rest.repos.createOrUpdateFileContents({
return false ...defaultConfig,
owner: username,
repo,
path: fileName,
sha
})
return res.status === 200
} }
} else { case 'gitea': {
const { endpoint = '' } = syncConfig const { endpoint = '' } = syncConfig
const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}` const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}`
try {
const headers = { const headers = {
Authorization: `token ${token}` Authorization: `token ${token}`
} }
const res = await axios.get(apiUrl, { const shaRes = await axios.get(apiUrl, {
headers, headers
params: {
ref: branch
}
}) })
if (res.status >= 200 && res.status < 300) { if (!isHttpResSuccess(shaRes)) {
const content = res.data.content throw new Error('get sha failed')
await fs.writeFile(localFilePath, Buffer.from(content, 'base64'))
return true
} }
const data = shaRes.data as any
const sha = data.sha
const res = await axios.put(apiUrl, {
...defaultConfig,
sha
}, {
headers
})
return isHttpResSuccess(res)
}
default:
return false return false
}
}
async function uploadFile (fileName: string[]): Promise<number> {
const syncConfig = getSyncConfig()
if (!isSyncConfigValidate(syncConfig)) {
logger.error('sync config is invalid')
return 0
}
const uploadFunc = async (file: string): Promise<number> => {
let result = false
try {
result = await updateLocalToRemote(syncConfig, file)
} catch (error: any) { } catch (error: any) {
logger.error(error) result = await uploadLocalToRemote(syncConfig, file)
return false
} }
} logger.info(`upload ${file} ${result ? 'success' : 'failed'}`)
}
async function uploadFile (fileName: string, all = false) {
const syncConfig = getSyncConfig()
if (!syncConfigValidator(syncConfig)) {
logger.error('sync config is invalid')
return 0
}
let successCount = 0
if (all) {
for (const file of configFileNames) {
const result = await uploadFunc(syncConfig, file)
if (result) {
successCount++
}
}
logger.info(`upload all files at ${new Date().toLocaleString()}`)
return successCount
} else {
const ressult = await uploadFunc(syncConfig, fileName)
return ressult ? 1 : 0
}
}
async function uploadFunc (syncConfig: ISyncConfig, fileName: string) {
let result = false
try {
result = await updateLocalToRemote(syncConfig, fileName)
} catch (error: any) {
result = await uploadLocalToRemote(syncConfig, fileName)
}
if (!result) {
logger.error(`upload ${fileName} failed`)
return false
} else {
logger.info(`upload ${fileName} success`)
return true
}
}
async function downloadFile (fileName: string, all = false) {
const syncConfig = getSyncConfig()
if (!syncConfigValidator(syncConfig)) {
logger.error('sync config is invalid')
return 0
}
if (all) {
let successCount = 0
for (const file of configFileNames) {
const result = await downloadFunc(syncConfig, file)
if (result) {
successCount++
}
}
logger.info(`download all files at ${new Date().toLocaleString()}`)
return successCount
} else {
const result = await downloadFunc(syncConfig, fileName)
return result ? 1 : 0 return result ? 1 : 0
} }
let count = 0
for (const file of fileName) {
count += await uploadFunc(file)
}
return count
} }
async function downloadFunc (syncConfig: ISyncConfig, fileName: string) { async function downloadAndWriteFile (url: string, localFilePath:string, config: any, isWriteJson = false) {
const result = await downloadRemoteToLocal(syncConfig, fileName) const res = await axios.get(url, config)
if (!result) { if (isHttpResSuccess(res)) {
logger.error(`download ${fileName} failed`) await fs.writeFile(localFilePath, isWriteJson ? JSON.stringify(res.data, null, 2) : Buffer.from(res.data.content, 'base64'))
return false
} else {
logger.info(`download ${fileName} success`)
return true return true
} }
return false
}
async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) {
const localFilePath = path.join(STORE_PATH, fileName)
const { username, repo, branch, token, proxy, type } = syncConfig
try {
switch (type) {
case 'gitee': {
const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${fileName}`
return downloadAndWriteFile(url, localFilePath, {
params: {
access_token: token,
ref: branch
}
})
}
case 'github': {
const octokit = getOctokit(syncConfig)
const res = await octokit.rest.repos.getContent({
owner: username,
repo,
path: fileName,
ref: branch
})
if (res.status === 200) {
const data = res.data as any
const downloadUrl = data.download_url
return downloadAndWriteFile(downloadUrl, localFilePath, {
httpsAgent: getProxyagent(proxy)
}, true)
}
return false
}
case 'gitea': {
const { endpoint = '' } = syncConfig
const apiUrl = `${endpoint}/api/v1/repos/${username}/${repo}/contents/${fileName}`
return downloadAndWriteFile(apiUrl, localFilePath, {
headers: {
Authorization: `token ${token}`
},
params: {
ref: branch
}
})
}
default:
return false
}
} catch (error: any) {
logger.error(error)
return false
}
}
async function downloadFile (fileName: string[]): Promise<number> {
const syncConfig = getSyncConfig()
if (!isSyncConfigValidate(syncConfig)) {
logger.error('sync config is invalid')
return 0
}
const downloadFunc = async (file: string): Promise<number> => {
const result = await downloadRemoteToLocal(syncConfig, file)
logger.info(`download ${file} ${result ? 'success' : 'failed'}`)
return result ? 1 : 0
}
return (await Promise.all(fileName.map(downloadFunc))).reduce((a, b) => a + b, 0)
} }
export { export {

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import axios from 'axios' import axios from 'axios'
import path from 'path' import path from 'path'
@ -16,7 +17,10 @@ export default class AlistApi {
const { fileName, config } = configMap const { fileName, config } = configMap
try { try {
const { version, url, uploadPath, token } = config const { version, url, uploadPath, token } = config
if (String(version) === '2') return true if (String(version) === '2') {
deleteLog(fileName, 'Alist', false, 'Alist version 2 is not supported, deletion is skipped')
return true
}
const result = await axios.request({ const result = await axios.request({
method: 'post', method: 'post',
url: `${url}/api/fs/remove`, url: `${url}/api/fs/remove`,
@ -29,9 +33,14 @@ export default class AlistApi {
names: [path.basename(fileName)] names: [path.basename(fileName)]
} }
}) })
return result.data.code === 200 if (result.data.code === 200) {
} catch (error) { deleteLog(fileName, 'Alist')
console.error(error) return true
}
deleteLog(fileName, 'Alist', false)
return false
} catch (error: any) {
deleteFailedLog(fileName, 'Alist', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import OSS from 'ali-oss' import OSS from 'ali-oss'
interface IConfigMap { interface IConfigMap {
@ -18,9 +19,14 @@ export default class AliyunApi {
const client = new OSS({ ...config, region: config.area }) const client = new OSS({ ...config, region: config.area })
const key = AliyunApi.#getKey(fileName, config.path) const key = AliyunApi.#getKey(fileName, config.path)
const result = await client.delete(key) const result = await client.delete(key)
return result.res.status === 204 if (result.res.status === 204) {
} catch (error) { deleteLog(fileName, 'Aliyun')
console.error(error) return true
}
deleteLog(fileName, 'Aliyun', false)
return false
} catch (error: any) {
deleteFailedLog(fileName, 'Aliyun', error)
return false return false
} }
} }

View File

@ -1,5 +1,5 @@
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import { getRawData } from '~/renderer/utils/common' import { deleteFailedLog, getRawData } from '~/renderer/utils/common'
import { removeFileFromS3InMain } from '~/main/utils/deleteFunc' import { removeFileFromS3InMain } from '~/main/utils/deleteFunc'
export default class AwsS3Api { export default class AwsS3Api {
@ -10,8 +10,8 @@ export default class AwsS3Api {
getRawData(configMap) getRawData(configMap)
) )
: await removeFileFromS3InMain(getRawData(configMap)) : await removeFileFromS3InMain(getRawData(configMap))
} catch (error) { } catch (error: any) {
console.log(error) deleteFailedLog(configMap.fileName, 'AWS S3', error)
return false return false
} }
} }

View File

@ -1,5 +1,5 @@
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import { getRawData } from '~/renderer/utils/common' import { deleteFailedLog, getRawData } from '~/renderer/utils/common'
import { removeFileFromDogeInMain } from '~/main/utils/deleteFunc' import { removeFileFromDogeInMain } from '~/main/utils/deleteFunc'
export default class AwsS3Api { export default class AwsS3Api {
@ -10,8 +10,8 @@ export default class AwsS3Api {
getRawData(configMap) getRawData(configMap)
) )
: await removeFileFromDogeInMain(getRawData(configMap)) : await removeFileFromDogeInMain(getRawData(configMap))
} catch (error) { } catch (error: any) {
console.log(error) deleteFailedLog(configMap.fileName, 'DogeCloud', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { Octokit } from '@octokit/rest' import { Octokit } from '@octokit/rest'
interface IConfigMap { interface IConfigMap {
@ -34,9 +35,14 @@ export default class GithubApi {
sha: hash, sha: hash,
branch branch
}) })
return status === 200 if (status === 200) {
} catch (error) { deleteLog(fileName, 'GitHub')
console.error(error) return true
}
deleteLog(fileName, 'GitHub', false)
return false
} catch (error: any) {
deleteFailedLog(fileName, 'GitHub', error)
return false return false
} }
} }

View File

@ -1,5 +1,5 @@
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import { getRawData } from '~/renderer/utils/common' import { deleteFailedLog, getRawData } from '~/renderer/utils/common'
import { removeFileFromHuaweiInMain } from '~/main/utils/deleteFunc' import { removeFileFromHuaweiInMain } from '~/main/utils/deleteFunc'
export default class HuaweicloudApi { export default class HuaweicloudApi {
@ -10,8 +10,8 @@ export default class HuaweicloudApi {
getRawData(configMap) getRawData(configMap)
) )
: await removeFileFromHuaweiInMain(getRawData(configMap)) : await removeFileFromHuaweiInMain(getRawData(configMap))
} catch (error) { } catch (error: any) {
console.log(error) deleteFailedLog(configMap.fileName, 'HuaweiCloud', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
interface IConfigMap { interface IConfigMap {
@ -22,6 +23,7 @@ export default class ImgurApi {
Authorization = `Client-ID ${clientId}` Authorization = `Client-ID ${clientId}`
apiUrl = `${ImgurApi.#baseUrl}/image/${hash}` apiUrl = `${ImgurApi.#baseUrl}/image/${hash}`
} else { } else {
deleteLog(hash, 'Imgur', false, 'No credentials found')
return false return false
} }
try { try {
@ -29,9 +31,14 @@ export default class ImgurApi {
headers: { Authorization }, headers: { Authorization },
timeout: 30000 timeout: 30000
}) })
return response.status === 200 if (response.status === 200) {
} catch (error) { deleteLog(hash, 'Imgur')
console.error(error) return true
}
deleteLog(hash, 'Imgur', false)
return false
} catch (error: any) {
deleteFailedLog(hash, 'Imgur', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import fs from 'fs-extra' import fs from 'fs-extra'
interface IConfigMap { interface IConfigMap {
@ -8,15 +9,16 @@ 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) {
console.error('Local.delete: invalid params') deleteLog(hash, 'Local', false, 'Local.delete: invalid params')
return false return false
} }
try { try {
await fs.remove(hash) await fs.remove(hash)
deleteLog(hash, 'Local')
return true return true
} catch (error) { } catch (error: any) {
console.error(error) deleteFailedLog(hash, 'Local', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
import https from 'https' import https from 'https'
@ -5,13 +6,13 @@ 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) {
console.error('LskyplistApi.delete: invalid params') deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid params')
return false return false
} }
const { host, token, version } = config const { host, token, version } = config
if (version !== 'V2') { if (version !== 'V2') {
console.error('LskyplistApi.delete: invalid version') deleteLog(hash, 'Lskyplist', false, 'LskyplistApi.delete: invalid version')
return false return false
} }
@ -30,9 +31,14 @@ export default class LskyplistApi {
timeout: 30000, timeout: 30000,
httpsAgent: requestAgent httpsAgent: requestAgent
}) })
return response.status === 200 && response.data.status === true if (response.status === 200 && response.data.status === true) {
} catch (error) { deleteLog(hash, 'Lskyplist')
console.error(error) return true
}
deleteLog(hash, 'Lskyplist', false)
return false
} catch (error: any) {
deleteFailedLog(hash, 'Lskyplist', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
export default class PiclistApi { export default class PiclistApi {
@ -5,7 +6,7 @@ export default class PiclistApi {
const { config, fullResult } = configMap const { config, fullResult } = configMap
const { host, port } = config const { host, port } = config
if (!host) { if (!host) {
console.error('PiclistApi.delete: invalid params') deleteLog(fullResult, 'Piclist', false, 'PiclistApi.delete: invalid params')
return false return false
} }
@ -18,9 +19,14 @@ export default class PiclistApi {
list: [fullResult] list: [fullResult]
} }
) )
return response.status === 200 && response.data?.success if (response.status === 200 && response.data?.success) {
} catch (error) { deleteLog(fullResult, 'Piclist')
console.error(error) return true
}
deleteLog(fullResult, 'Piclist', false)
return false
} catch (error: any) {
deleteFailedLog(fullResult, 'Piclist', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import Qiniu from 'qiniu' import Qiniu from 'qiniu'
interface IConfigMap { interface IConfigMap {
@ -26,9 +27,14 @@ export default class QiniuApi {
} }
}) })
}) as any }) as any
return res?.respInfo?.statusCode === 200 if (res?.respInfo?.statusCode === 200) {
} catch (error) { deleteLog(fileName, 'Qiniu')
console.error(error) return true
}
deleteLog(fileName, 'Qiniu', false)
return false
} catch (error: any) {
deleteFailedLog(fileName, 'Qiniu', error)
return false return false
} }
} }

View File

@ -1,5 +1,5 @@
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import { getRawData } from '~/renderer/utils/common' import { deleteFailedLog, getRawData } from '~/renderer/utils/common'
export default class SftpPlistApi { export default class SftpPlistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> { static async delete (configMap: IStringKeyMap): Promise<boolean> {
@ -10,8 +10,8 @@ export default class SftpPlistApi {
fileName fileName
) )
return deleteResult return deleteResult
} catch (error) { } catch (error: any) {
console.error(error) deleteFailedLog(fileName, 'SFTP', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
interface IConfigMap { interface IConfigMap {
@ -11,7 +12,7 @@ export default class SmmsApi {
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) {
console.error('SmmsApi.delete: invalid params') deleteLog(hash, 'Smms', false, 'SmmsApi.delete: invalid params')
return false return false
} }
@ -29,9 +30,14 @@ export default class SmmsApi {
}, },
timeout: 30000 timeout: 30000
}) })
return response.status === 200 if (response.status === 200) {
} catch (error) { deleteLog(hash, 'Smms')
console.error(error) return true
}
deleteLog(hash, 'Smms', false)
return false
} catch (error: any) {
deleteFailedLog(hash, 'Smms', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import COS from 'cos-nodejs-sdk-v5' import COS from 'cos-nodejs-sdk-v5'
interface IConfigMap { interface IConfigMap {
@ -28,9 +29,14 @@ export default class TcyunApi {
Region: area, Region: area,
Key: key Key: key
}) })
return result.statusCode === 204 if (result.statusCode === 204) {
} catch (error) { deleteLog(fileName, 'Tcyun')
console.error(error) return true
}
deleteLog(fileName, 'Tcyun', false)
return false
} catch (error: any) {
deleteFailedLog(fileName, 'Tcyun', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import Upyun from 'upyun' import Upyun from 'upyun'
interface IConfigMap { interface IConfigMap {
@ -17,9 +18,15 @@ export default class UpyunApi {
} else { } else {
key = `${path.replace(/^\/+|\/+$/, '')}/${fileName}` key = `${path.replace(/^\/+|\/+$/, '')}/${fileName}`
} }
return await client.deleteFile(key) const result = await client.deleteFile(key)
} catch (error) { if (result) {
console.log(error) deleteLog(fileName, 'Upyun')
return true
}
deleteLog(fileName, 'Upyun', false)
return false
} catch (error: any) {
deleteFailedLog(fileName, 'Upyun', error)
return false return false
} }
} }

View File

@ -1,3 +1,4 @@
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { AuthType, WebDAVClientOptions, createClient } from 'webdav' import { AuthType, WebDAVClientOptions, createClient } from 'webdav'
import { formatEndpoint } from '~/main/manage/utils/common' import { formatEndpoint } from '~/main/manage/utils/common'
@ -29,9 +30,10 @@ export default class WebdavApi {
} }
try { try {
await ctx.deleteFile(key) await ctx.deleteFile(key)
deleteLog(fileName, 'WebDAV')
return true return true
} catch (error) { } catch (error: any) {
console.log(error) deleteFailedLog(fileName, 'WebDAV', error)
return false return false
} }
} }

View File

@ -49,7 +49,7 @@ onBeforeMount(() => {
$bus.on(SHOW_INPUT_BOX, initInputBoxValue) $bus.on(SHOW_INPUT_BOX, initInputBoxValue)
}) })
function ipcEventHandler (evt: IpcRendererEvent, options: IShowInputBoxOption) { function ipcEventHandler (_: IpcRendererEvent, options: IShowInputBoxOption) {
initInputBoxValue(options) initInputBoxValue(options)
} }

View File

@ -2462,7 +2462,7 @@ async function handleFolderBatchDownload (item: any) {
const downloadFileTransferStore = useDownloadFileTransferStore() const downloadFileTransferStore = useDownloadFileTransferStore()
downloadFileTransferStore.resetDownloadFileTransferList() downloadFileTransferStore.resetDownloadFileTransferList()
ipcRenderer.send('getBucketListRecursively', configMap.alias, paramGet) ipcRenderer.send('getBucketListRecursively', configMap.alias, paramGet)
ipcRenderer.on(refreshDownloadFileTransferList, (evt: IpcRendererEvent, data) => { ipcRenderer.on(refreshDownloadFileTransferList, (_: IpcRendererEvent, data) => {
downloadFileTransferStore.refreshDownloadFileTransferList(data) downloadFileTransferStore.refreshDownloadFileTransferList(data)
}) })
downloadInterval = setInterval(() => { downloadInterval = setInterval(() => {
@ -2838,7 +2838,7 @@ async function getBucketFileListBackStage () {
param.webPath = configMap.webPath param.webPath = configMap.webPath
} }
ipcRenderer.send('getBucketListBackstage', configMap.alias, param) ipcRenderer.send('getBucketListBackstage', configMap.alias, param)
ipcRenderer.on('refreshFileTransferList', (evt: IpcRendererEvent, data) => { ipcRenderer.on('refreshFileTransferList', (_: IpcRendererEvent, data) => {
fileTransferStore.refreshFileTransferList(data) fileTransferStore.refreshFileTransferList(data)
}) })
fileTransferInterval = setInterval(() => { fileTransferInterval = setInterval(() => {

View File

@ -1,6 +1,6 @@
<template> <template>
<webview <webview
src="https://piclist.cn/app.html" :src="srcUrl"
disablewebsecurity disablewebsecurity
allowpopups allowpopups
autosize="on" autosize="on"
@ -9,6 +9,25 @@
/> />
</template> </template>
<script lang="ts" setup>
import { getConfig } from '@/utils/dataSender'
import { onMounted, ref } from 'vue'
import { II18nLanguage } from '~/universal/types/enum'
import { configPaths } from '~/universal/utils/configPaths'
const srcUrl = ref('https://piclist.cn/app.html')
const updateUrl = async () => {
const lang = await getConfig(configPaths.settings.language) || II18nLanguage.ZH_CN
srcUrl.value = lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html'
}
onMounted(() => {
updateUrl()
})
</script>
<script lang="ts"> <script lang="ts">
export default { export default {
name: 'DocumentPage' name: 'DocumentPage'

View File

@ -88,7 +88,7 @@ async function initLogoPath () {
onBeforeMount(async () => { onBeforeMount(async () => {
os.value = process.platform os.value = process.platform
await initLogoPath() await initLogoPath()
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, _progress: number) => { ipcRenderer.on('uploadProgress', (_: IpcRendererEvent, _progress: number) => {
if (_progress !== -1) { if (_progress !== -1) {
showProgress.value = true showProgress.value = true
progress.value = _progress progress.value = _progress
@ -97,6 +97,9 @@ onBeforeMount(async () => {
showError.value = true showError.value = true
} }
}) })
ipcRenderer.on('updateMiniIcon', async () => {
await initLogoPath()
})
window.addEventListener('mousedown', handleMouseDown, false) window.addEventListener('mousedown', handleMouseDown, false)
window.addEventListener('mousemove', handleMouseMove, false) window.addEventListener('mousemove', handleMouseMove, false)
window.addEventListener('mouseup', handleMouseUp, false) window.addEventListener('mouseup', handleMouseUp, false)
@ -215,6 +218,7 @@ function openContextMenu () {
onBeforeUnmount(() => { onBeforeUnmount(() => {
ipcRenderer.removeAllListeners('uploadProgress') ipcRenderer.removeAllListeners('uploadProgress')
ipcRenderer.removeAllListeners('updateMiniIcon')
window.removeEventListener('mousedown', handleMouseDown, false) window.removeEventListener('mousedown', handleMouseDown, false)
window.removeEventListener('mousemove', handleMouseMove, false) window.removeEventListener('mousemove', handleMouseMove, false)
window.removeEventListener('mouseup', handleMouseUp, false) window.removeEventListener('mouseup', handleMouseUp, false)

View File

@ -96,7 +96,7 @@
:label="$T('MANUAL_PAGE_OPEN_SETTING_TIP')" :label="$T('MANUAL_PAGE_OPEN_SETTING_TIP')"
> >
<el-select <el-select
v-model="form.manualPageOpen" v-model="currentManualPageOpen"
size="small" size="small"
style="width: 50%" style="width: 50%"
:placeholder="$T('MANUAL_PAGE_OPEN_SETTING_TIP')" :placeholder="$T('MANUAL_PAGE_OPEN_SETTING_TIP')"
@ -469,7 +469,7 @@
:label="$T('SETTINGS_SHORT_URL_SERVER')" :label="$T('SETTINGS_SHORT_URL_SERVER')"
> >
<el-select <el-select
v-model="form.shortUrlServer" v-model="currentShortUrlServer"
size="small" size="small"
style="width: 50%" style="width: 50%"
:placeholder="$T('SETTINGS_SHORT_URL_SERVER')" :placeholder="$T('SETTINGS_SHORT_URL_SERVER')"
@ -1735,7 +1735,7 @@ import pkg from 'root/package.json'
// //
import { PICGO_OPEN_FILE, PICGO_OPEN_DIRECTORY, OPEN_URL, GET_PICBEDS, HIDE_DOCK } from '#/events/constants' import { PICGO_OPEN_FILE, PICGO_OPEN_DIRECTORY, OPEN_URL, GET_PICBEDS, HIDE_DOCK } from '#/events/constants'
import { IRPCActionType, ISartMode } from '~/universal/types/enum' import { II18nLanguage, IRPCActionType, ISartMode } from '~/universal/types/enum'
// Electron // Electron
import { import {
@ -1789,6 +1789,30 @@ const shortUrlServerList = [{
} }
] ]
const languageList = i18nManager.languageList.map(item => ({
label: item.label,
value: item.value
}))
const startModeList = [
{
label: $T('SETTINGS_START_MODE_QUIET'),
value: ISartMode.QUIET
},
{
label: $T('SETTINGS_START_MODE_MINI'),
value: ISartMode.MINI
},
{
label: $T('SETTINGS_START_MODE_NO_TRAY'),
value: ISartMode.NO_TRAY
},
{
label: $T('SETTINGS_START_MODE_MAIN'),
value: ISartMode.MAIN
}
]
const manualPageOpenList = [{ const manualPageOpenList = [{
label: $T('MANUAL_PAGE_OPEN_BY_BUILD_IN'), label: $T('MANUAL_PAGE_OPEN_BY_BUILD_IN'),
value: 'window' value: 'window'
@ -1799,6 +1823,8 @@ const manualPageOpenList = [{
} }
] ]
const picBed = ref<IPicBedType[]>([])
const waterMarkPositionMap = new Map([ const waterMarkPositionMap = new Map([
['north', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP')], ['north', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP')],
['northeast', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP_RIGHT')], ['northeast', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP_RIGHT')],
@ -1934,9 +1960,7 @@ const form = reactive<ISettingForm>({
autoCloseMainWindow: false, autoCloseMainWindow: false,
logLevel: ['all'], logLevel: ['all'],
autoCopyUrl: true, autoCopyUrl: true,
checkBetaUpdate: true,
useBuiltinClipboard: true, useBuiltinClipboard: true,
language: 'zh-CN',
logFileSizeLimit: 10, logFileSizeLimit: 10,
deleteCloudFile: false, deleteCloudFile: false,
isCustomMiniIcon: false, isCustomMiniIcon: false,
@ -1955,22 +1979,20 @@ const form = reactive<ISettingForm>({
deleteLocalFile: false, deleteLocalFile: false,
serverKey: '', serverKey: '',
aesPassword: '', aesPassword: '',
manualPageOpen: 'browser',
enableWebServer: false, enableWebServer: false,
webServerHost: '0.0.0.0', webServerHost: '0.0.0.0',
webServerPort: 37777, webServerPort: 37777,
webServerPath: '' webServerPath: ''
}) })
const languageList = i18nManager.languageList.map(item => ({ const valueToOptionItem = (value: any, list: { label: string, value: any }[]) => {
label: item.label, return list.find(item => item.value === value) || list[0]
value: item.value }
}))
const currentLanguage = ref('zh-CN') const currentLanguage = ref()
const currentStartMode = ref('quiet') const currentStartMode = ref()
const currentManualPageOpen = ref()
const picBed = ref<IPicBedType[]>([]) const currentShortUrlServer = ref()
const logFileVisible = ref(false) const logFileVisible = ref(false)
const customLinkVisible = ref(false) const customLinkVisible = ref(false)
@ -2092,22 +2114,20 @@ async function initData () {
if (config !== undefined) { if (config !== undefined) {
const settings = config.settings || {} const settings = config.settings || {}
const picBed = config.picBed const picBed = config.picBed
form.updateHelper = settings.showUpdateTip === undefined ? true : settings.showUpdateTip form.updateHelper = settings.showUpdateTip ?? true
form.autoStart = settings.autoStart || false form.autoStart = settings.autoStart || false
form.rename = settings.rename || false form.rename = settings.rename || false
form.autoRename = settings.autoRename || false form.autoRename = settings.autoRename || false
form.uploadNotification = settings.uploadNotification || false form.uploadNotification = settings.uploadNotification || false
form.uploadResultNotification = settings.uploadResultNotification === undefined ? true : settings.uploadResultNotification form.uploadResultNotification = settings.uploadResultNotification ?? true
form.miniWindowOntop = settings.miniWindowOntop || false form.miniWindowOntop = settings.miniWindowOntop || false
form.autoCloseMiniWindow = settings.autoCloseMiniWindow || false form.autoCloseMiniWindow = settings.autoCloseMiniWindow || false
form.autoCloseMainWindow = settings.autoCloseMainWindow || false form.autoCloseMainWindow = settings.autoCloseMainWindow || false
form.logLevel = initArray(settings.logLevel || [], ['all']) form.logLevel = initArray(settings.logLevel || [], ['all'])
form.autoCopyUrl = settings.autoCopy === undefined ? true : settings.autoCopy form.autoCopyUrl = settings.autoCopy ?? true
form.checkBetaUpdate = settings.checkBetaUpdate === undefined ? true : settings.checkBetaUpdate form.useBuiltinClipboard = settings.useBuiltinClipboard ?? true
form.useBuiltinClipboard = settings.useBuiltinClipboard === undefined ? true : settings.useBuiltinClipboard
form.isAutoListenClipboard = settings.isAutoListenClipboard || false form.isAutoListenClipboard = settings.isAutoListenClipboard || false
form.language = settings.language ?? 'zh-CN' form.encodeOutputURL = settings.encodeOutputURL || false
form.encodeOutputURL = settings.encodeOutputURL === undefined ? false : settings.encodeOutputURL
form.deleteCloudFile = settings.deleteCloudFile || false form.deleteCloudFile = settings.deleteCloudFile || false
form.autoImport = settings.autoImport || false form.autoImport = settings.autoImport || false
form.autoImportPicBed = initArray(settings.autoImportPicBed || [], []) form.autoImportPicBed = initArray(settings.autoImportPicBed || [], [])
@ -2123,13 +2143,14 @@ async function initData () {
form.deleteLocalFile = settings.deleteLocalFile || false form.deleteLocalFile = settings.deleteLocalFile || false
form.serverKey = settings.serverKey || '' form.serverKey = settings.serverKey || ''
form.aesPassword = settings.aesPassword || 'PicList-aesPassword' form.aesPassword = settings.aesPassword || 'PicList-aesPassword'
form.manualPageOpen = settings.manualPageOpen || 'window'
form.enableWebServer = settings.enableWebServer || false form.enableWebServer = settings.enableWebServer || false
form.webServerHost = settings.webServerHost || '0.0.0.0' form.webServerHost = settings.webServerHost || '0.0.0.0'
form.webServerPort = settings.webServerPort || 37777 form.webServerPort = settings.webServerPort || 37777
form.webServerPath = settings.webServerPath || '' form.webServerPath = settings.webServerPath || ''
currentLanguage.value = settings.language ?? 'zh-CN' currentLanguage.value = valueToOptionItem(settings.language || 'zh-CN', languageList)
currentStartMode.value = settings.startMode || 'quiet' currentStartMode.value = valueToOptionItem(settings.startMode || ISartMode.QUIET, startModeList)
currentManualPageOpen.value = valueToOptionItem(settings.manualPageOpen || 'window', manualPageOpenList)
currentShortUrlServer.value = valueToOptionItem(settings.shortUrlServer || 'c1n', shortUrlServerList)
customLink.value = settings.customLink || '![$fileName]($url)' customLink.value = settings.customLink || '![$fileName]($url)'
proxy.value = picBed.proxy || '' proxy.value = picBed.proxy || ''
npmRegistry.value = settings.registry || '' npmRegistry.value = settings.registry || ''
@ -2298,7 +2319,7 @@ function handleAutoImportPicBedChange (val: string[]) {
} }
function handleHideDockChange (val: ICheckBoxValueType) { function handleHideDockChange (val: ICheckBoxValueType) {
if (val && currentStartMode.value === 'no-tray') { if (val && currentStartMode.value.value === ISartMode.NO_TRAY) {
ElMessage.warning($T('SETTINGS_ISHIDEDOCK_TIPS')) ElMessage.warning($T('SETTINGS_ISHIDEDOCK_TIPS'))
form.isHideDock = false form.isHideDock = false
return return
@ -2457,21 +2478,20 @@ function handleAutoCloseMiniWindowChange (val: ICheckBoxValueType) {
function handleMiniWindowOntop (val: ICheckBoxValueType) { function handleMiniWindowOntop (val: ICheckBoxValueType) {
saveConfig(configPaths.settings.miniWindowOntop, val) saveConfig(configPaths.settings.miniWindowOntop, val)
$message.info($T('TIPS_NEED_RELOAD')) ipcRenderer.send('miniWindowOntop', val)
} }
async function handleMiniIconPath (evt: Event) { async function handleMiniIconPath (_: Event) {
const result = await invokeToMain('openFileSelectDialog') const result = await invokeToMain('openFileSelectDialog')
if (result && result[0]) { if (result && result[0]) {
form.customMiniIcon = result[0] form.customMiniIcon = result[0]
saveConfig(configPaths.settings.customMiniIcon, form.customMiniIcon) saveConfig(configPaths.settings.customMiniIcon, form.customMiniIcon)
$message.info($T('TIPS_NEED_RELOAD')) ipcRenderer.send('updateMiniIcon', form.customMiniIcon)
} }
} }
function handleIsCustomMiniIcon (val: ICheckBoxValueType) { function handleIsCustomMiniIcon (val: ICheckBoxValueType) {
saveConfig(configPaths.settings.isCustomMiniIcon, val) saveConfig(configPaths.settings.isCustomMiniIcon, val)
$message.info($T('TIPS_NEED_RELOAD'))
} }
function handleAutoCopyUrl (val: ICheckBoxValueType) { function handleAutoCopyUrl (val: ICheckBoxValueType) {
@ -2495,6 +2515,7 @@ function handleUseShortUrl (val: ICheckBoxValueType) {
} }
function handleShortUrlServerChange (val: string) { function handleShortUrlServerChange (val: string) {
form.shortUrlServer = val
saveConfig(configPaths.settings.shortUrlServer, val) saveConfig(configPaths.settings.shortUrlServer, val)
} }
@ -2667,7 +2688,7 @@ function handleStartModeChange (val: ISartModeValues) {
if (val === ISartMode.NO_TRAY) { if (val === ISartMode.NO_TRAY) {
if (form.isHideDock) { if (form.isHideDock) {
ElMessage.warning($T('SETTINGS_ISHIDEDOCK_TIPS')) ElMessage.warning($T('SETTINGS_ISHIDEDOCK_TIPS'))
currentStartMode.value = ISartMode.QUIET currentStartMode.value = valueToOptionItem(ISartMode.QUIET, startModeList)
return return
} }
$message.info($T('TIPS_NEED_RELOAD')) $message.info($T('TIPS_NEED_RELOAD'))
@ -2683,8 +2704,10 @@ function handleManualPageOpenChange (val: string) {
}) })
} }
function goConfigPage () { async function goConfigPage () {
sendToMain(OPEN_URL, 'https://piclist.cn/configure.html') const lang = await getConfig(configPaths.settings.language) || II18nLanguage.ZH_CN
const url = lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/configure.html' : 'https://piclist.cn/en/configure.html'
sendToMain(OPEN_URL, url)
} }
function goShortCutPage () { function goShortCutPage () {

View File

@ -337,7 +337,7 @@ onBeforeMount(async () => {
ipcRenderer.on('hideLoading', () => { ipcRenderer.on('hideLoading', () => {
loading.value = false loading.value = false
}) })
ipcRenderer.on(PICGO_HANDLE_PLUGIN_DONE, (evt: IpcRendererEvent, fullName: string) => { ipcRenderer.on(PICGO_HANDLE_PLUGIN_DONE, (_: IpcRendererEvent, fullName: string) => {
pluginList.value.forEach(item => { pluginList.value.forEach(item => {
if (item.fullName === fullName || (item.name === fullName)) { if (item.fullName === fullName || (item.name === fullName)) {
item.ing = false item.ing = false
@ -345,7 +345,7 @@ onBeforeMount(async () => {
}) })
loading.value = false loading.value = false
}) })
ipcRenderer.on('pluginList', (evt: IpcRendererEvent, list: IPicGoPlugin[]) => { ipcRenderer.on('pluginList', (_: IpcRendererEvent, list: IPicGoPlugin[]) => {
pluginList.value = list pluginList.value = list
pluginNameList.value = list.map(item => item.fullName) pluginNameList.value = list.map(item => item.fullName)
for (const item of pluginList.value) { for (const item of pluginList.value) {
@ -353,7 +353,7 @@ onBeforeMount(async () => {
} }
loading.value = false loading.value = false
}) })
ipcRenderer.on('installPlugin', (evt: IpcRendererEvent, { success, body }: { ipcRenderer.on('installPlugin', (_: IpcRendererEvent, { success, body }: {
success: boolean, success: boolean,
body: string body: string
}) => { }) => {
@ -365,7 +365,7 @@ onBeforeMount(async () => {
} }
}) })
}) })
ipcRenderer.on('updateSuccess', (evt: IpcRendererEvent, plugin: string) => { ipcRenderer.on('updateSuccess', (_: IpcRendererEvent, plugin: string) => {
loading.value = false loading.value = false
pluginList.value.forEach(item => { pluginList.value.forEach(item => {
if (item.fullName === plugin) { if (item.fullName === plugin) {
@ -377,7 +377,7 @@ onBeforeMount(async () => {
handleReload() handleReload()
getPluginList() getPluginList()
}) })
ipcRenderer.on('uninstallSuccess', (evt: IpcRendererEvent, plugin: string) => { ipcRenderer.on('uninstallSuccess', (_: IpcRendererEvent, plugin: string) => {
loading.value = false loading.value = false
pluginList.value = pluginList.value.filter(item => { pluginList.value = pluginList.value.filter(item => {
if (item.fullName === plugin) { // restore Uploader & Transformer after uninstalling if (item.fullName === plugin) { // restore Uploader & Transformer after uninstalling
@ -393,13 +393,13 @@ onBeforeMount(async () => {
}) })
pluginNameList.value = pluginNameList.value.filter(item => item !== plugin) pluginNameList.value = pluginNameList.value.filter(item => item !== plugin)
}) })
ipcRenderer.on(PICGO_CONFIG_PLUGIN, (evt: IpcRendererEvent, _currentType: 'plugin' | 'transformer' | 'uploader', _configName: string, _config: any) => { ipcRenderer.on(PICGO_CONFIG_PLUGIN, (_: IpcRendererEvent, _currentType: 'plugin' | 'transformer' | 'uploader', _configName: string, _config: any) => {
currentType.value = _currentType currentType.value = _currentType
configName.value = _configName configName.value = _configName
config.value = _config config.value = _config
dialogVisible.value = true dialogVisible.value = true
}) })
ipcRenderer.on(PICGO_HANDLE_PLUGIN_ING, (evt: IpcRendererEvent, fullName: string) => { ipcRenderer.on(PICGO_HANDLE_PLUGIN_ING, (_: IpcRendererEvent, fullName: string) => {
pluginList.value.forEach(item => { pluginList.value.forEach(item => {
if (item.fullName === fullName || (item.name === fullName)) { if (item.fullName === fullName || (item.name === fullName)) {
item.ing = true item.ing = true
@ -407,7 +407,7 @@ onBeforeMount(async () => {
}) })
loading.value = true loading.value = true
}) })
ipcRenderer.on(PICGO_TOGGLE_PLUGIN, (evt: IpcRendererEvent, fullName: string, enabled: boolean) => { ipcRenderer.on(PICGO_TOGGLE_PLUGIN, (_: IpcRendererEvent, fullName: string, enabled: boolean) => {
const plugin = pluginList.value.find(item => item.fullName === fullName) const plugin = pluginList.value.find(item => item.fullName === fullName)
if (plugin) { if (plugin) {
plugin.enabled = enabled plugin.enabled = enabled

View File

@ -190,7 +190,7 @@ async function confirmKeyBinding () {
const config = Object.assign({}, list.value[currentIndex.value]) const config = Object.assign({}, list.value[currentIndex.value])
config.key = shortKey.value config.key = shortKey.value
sendToMain('updateShortKey', config, oldKey, config.from) sendToMain('updateShortKey', config, oldKey, config.from)
ipcRenderer.once('updateShortKeyResponse', (evt: IpcRendererEvent, result) => { ipcRenderer.once('updateShortKeyResponse', (_: IpcRendererEvent, result) => {
if (result) { if (result) {
keyBindingVisible.value = false keyBindingVisible.value = false
list.value[currentIndex.value].key = shortKey.value list.value[currentIndex.value].key = shortKey.value

View File

@ -192,14 +192,14 @@ function uploadClipboardFiles () {
onBeforeMount(() => { onBeforeMount(() => {
disableDragFile() disableDragFile()
getData() getData()
ipcRenderer.on('dragFiles', async (event: Event, _files: string[]) => { ipcRenderer.on('dragFiles', async (_: Event, _files: string[]) => {
for (let i = 0; i < _files.length; i++) { for (let i = 0; i < _files.length; i++) {
const item = _files[i] const item = _files[i]
await $$db.insert(item) await $$db.insert(item)
} }
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
}) })
ipcRenderer.on('clipboardFiles', (event: Event, files: ImgInfo[]) => { ipcRenderer.on('clipboardFiles', (_: Event, files: ImgInfo[]) => {
clipboardFiles.value = files clipboardFiles.value = files
}) })
ipcRenderer.on('uploadFiles', async () => { ipcRenderer.on('uploadFiles', async () => {
@ -214,7 +214,7 @@ onBeforeMount(() => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
ipcRenderer.removeAllListeners('dragFiles') ipcRenderer.removeAllListeners('dragFiles')
ipcRenderer.removeAllListeners('clipboardFiles') ipcRenderer.removeAllListeners('clipboardFiles')
ipcRenderer.removeAllListeners('uploadClipboardFiles') ipcRenderer.removeAllListeners('uploadFiles')
ipcRenderer.removeAllListeners('updateFiles') ipcRenderer.removeAllListeners('updateFiles')
}) })
</script> </script>

View File

@ -97,7 +97,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
// //
import { IRPCActionType } from '~/universal/types/enum' import { II18nLanguage, IRPCActionType } from '~/universal/types/enum'
// Vue // Vue
import { ref, onBeforeUnmount, onBeforeMount } from 'vue' import { ref, onBeforeUnmount, onBeforeMount } from 'vue'
@ -133,6 +133,7 @@ import dayjs from 'dayjs'
// Element Plus // Element Plus
import { ElDropdown, ElMessage } from 'element-plus' import { ElDropdown, ElMessage } from 'element-plus'
import { configPaths } from '~/universal/utils/configPaths' import { configPaths } from '~/universal/utils/configPaths'
import { picBedManualUrlList } from '~/universal/utils/static'
const type = ref('') const type = ref('')
const config = ref<IPicGoPluginConfig[]>([]) const config = ref<IPicGoPluginConfig[]>([])
@ -200,27 +201,9 @@ const handleReset = async () => {
$router.back() $router.back()
} }
function handleNameClick () { async function handleNameClick () {
const typeUrlMap: IStringKeyMap = { const lang = await getConfig(configPaths.settings.language) || II18nLanguage.ZH_CN
github: 'https://piclist.cn/configure.html#github%E5%9B%BE%E5%BA%8A', const url = picBedManualUrlList[lang === II18nLanguage.EN ? 'en' : 'zh_cn'][$route.params.type as string]
githubPlus: 'https://piclist.cn/configure.html#github%E5%9B%BE%E5%BA%8A',
tcyun: 'https://piclist.cn/configure.html#%E8%85%BE%E8%AE%AF%E4%BA%91cos',
aliyun: 'https://piclist.cn/configure.html#%E9%98%BF%E9%87%8C%E4%BA%91oss',
smms: 'https://piclist.cn/configure.html#sm-ms',
qiniu: 'https://piclist.cn/configure.html#%E4%B8%83%E7%89%9B%E4%BA%91',
imgur: 'https://piclist.cn/configure.html#imgur',
upyun: 'https://piclist.cn/configure.html#%E5%8F%88%E6%8B%8D%E4%BA%91',
'aws-s3-plist': 'https://piclist.cn/configure.html#%E5%86%85%E7%BD%AEaws-s3',
'aws-s3': 'https://piclist.cn/configure.html#%E5%86%85%E7%BD%AEaws-s3',
local: 'https://piclist.cn/configure.html#%E6%9C%AC%E5%9C%B0%E5%9B%BE%E5%BA%8A',
lskyplist: 'https://piclist.cn/configure.html#%E5%85%B0%E7%A9%BA%E5%9B%BE%E5%BA%8A',
sftpplist: 'https://piclist.cn/configure.html#%E5%86%85%E7%BD%AEsftp',
telegraphplist: 'https://piclist.cn/configure.html#telegra-ph',
webdavplist: 'https://piclist.cn/configure.html#webdav',
piclist: 'https://piclist.cn/configure.html#piclist',
lankong: 'https://github.com/hellodk34/picgo-plugin-lankong'
}
const url = typeUrlMap[$route.params.type as string]
if (url) { if (url) {
sendToMain(OPEN_URL, url) sendToMain(OPEN_URL, url)
} }

View File

@ -1,6 +1,7 @@
import { isReactive, isRef, toRaw, unref } from 'vue' import { isReactive, isRef, toRaw, unref } from 'vue'
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import { OPEN_URL } from '~/universal/events/constants' import { OPEN_URL } from '~/universal/events/constants'
import { ILogType } from '~/universal/types/enum'
const isDevelopment = process.env.NODE_ENV !== 'production' const isDevelopment = process.env.NODE_ENV !== 'production'
export const handleTalkingDataEvent = (data: ITalkingDataOptions) => { export const handleTalkingDataEvent = (data: ITalkingDataOptions) => {
@ -37,3 +38,12 @@ function sendToMain (channel: string, ...args: any[]) {
export const openURL = (url: string) => { export const openURL = (url: string) => {
sendToMain(OPEN_URL, url) sendToMain(OPEN_URL, url)
} }
export const deleteLog = (fileName?: string, type?: string, isSuccess = true, msg?: string) => {
ipcRenderer.send('logDeleteMsg', msg || `Delete ${fileName} on ${type} success`, isSuccess ? ILogType.success : ILogType.error)
}
export const deleteFailedLog = (fileName: string, type: string, error: any) => {
deleteLog(fileName, type, false)
ipcRenderer.send('logDeleteMsg', error, ILogType.error)
}

View File

@ -57,7 +57,7 @@ export class GalleryDB implements IGalleryDB {
#msgHandler<T> (method: string, ...args: any[]): Promise<T> { #msgHandler<T> (method: string, ...args: any[]): Promise<T> {
return new Promise((resolve) => { return new Promise((resolve) => {
const callbackId = uuid() const callbackId = uuid()
const callback = (event: IpcRendererEvent, data: T, returnCallbackId: string) => { const callback = (_: IpcRendererEvent, data: T, returnCallbackId: string) => {
if (returnCallbackId === callbackId) { if (returnCallbackId === callbackId) {
resolve(data) resolve(data)
ipcRenderer.removeListener(method, callback) ipcRenderer.removeListener(method, callback)

View File

@ -11,9 +11,7 @@ interface ISettingForm {
autoCloseMainWindow: boolean autoCloseMainWindow: boolean
logLevel: string[] logLevel: string[]
autoCopyUrl: boolean autoCopyUrl: boolean
checkBetaUpdate: boolean
useBuiltinClipboard: boolean useBuiltinClipboard: boolean
language: 'zh-CN' | 'zh-TW' | 'en'
logFileSizeLimit: number logFileSizeLimit: number
deleteCloudFile: boolean deleteCloudFile: boolean
isCustomMiniIcon: boolean isCustomMiniIcon: boolean
@ -24,15 +22,14 @@ interface ISettingForm {
encodeOutputURL: boolean encodeOutputURL: boolean
isAutoListenClipboard: boolean isAutoListenClipboard: boolean
useShortUrl: boolean useShortUrl: boolean
c1nToken: string
shortUrlServer: string shortUrlServer: string
c1nToken: string
yourlsDomain: string yourlsDomain: string
yourlsSignature: string yourlsSignature: string
cfWorkerHost: string cfWorkerHost: string
deleteLocalFile: boolean deleteLocalFile: boolean
serverKey: string serverKey: string
aesPassword: string aesPassword: string
manualPageOpen: 'window' | 'browser'
enableWebServer: boolean enableWebServer: boolean
webServerHost: string webServerHost: string
webServerPort: number webServerPort: number

View File

@ -23,4 +23,45 @@ export const picBedsCanbeDeleted = [
'webdavplist' 'webdavplist'
] ]
export const picBedManualUrlList: IStringKeyMap = {
zh_cn: {
aliyun: 'https://piclist.cn/configure.html#%E9%98%BF%E9%87%8C%E4%BA%91oss',
'aws-s3': 'https://piclist.cn/configure.html#%E5%86%85%E7%BD%AEaws-s3',
'aws-s3-plist': 'https://piclist.cn/configure.html#%E5%86%85%E7%BD%AEaws-s3',
github: 'https://piclist.cn/configure.html#github%E5%9B%BE%E5%BA%8A',
githubPlus: 'https://piclist.cn/configure.html#github%E5%9B%BE%E5%BA%8A',
imgur: 'https://piclist.cn/configure.html#imgur',
lankong: 'https://github.com/hellodk34/picgo-plugin-lankong',
local: 'https://piclist.cn/configure.html#%E6%9C%AC%E5%9C%B0%E5%9B%BE%E5%BA%8A',
lskyplist: 'https://piclist.cn/configure.html#%E5%85%B0%E7%A9%BA%E5%9B%BE%E5%BA%8A',
tcyun: 'https://piclist.cn/configure.html#%E8%85%BE%E8%AE%AF%E4%BA%91cos',
piclist: 'https://piclist.cn/configure.html#piclist',
qiniu: 'https://piclist.cn/configure.html#%E4%B8%83%E7%89%9B%E4%BA%91',
sftpplist: 'https://piclist.cn/configure.html#%E5%86%85%E7%BD%AEsftp',
smms: 'https://piclist.cn/configure.html#sm-ms',
telegraphplist: 'https://piclist.cn/configure.html#telegra-ph',
upyun: 'https://piclist.cn/configure.html#%E5%8F%88%E6%8B%8D%E4%BA%91',
webdavplist: 'https://piclist.cn/configure.html#webdav'
},
en: {
aliyun: 'https://piclist.cn/en/configure.html#alibaba-cloud',
'aws-s3': 'https://piclist.cn/en/configure.html#built-in-aws-s3',
'aws-s3-plist': 'https://piclist.cn/en/configure.html#built-in-aws-s3',
github: 'https://piclist.cn/en/configure.html#github',
githubPlus: 'https://piclist.cn/en/configure.html#github',
imgur: 'https://piclist.cn/en/configure.html#imgur',
lankong: 'https://github.com/hellodk34/picgo-plugin-lankong',
local: 'https://piclist.cn/en/configure.html#local-image-hosting',
lskyplist: 'https://piclist.cn/en/configure.html#lsky-pro',
tcyun: 'https://piclist.cn/en/configure.html#tencent-cloud-cos',
piclist: 'https://piclist.cn/en/configure.html#piclist',
qiniu: 'https://piclist.cn/en/configure.html#qiniu-cloud',
sftpplist: 'https://piclist.cn/en/configure.html#built-in-sftp',
smms: 'https://piclist.cn/en/configure.html#sm-ms',
telegraphplist: 'https://piclist.cn/en/configure.html#telegra-ph',
upyun: 'https://piclist.cn/en/configure.html#upyun',
webdavplist: 'https://piclist.cn/en/configure.html#webdav'
}
}
export const DEFAULT_AES_PASSWORD = 'aesPassword' export const DEFAULT_AES_PASSWORD = 'aesPassword'