Merge branch 'dev' into release

This commit is contained in:
Kuingsmile 2024-04-09 16:19:07 +08:00
commit d58ad2653e
66 changed files with 1421 additions and 564 deletions

View File

@ -1,3 +1,36 @@
## :tada: 2.8.1 (2024-04-09)
### :sparkles: Features
* **custom:** add api doc for 36677 port ([872a1a7](https://github.com/Kuingsmile/piclist/commit/872a1a7))
* **custom:** add buildin web server ([ab8b62e](https://github.com/Kuingsmile/piclist/commit/ab8b62e)), closes [#180](https://github.com/Kuingsmile/piclist/issues/180)
* **custom:** add log for image processing ([e4c1c7f](https://github.com/Kuingsmile/piclist/commit/e4c1c7f))
* **custom:** add u flag for gallery regexp match ([aa9e535](https://github.com/Kuingsmile/piclist/commit/aa9e535))
* **custom:** change buildin rename md5 calculate ([bf8d7b4](https://github.com/Kuingsmile/piclist/commit/bf8d7b4)), closes [#178](https://github.com/Kuingsmile/piclist/issues/178)
* **custom:** exclude svg from watermarker ([75b0c7f](https://github.com/Kuingsmile/piclist/commit/75b0c7f)), closes [#182](https://github.com/Kuingsmile/piclist/issues/182)
* **custom:** optimize the processing of upload path and custom url ([ae40a16](https://github.com/Kuingsmile/piclist/commit/ae40a16))
* **custom:** optimize webServer ([e6e9472](https://github.com/Kuingsmile/piclist/commit/e6e9472))
* **custom:** refactor upload and delete api ([475b85e](https://github.com/Kuingsmile/piclist/commit/475b85e))
* **custom:** update api doc ([922f04f](https://github.com/Kuingsmile/piclist/commit/922f04f))
### :bug: Bug Fixes
* **custom:** fix compatiblity with typora ([762913c](https://github.com/Kuingsmile/piclist/commit/762913c))
* **custom:** fix error handling in server startup ([cf0450f](https://github.com/Kuingsmile/piclist/commit/cf0450f))
* **custom:** fix image watermark bug ([8e5e6d4](https://github.com/Kuingsmile/piclist/commit/8e5e6d4))
### :pencil: Documentation
* **custom:** add tg group qr code ([5cd34a6](https://github.com/Kuingsmile/piclist/commit/5cd34a6))
* **custom:** prepare for 2.8.1 ([f73badd](https://github.com/Kuingsmile/piclist/commit/f73badd))
* **custom:** prepare for 2.81 ([0476346](https://github.com/Kuingsmile/piclist/commit/0476346))
* **custom:** update tg group link ([20f6acc](https://github.com/Kuingsmile/piclist/commit/20f6acc))
# :tada: 2.8.0 (2024-03-14) # :tada: 2.8.0 (2024-03-14)

View File

@ -231,9 +231,11 @@ If you need to build it yourself, you can start building with `yarn run build`.
## Communication group ## Communication group
If you have any questions, you can join the WeChat group for communication. If you have any questions, you can join the TG group for communication.
![wechat](https://pichoro.msq.pub/wechat.png) [PicList TG Group](https://t.me/+rq8y7wsj7Pg5ZTg1)
![tg](https://pichoro.msq.pub/wechat.png)
## License ## License

View File

@ -221,9 +221,11 @@ brew uninstall piclist
## 交流群 ## 交流群
如果有任何问题,可以加入微信群进行交流. 如果有任何问题,可以加入TG群进行交流.
![wechat](https://pichoro.msq.pub/wechat.png) [PicList交流群](https://t.me/+rq8y7wsj7Pg5ZTg1)
![tg](https://pichoro.msq.pub/wechat.png)
## License ## License

View File

@ -1,15 +1,22 @@
💥 Breaking Change
- 由于[C1N短网址](https://www.c1n.cn/)的收费策略修改预期可使用API的团队版在1000元/年作者承担费用压力较大现在修改为自己提供API token
- 原软件内置提供的c1n token即时失效
✨ Features ✨ Features
- 新增对cf workers 短链接项目[xyTom/Url-Shorten-Worker](https://github.com/xyTom/Url-Shorten-Worker)的支持 - 图床功能优化
- 现在相册页面支持强制无视缓存刷新 - 优化了github等图床路径设置为`/`时的处理
- 优化了阿里云图床对无扩增名文件的上传处理 - 现在会自动对上传路径开始和结尾的`/`进行处理,大部分图床不再强制要求路径以`/`结尾
- 优化了短网址功能的错误日志记录 - 优化了对自定义网站的处理,现在会自动去除最后多余的`/`
- 上传服务器
- 现在来自本机的上传请求不再进行鉴权
- 现在浏览器访问36677端口会显示API文档支持`/`和`/upload`路径)
- 现在`heartbeat`接口支持`GET`请求
- 新增内置web服务支持默认在37777端口开启一个简易web服务器类似`EasyWebSvr`
- 现在不再对`svg`图片进行水印处理
- 现在内置高级重命名中`{md5}`使用文件内容而非文件名字符串计算
- 现在相册URL修改功能的正则匹配增加了`u`修饰符
- 现在设置界面的弹出窗口支持拖拽调整位置
- 现在图片处理过程会记录错误日志
🐛 Bug Fixes 🐛 Bug Fixes
- 修复了buffer上传时的文件名错误 - 修复了设置了服务器鉴权密钥后Typora上传失败的问题
- 修复了未设置水印文字时图片水印功能无法生效的bug
- 修复了server端口被占用时端口探测功能没有正常发挥作用的问题

View File

@ -1,15 +1,22 @@
💥 Breaking Change
- Due to the upcoming changes in the charging policy of [C1N short URL](https://www.c1n.cn/), the expected team version that can use the API will be around 1000 yuan/year, and the author bears a greater pressure on the cost. Now it is changed to provide the API token by yourself
- The c1n token provided by the original software is immediately invalid
✨ Features ✨ Features
- Added support for the cf workers short link project [xyTom/Url-Shorten-Worker](https://github.com/xyTom/Url-Shorten-Worker) - Picture bed function optimization
- Now the album page supports forced cache refresh - Optimized the processing of the path set to `/` for github and other picture beds
- Optimized the upload processing of files without extension names for Aliyun image bed - Now it will automatically process the `/` at the beginning and end of the upload path, and most picture beds no longer require the path to end with `/`
- Optimized error log recording for short URL function - Optimized the processing of custom websites, now it will automatically remove the extra `/` at the end
- Upload server
- Now the upload requests from the local machine no longer require authentication
- Now browsing port 36677 will display the API document (support `/` and `/upload` paths)
- Now the `heartbeat` interface supports `GET` requests
- Added built-in web service support, a simple web server is opened by default on port 37777, similar to `EasyWebSvr`
- Now no longer watermark `svg` images
- Now the `{md5}` in the advanced rename uses the file content instead of the file name string for calculation
- The regular expression matching of the album URL modification function now adds the `u` modifier
- Now the pop-up window in the settings interface supports dragging to adjust the position
- Now the image processing process will record error logs
🐛 Bug Fixes 🐛 Bug Fixes
- Fixed the file name error when uploading buffer - Fix the problem of Typora upload failure after setting the server authentication key
- Fixed the bug that the image watermark function does not take effect when the watermark text is not set
- Fixed the problem that the port detection function does not work properly when the server port is occupied

View File

@ -1,6 +1,6 @@
{ {
"name": "piclist", "name": "piclist",
"version": "2.8.0", "version": "2.8.1",
"author": { "author": {
"name": "Kuingsmile", "name": "Kuingsmile",
"email": "pkukuing@gmail.com" "email": "pkukuing@gmail.com"
@ -46,7 +46,7 @@
"@smithy/node-http-handler": "^2.1.6", "@smithy/node-http-handler": "^2.1.6",
"@videojs-player/vue": "^1.0.0", "@videojs-player/vue": "^1.0.0",
"ali-oss": "^6.18.1", "ali-oss": "^6.18.1",
"axios": "^1.6.2", "axios": "^1.6.8",
"compare-versions": "^4.1.3", "compare-versions": "^4.1.3",
"core-js": "^3.33.3", "core-js": "^3.33.3",
"cos-nodejs-sdk-v5": "^2.12.5", "cos-nodejs-sdk-v5": "^2.12.5",
@ -68,7 +68,7 @@
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"node-ssh-no-cpu-features": "^1.0.1", "node-ssh-no-cpu-features": "^1.0.1",
"nodejs-file-downloader": "^4.12.1", "nodejs-file-downloader": "^4.12.1",
"piclist": "^1.7.12", "piclist": "^1.8.3",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.0", "pinia-plugin-persistedstate": "^3.2.0",
"proxy-agent": "^5.0.0", "proxy-agent": "^5.0.0",

View File

@ -209,6 +209,14 @@ SETTINGS_ENABLE_SERVER: Enable Server
SETTINGS_SET_SERVER_HOST: Set Server Host SETTINGS_SET_SERVER_HOST: Set Server Host
SETTINGS_SET_SERVER_PORT: Set Server Port SETTINGS_SET_SERVER_PORT: Set Server Port
SETTINGS_SET_SERVER_KEY: Set Auth Key SETTINGS_SET_SERVER_KEY: Set Auth Key
SETTINGS_SET_WEB_SERVER: Set Web Server
SETTINGS_TIPS_WEB_SERVER_NOTICE: If you don't know what is the web server's function, please read the document, or don't modify the configuration.
SETTINGS_SET_ENABLE_WEB_SERVER: Enable Web Server
SETTINGS_SET_WEB_SERVER_HOST: Set Web Server Host
SETTINGS_SET_WEB_SERVER_PORT: Set Web Server Port
SETTINGS_SET_WEB_SERVER_PATH: Set Web Server Path
SETTINGS_TIP_PLACEHOLDER_WEB_HOST: Default:127.0.0.1
SETTINGS_TIP_PLACEHOLDER_WEB_PORT: Default:37777
SETTINGS_TIP_PLACEHOLDER_HOST: Default:127.0.0.1 SETTINGS_TIP_PLACEHOLDER_HOST: Default:127.0.0.1
SETTINGS_TIP_PLACEHOLDER_PORT: Default:36677 SETTINGS_TIP_PLACEHOLDER_PORT: Default:36677
SETTINGS_TIP_PLACEHOLDER_KEY: This key is used to avoid malicious requests, through urlParams '?key=xxx' to pass SETTINGS_TIP_PLACEHOLDER_KEY: This key is used to avoid malicious requests, through urlParams '?key=xxx' to pass

View File

@ -211,6 +211,14 @@ SETTINGS_ENABLE_SERVER: 是否开启Server
SETTINGS_SET_SERVER_HOST: 设置监听地址 SETTINGS_SET_SERVER_HOST: 设置监听地址
SETTINGS_SET_SERVER_PORT: 设置监听端口 SETTINGS_SET_SERVER_PORT: 设置监听端口
SETTINGS_SET_SERVER_KEY: 设置鉴权密钥 SETTINGS_SET_SERVER_KEY: 设置鉴权密钥
SETTINGS_SET_WEB_SERVER: 设置Web服务
SETTINGS_TIPS_WEB_SERVER_NOTICE: 如果你不知道Web服务的作用请阅读文档或者不用修改配置。
SETTINGS_SET_ENABLE_WEB_SERVER: 是否开启Web服务
SETTINGS_SET_WEB_SERVER_HOST: 设置Web服务监听地址
SETTINGS_SET_WEB_SERVER_PORT: 设置Web服务监听端口
SETTINGS_SET_WEB_SERVER_PATH: 设置Web服务路径
SETTINGS_TIP_PLACEHOLDER_WEB_HOST: 推荐默认地址:127.0.0.1
SETTINGS_TIP_PLACEHOLDER_WEB_PORT: 推荐默认端口:37777
SETTINGS_TIP_PLACEHOLDER_HOST: 推荐默认地址:127.0.0.1 SETTINGS_TIP_PLACEHOLDER_HOST: 推荐默认地址:127.0.0.1
SETTINGS_TIP_PLACEHOLDER_PORT: 推荐默认端口:36677 SETTINGS_TIP_PLACEHOLDER_PORT: 推荐默认端口:36677
SETTINGS_TIP_PLACEHOLDER_KEY: 用于接口鉴权, 通过url参数添加'?key=xxx' SETTINGS_TIP_PLACEHOLDER_KEY: 用于接口鉴权, 通过url参数添加'?key=xxx'

View File

@ -209,6 +209,14 @@ SETTINGS_ENABLE_SERVER: 是否開啟Server
SETTINGS_SET_SERVER_HOST: 設定監聽地址 SETTINGS_SET_SERVER_HOST: 設定監聽地址
SETTINGS_SET_SERVER_PORT: 設定監聽端口 SETTINGS_SET_SERVER_PORT: 設定監聽端口
SETTINGS_SET_SERVER_KEY: 設定鑒權密鑰 SETTINGS_SET_SERVER_KEY: 設定鑒權密鑰
SETTINGS_SET_WEB_SERVER: 設定Web服務
SETTINGS_TIPS_WEB_SERVER_NOTICE: 如果你不知道Web服務的作用請閱讀文檔或者不用修改設定。
SETTINGS_SET_ENABLE_WEB_SERVER: 是否開啟Web服務
SETTINGS_SET_WEB_SERVER_HOST: 設定Web服務地
SETTINGS_SET_WEB_SERVER_PORT: 設定Web服務端口
SETTINGS_SET_WEB_SERVER_PATH: 設定Web服務路徑
SETTINGS_TIP_PLACEHOLDER_WEB_HOST: 推薦預設地址:127.0.0.1
SETTINGS_TIP_PLACEHOLDER_WEB_PORT: 推薦預設端口:37777
SETTINGS_TIP_PLACEHOLDER_HOST: 推薦預設地址:127.0.0.1 SETTINGS_TIP_PLACEHOLDER_HOST: 推薦預設地址:127.0.0.1
SETTINGS_TIP_PLACEHOLDER_PORT: 推薦預設端口:36677 SETTINGS_TIP_PLACEHOLDER_PORT: 推薦預設端口:36677
SETTINGS_TIP_PLACEHOLDER_KEY: 用於接口鑒權, 通過url參數添加'?key=xxx' SETTINGS_TIP_PLACEHOLDER_KEY: 用於接口鑒權, 通過url參數添加'?key=xxx'

View File

@ -18,6 +18,7 @@ import shortKeyService from './shortKeyService'
// External utility functions // External utility functions
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants' import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
import { configPaths } from '~/universal/utils/configPaths'
class ShortKeyHandler { class ShortKeyHandler {
private isInModifiedMode: boolean = false private isInModifiedMode: boolean = false
@ -33,7 +34,7 @@ class ShortKeyHandler {
} }
private initBuiltInShortKey () { private initBuiltInShortKey () {
const commands = db.get('settings.shortKey') as IShortKeyConfigs const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
Object.keys(commands) Object.keys(commands)
.filter(item => item.includes('picgo:')) .filter(item => item.includes('picgo:'))
.forEach(command => { .forEach(command => {
@ -175,7 +176,7 @@ class ShortKeyHandler {
} }
unregisterPluginShortKey (pluginName: string) { unregisterPluginShortKey (pluginName: string) {
const commands = db.get('settings.shortKey') as IShortKeyConfigs const commands = db.get(configPaths.settings.shortKey._path) as IShortKeyConfigs
const keyList = Object.keys(commands) const keyList = Object.keys(commands)
.filter(command => command.includes(pluginName)) .filter(command => command.includes(pluginName))
.map(command => { .map(command => {
@ -187,7 +188,7 @@ class ShortKeyHandler {
keyList.forEach(item => { keyList.forEach(item => {
globalShortcut.unregister(item.key) globalShortcut.unregister(item.key)
shortKeyService.unregisterCommand(item.command) shortKeyService.unregisterCommand(item.command)
db.unset('settings.shortKey', item.command) db.unset(configPaths.settings.shortKey._path, item.command)
}) })
} }
} }

View File

@ -18,7 +18,7 @@ import {
import uploader from 'apis/app/uploader' import uploader from 'apis/app/uploader'
import db, { GalleryDB } from '~/main/apis/core/datastore' import db, { GalleryDB } from '~/main/apis/core/datastore'
import windowManager from 'apis/app/window/windowManager' import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from '#/types/enum' import { IPasteStyle, IWindowList } from '#/types/enum'
import pasteTemplate from '~/main/utils/pasteTemplate' import pasteTemplate from '~/main/utils/pasteTemplate'
import pkg from 'root/package.json' import pkg from 'root/package.json'
import { ensureFilePath, handleCopyUrl } from '~/main/utils/common' import { ensureFilePath, handleCopyUrl } from '~/main/utils/common'
@ -28,13 +28,14 @@ import { buildPicBedListMenu } from '~/main/events/remotes/menu'
import clipboardPoll from '~/main/utils/clipboardPoll' import clipboardPoll from '~/main/utils/clipboardPoll'
import picgo from '../../core/picgo' import picgo from '../../core/picgo'
import { uploadClipboardFiles } from '../uploader/apis' import { uploadClipboardFiles } from '../uploader/apis'
import { configPaths } from '~/universal/utils/configPaths'
let contextMenu: Menu | null let contextMenu: Menu | null
let tray: Tray | null let tray: Tray | null
export function setDockMenu () { export function setDockMenu () {
const isListeningClipboard = db.get('settings.isListeningClipboard') || false const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const autoCloseMiniWindow = db.get('settings.autoCloseMiniWindow') || false const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
const dockMenu = Menu.buildFromTemplate([ const dockMenu = Menu.buildFromTemplate([
{ {
label: T('OPEN_MAIN_WINDOW'), label: T('OPEN_MAIN_WINDOW'),
@ -50,7 +51,7 @@ export function setDockMenu () {
{ {
label: T('START_WATCH_CLIPBOARD'), label: T('START_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', true) db.set(configPaths.settings.isListeningClipboard, true)
clipboardPoll.startListening() clipboardPoll.startListening()
clipboardPoll.on('change', () => { clipboardPoll.on('change', () => {
picgo.log.info('clipboard changed') picgo.log.info('clipboard changed')
@ -63,7 +64,7 @@ export function setDockMenu () {
{ {
label: T('STOP_WATCH_CLIPBOARD'), label: T('STOP_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', false) db.set(configPaths.settings.isListeningClipboard, false)
clipboardPoll.stopListening() clipboardPoll.stopListening()
clipboardPoll.removeAllListeners() clipboardPoll.removeAllListeners()
setDockMenu() setDockMenu()
@ -84,7 +85,7 @@ export function createMenu () {
label: T('OPEN_MAIN_WINDOW'), label: T('OPEN_MAIN_WINDOW'),
click () { click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get('settings.autoCloseMiniWindow') || false const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show() settingWindow!.show()
settingWindow!.focus() settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) { if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
@ -141,7 +142,7 @@ export function createMenu () {
export function createContextMenu () { export function createContextMenu () {
const ClipboardWatcher = clipboardPoll const ClipboardWatcher = clipboardPoll
const isListeningClipboard = db.get('settings.isListeningClipboard') || false const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
if (process.platform === 'darwin' || process.platform === 'win32') { if (process.platform === 'darwin' || process.platform === 'win32') {
const submenu = buildPicBedListMenu() const submenu = buildPicBedListMenu()
const template = [ const template = [
@ -149,7 +150,7 @@ export function createContextMenu () {
label: T('OPEN_MAIN_WINDOW'), label: T('OPEN_MAIN_WINDOW'),
click () { click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get('settings.autoCloseMiniWindow') || false const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show() settingWindow!.show()
settingWindow!.focus() settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) { if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
@ -166,7 +167,7 @@ export function createContextMenu () {
{ {
label: T('START_WATCH_CLIPBOARD'), label: T('START_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', true) db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening() ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => { ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed') picgo.log.info('clipboard changed')
@ -179,7 +180,7 @@ export function createContextMenu () {
{ {
label: T('STOP_WATCH_CLIPBOARD'), label: T('STOP_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', false) db.set(configPaths.settings.isListeningClipboard, false)
ClipboardWatcher.stopListening() ClipboardWatcher.stopListening()
ClipboardWatcher.removeAllListeners() ClipboardWatcher.removeAllListeners()
createContextMenu() createContextMenu()
@ -206,11 +207,11 @@ export function createContextMenu () {
click () { click () {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.removeAllListeners() miniWindow.removeAllListeners()
if (db.get('settings.miniWindowOntop')) { if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true) miniWindow.setAlwaysOnTop(true)
} }
const { width, height } = screen.getPrimaryDisplay().workAreaSize const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get('settings.miniWindowPosition') const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) { if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1]) miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else { } else {
@ -218,13 +219,13 @@ export function createContextMenu () {
} }
const setPositionFunc = () => { const setPositionFunc = () => {
const position = miniWindow.getPosition() const position = miniWindow.getPosition()
db.set('settings.miniWindowPosition', position) db.set(configPaths.settings.miniWindowPosition, position)
} }
miniWindow.on('close', setPositionFunc) miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc) miniWindow.on('move', setPositionFunc)
miniWindow.show() miniWindow.show()
miniWindow.focus() miniWindow.focus()
const autoCloseMainWindow = db.get('settings.autoCloseMainWindow') || false const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) { if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
windowManager.get(IWindowList.SETTING_WINDOW)!.hide() windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
} }
@ -246,7 +247,7 @@ export function createContextMenu () {
label: T('OPEN_MAIN_WINDOW'), label: T('OPEN_MAIN_WINDOW'),
click () { click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get('settings.autoCloseMiniWindow') || false const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show() settingWindow!.show()
settingWindow!.focus() settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) { if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
@ -259,11 +260,11 @@ export function createContextMenu () {
click () { click () {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.removeAllListeners() miniWindow.removeAllListeners()
if (db.get('settings.miniWindowOntop')) { if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true) miniWindow.setAlwaysOnTop(true)
} }
const { width, height } = screen.getPrimaryDisplay().workAreaSize const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get('settings.miniWindowPosition') const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) { if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1]) miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else { } else {
@ -271,13 +272,13 @@ export function createContextMenu () {
} }
const setPositionFunc = () => { const setPositionFunc = () => {
const position = miniWindow.getPosition() const position = miniWindow.getPosition()
db.set('settings.miniWindowPosition', position) db.set(configPaths.settings.miniWindowPosition, position)
} }
miniWindow.on('close', setPositionFunc) miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc) miniWindow.on('move', setPositionFunc)
miniWindow.show() miniWindow.show()
miniWindow.focus() miniWindow.focus()
const autoCloseMainWindow = db.get('settings.autoCloseMainWindow') || false const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) { if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
windowManager.get(IWindowList.SETTING_WINDOW)!.hide() windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
} }
@ -286,7 +287,7 @@ export function createContextMenu () {
{ {
label: T('START_WATCH_CLIPBOARD'), label: T('START_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', true) db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening() ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => { ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed') picgo.log.info('clipboard changed')
@ -299,7 +300,7 @@ export function createContextMenu () {
{ {
label: T('STOP_WATCH_CLIPBOARD'), label: T('STOP_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', false) db.set(configPaths.settings.isListeningClipboard, false)
ClipboardWatcher.stopListening() ClipboardWatcher.stopListening()
ClipboardWatcher.removeAllListeners() ClipboardWatcher.removeAllListeners()
createContextMenu() createContextMenu()
@ -388,7 +389,7 @@ export function createTray () {
windowManager.get(IWindowList.TRAY_WINDOW)!.hide() windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
} }
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW) const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get('settings.autoCloseMiniWindow') || false const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show() settingWindow!.show()
settingWindow!.focus() settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) { if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
@ -412,21 +413,21 @@ export function createTray () {
// drop-files only be supported in macOS // drop-files only be supported in macOS
// so the tray window must be available // so the tray window must be available
tray.on('drop-files', async (event: Event, files: string[]) => { tray.on('drop-files', async (event: Event, files: string[]) => {
const pasteStyle = db.get('settings.pasteStyle') || 'markdown' const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const rawInput = cloneDeep(files) const rawInput = cloneDeep(files)
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)! const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
const imgs = await uploader const imgs = await uploader
.setWebContents(trayWindow.webContents) .setWebContents(trayWindow.webContents)
.upload(files) .upload(files)
const deleteLocalFile = db.get('settings.deleteLocalFile') || false const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false
if (imgs !== false) { if (imgs !== false) {
const pasteText: string[] = [] const pasteText: string[] = []
for (let i = 0; i < imgs.length; i++) { for (let i = 0; i < imgs.length; i++) {
if (deleteLocalFile) { if (deleteLocalFile) {
await fs.remove(rawInput[i]) await fs.remove(rawInput[i])
} }
pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))) pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink))))
const isShowResultNotification = db.get('settings.uploadResultNotification') === undefined ? true : !!db.get('settings.uploadResultNotification') const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) { if (isShowResultNotification) {
const notification = new Notification({ const notification = new Notification({
title: T('UPLOAD_SUCCEED'), title: T('UPLOAD_SUCCEED'),

View File

@ -18,15 +18,16 @@ import ALLApi from '@/apis/allApi'
import picgo from '@core/picgo' import picgo from '@core/picgo'
import GuiApi from '../../gui' import GuiApi from '../../gui'
import uploader from '.' import uploader from '.'
import { IWindowList } from '#/types/enum' import { IPasteStyle, IWindowList } from '#/types/enum'
import { picBedsCanbeDeleted } from '#/utils/static' import { picBedsCanbeDeleted } from '#/utils/static'
import path from 'path' import path from 'path'
import SSHClient from '~/main/utils/sshClient' import SSHClient from '~/main/utils/sshClient'
import { ISftpPlistConfig } from 'piclist' import { ISftpPlistConfig } from 'piclist'
import { getRawData } from '~/renderer/utils/common' import { getRawData } from '~/renderer/utils/common'
import { configPaths } from '~/universal/utils/configPaths'
const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => { const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
const useBuiltinClipboard = db.get('settings.useBuiltinClipboard') === undefined ? true : !!db.get('settings.useBuiltinClipboard') const useBuiltinClipboard = db.get(configPaths.settings.useBuiltinClipboard) === undefined ? true : !!db.get(configPaths.settings.useBuiltinClipboard)
const win = windowManager.getAvailableWindow() const win = windowManager.getAvailableWindow()
if (useBuiltinClipboard) { if (useBuiltinClipboard) {
return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard() return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard()
@ -36,13 +37,12 @@ const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
export const uploadClipboardFiles = async (): Promise<IStringKeyMap> => { export const uploadClipboardFiles = async (): Promise<IStringKeyMap> => {
const img = await handleClipboardUploading() const img = await handleClipboardUploading()
console.log(img)
if (img !== false) { if (img !== false) {
if (img.length > 0) { if (img.length > 0) {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW) const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
const pasteStyle = db.get('settings.pasteStyle') || 'markdown' const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get('settings.customLink')))) handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))))
const isShowResultNotification = db.get('settings.uploadResultNotification') === undefined ? true : !!db.get('settings.uploadResultNotification') const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) { if (isShowResultNotification) {
const notification = new Notification({ const notification = new Notification({
title: T('UPLOAD_SUCCEED'), title: T('UPLOAD_SUCCEED'),
@ -89,8 +89,8 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
const imgs = await uploader.setWebContents(webContents).upload(input) const imgs = await uploader.setWebContents(webContents).upload(input)
const result = [] const result = []
if (imgs !== false) { if (imgs !== false) {
const pasteStyle = db.get('settings.pasteStyle') || 'markdown' const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const deleteLocalFile = db.get('settings.deleteLocalFile') || false const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false
const pasteText: string[] = [] const pasteText: string[] = []
for (let i = 0; i < imgs.length; i++) { for (let i = 0; i < imgs.length; i++) {
if (deleteLocalFile) { if (deleteLocalFile) {
@ -100,8 +100,8 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
picgo.log.error(err) picgo.log.error(err)
}) })
} }
pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))) pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink))))
const isShowResultNotification = db.get('settings.uploadResultNotification') === undefined ? true : !!db.get('settings.uploadResultNotification') const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) { if (isShowResultNotification) {
const notification = new Notification({ const notification = new Notification({
title: T('UPLOAD_SUCCEED'), title: T('UPLOAD_SUCCEED'),
@ -153,7 +153,7 @@ export const deleteChoosedFiles = async (list: ImgInfo[]): Promise<boolean[]> =>
const dbStore = GalleryDB.getInstance() const dbStore = GalleryDB.getInstance()
const file = await dbStore.getById(item.id) const file = await dbStore.getById(item.id)
await dbStore.removeById(item.id) await dbStore.removeById(item.id)
if (await picgo.getConfig('settings.deleteCloudFile')) { if (await picgo.getConfig(configPaths.settings.deleteCloudFile)) {
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) { if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
const noteFunc = (value: boolean) => { const noteFunc = (value: boolean) => {
const notification = new Notification({ const notification = new Notification({

View File

@ -33,6 +33,7 @@ import {
RENAME_FILE_NAME, RENAME_FILE_NAME,
TALKING_DATA_EVENT TALKING_DATA_EVENT
} from '~/universal/events/constants' } from '~/universal/events/constants'
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) => {
@ -80,7 +81,7 @@ class Uploader {
this.webContents?.send('uploadProgress', progress) this.webContents?.send('uploadProgress', progress)
}) })
picgo.on('beforeTransform', () => { picgo.on('beforeTransform', () => {
if (db.get('settings.uploadNotification')) { if (db.get(configPaths.settings.uploadNotification)) {
const notification = new Notification({ const notification = new Notification({
title: T('UPLOAD_PROGRESS'), title: T('UPLOAD_PROGRESS'),
body: T('UPLOADING') body: T('UPLOADING')
@ -90,8 +91,8 @@ class Uploader {
}) })
picgo.helper.beforeUploadPlugins.register('renameFn', { picgo.helper.beforeUploadPlugins.register('renameFn', {
handle: async (ctx: IPicGo) => { handle: async (ctx: IPicGo) => {
const rename = db.get('settings.rename') const rename = db.get(configPaths.settings.rename)
const autoRename = db.get('settings.autoRename') const autoRename = db.get(configPaths.settings.autoRename)
if (autoRename || rename) { if (autoRename || rename) {
await Promise.all(ctx.output.map(async (item, index) => { await Promise.all(ctx.output.map(async (item, index) => {
let name: undefined | string | null let name: undefined | string | null
@ -163,7 +164,7 @@ class Uploader {
if (this.webContents) { if (this.webContents) {
handleTalkingData(this.webContents, { handleTalkingData(this.webContents, {
fromClipboard: !img, fromClipboard: !img,
type: db.get('picBed.uploader') || db.get('picBed.current') || 'smms', type: db.get(configPaths.picBed.uploader) || db.get(configPaths.picBed.current) || 'smms',
count: img ? img.length : 1, count: img ? img.length : 1,
duration: Date.now() - startTime duration: Date.now() - startTime
} as IAnalyticsData) } as IAnalyticsData)

View File

@ -23,14 +23,15 @@ import { IWindowList } from '#/types/enum'
// External utility functions // External utility functions
import { CREATE_APP_MENU } from '@core/bus/constants' import { CREATE_APP_MENU } from '@core/bus/constants'
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants' import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
import { configPaths } from '~/universal/utils/configPaths'
const windowList = new Map<IWindowList, IWindowListItem>() const windowList = new Map<IWindowList, IWindowListItem>()
const handleWindowParams = (windowURL: string) => windowURL const handleWindowParams = (windowURL: string) => windowURL
const getDefaultWindowSizes = (): { width: number, height: number } => { const getDefaultWindowSizes = (): { width: number, height: number } => {
const mainWindowWidth = picgo.getConfig<any>('settings.mainWindowWidth') const mainWindowWidth = picgo.getConfig<any>(configPaths.settings.mainWindowWidth)
const mainWindowHeight = picgo.getConfig<any>('settings.mainWindowHeight') const mainWindowHeight = picgo.getConfig<any>(configPaths.settings.mainWindowHeight)
return { return {
width: mainWindowWidth || 1200, width: mainWindowWidth || 1200,
height: mainWindowHeight || 800 height: mainWindowHeight || 800
@ -127,7 +128,7 @@ const miniWindowOptions = {
} }
} as IBrowserWindowOptions } as IBrowserWindowOptions
if (db.get('settings.miniWindowOntop')) { if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindowOptions.alwaysOnTop = true miniWindowOptions.alwaysOnTop = true
} }

View File

@ -13,6 +13,7 @@ import { DBStore, JSONStore } from '@picgo/store'
// External utility functions // External utility functions
import { T } from '~/main/i18n' import { T } from '~/main/i18n'
import { configPaths } from '~/universal/utils/configPaths'
const STORE_PATH = dbPathDir() const STORE_PATH = dbPathDir()
@ -37,8 +38,8 @@ class ConfigStore {
}) })
} }
if (!this.db.has('settings.shortKey')) { if (!this.db.has(configPaths.settings.shortKey._path)) {
this.db.set('settings.shortKey[picgo:upload]', { this.db.set(configPaths.settings.shortKey['picgo:upload'], {
enable: true, enable: true,
key: 'CommandOrControl+Shift+P', key: 'CommandOrControl+Shift+P',
name: 'upload', name: 'upload',

View File

@ -24,6 +24,8 @@ import { SHOW_INPUT_BOX } from '~/universal/events/constants'
// External utility functions // External utility functions
import { DBStore } from '@picgo/store' import { DBStore } from '@picgo/store'
import { T } from '~/main/i18n' import { T } from '~/main/i18n'
import { configPaths } from '~/universal/utils/configPaths'
import { IPasteStyle } from '~/universal/types/enum'
// Cross-process support may be required in the future // Cross-process support may be required in the future
class GuiApi implements IGuiApi { class GuiApi implements IGuiApi {
@ -85,15 +87,15 @@ class GuiApi implements IGuiApi {
const rawInput = cloneDeep(input) const rawInput = cloneDeep(input)
const imgs = await uploader.setWebContents(webContents!).upload(input) const imgs = await uploader.setWebContents(webContents!).upload(input)
if (imgs !== false) { if (imgs !== false) {
const pasteStyle = db.get('settings.pasteStyle') || 'markdown' const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const deleteLocalFile = db.get('settings.deleteLocalFile') || false const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false
const pasteText: string[] = [] const pasteText: string[] = []
for (let i = 0; i < imgs.length; i++) { for (let i = 0; i < imgs.length; i++) {
if (deleteLocalFile) { if (deleteLocalFile) {
await fs.remove(rawInput[i]) await fs.remove(rawInput[i])
} }
pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))) pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink))))
const isShowResultNotification = db.get('settings.uploadResultNotification') === undefined ? true : !!db.get('settings.uploadResultNotification') const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) { if (isShowResultNotification) {
const notification = new Notification({ const notification = new Notification({
title: T('UPLOAD_SUCCEED'), title: T('UPLOAD_SUCCEED'),

View File

@ -14,7 +14,7 @@ import {
import windowManager from 'apis/app/window/windowManager' import windowManager from 'apis/app/window/windowManager'
// 枚举类型声明 // 枚举类型声明
import { IWindowList } from '#/types/enum' import { IPasteStyle, IWindowList } from '#/types/enum'
// 上传器 // 上传器
import uploader from 'apis/app/uploader' import uploader from 'apis/app/uploader'
@ -89,6 +89,8 @@ import SSHClient from '../utils/sshClient'
import { ISftpPlistConfig } from 'piclist' 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 { configPaths } from '~/universal/utils/configPaths'
const STORE_PATH = app.getPath('userData') const STORE_PATH = app.getPath('userData')
@ -102,9 +104,9 @@ export default {
// macOS use builtin clipboard is OK // macOS use builtin clipboard is OK
const img = await uploader.setWebContents(trayWindow.webContents).uploadWithBuildInClipboard() const img = await uploader.setWebContents(trayWindow.webContents).uploadWithBuildInClipboard()
if (img !== false) { if (img !== false) {
const pasteStyle = db.get('settings.pasteStyle') || 'markdown' const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get('settings.customLink')))) handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))))
const isShowResultNotification = db.get('settings.uploadResultNotification') === undefined ? true : !!db.get('settings.uploadResultNotification') const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) { if (isShowResultNotification) {
const notification = new Notification({ const notification = new Notification({
title: T('UPLOAD_SUCCEED'), title: T('UPLOAD_SUCCEED'),
@ -298,7 +300,7 @@ export default {
ipcMain.on('openSettingWindow', () => { ipcMain.on('openSettingWindow', () => {
windowManager.get(IWindowList.SETTING_WINDOW)!.show() windowManager.get(IWindowList.SETTING_WINDOW)!.show()
const autoCloseMiniWindow = db.get('settings.autoCloseMiniWindow') || false const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
if (autoCloseMiniWindow) { if (autoCloseMiniWindow) {
if (windowManager.has(IWindowList.MINI_WINDOW)) { if (windowManager.has(IWindowList.MINI_WINDOW)) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide() windowManager.get(IWindowList.MINI_WINDOW)!.hide()
@ -314,11 +316,11 @@ export default {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
miniWindow.removeAllListeners() miniWindow.removeAllListeners()
if (db.get('settings.miniWindowOntop')) { if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true) miniWindow.setAlwaysOnTop(true)
} }
const { width, height } = screen.getPrimaryDisplay().workAreaSize const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get('settings.miniWindowPosition') const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) { if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1]) miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else { } else {
@ -326,7 +328,7 @@ export default {
} }
const setPositionFunc = () => { const setPositionFunc = () => {
const position = miniWindow.getPosition() const position = miniWindow.getPosition()
db.set('settings.miniWindowPosition', position) db.set(configPaths.settings.miniWindowPosition, position)
} }
miniWindow.on('close', setPositionFunc) miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc) miniWindow.on('move', setPositionFunc)
@ -360,6 +362,12 @@ export default {
ipcMain.on('updateServer', () => { ipcMain.on('updateServer', () => {
server.restart() server.restart()
}) })
ipcMain.on('stopWebServer', () => {
webServer.stop()
})
ipcMain.on('restartWebServer', () => {
webServer.restart()
})
ipcMain.on(OPEN_DEVTOOLS, (event: IpcMainEvent) => { ipcMain.on(OPEN_DEVTOOLS, (event: IpcMainEvent) => {
event.sender.openDevTools() event.sender.openDevTools()
}) })

View File

@ -47,6 +47,7 @@ import {
SET_CURRENT_LANGUAGE, SET_CURRENT_LANGUAGE,
GET_CURRENT_LANGUAGE GET_CURRENT_LANGUAGE
} from '#/events/constants' } from '#/events/constants'
import { configPaths } from '~/universal/utils/configPaths'
// eslint-disable-next-line // eslint-disable-next-line
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
@ -360,8 +361,8 @@ const handlePicGoGalleryDB = () => {
}) })
ipcMain.handle(PASTE_TEXT, async (_, item: ImgInfo, copy = true) => { ipcMain.handle(PASTE_TEXT, async (_, item: ImgInfo, copy = true) => {
const pasteStyle = picgo.getConfig<IPasteStyle>('settings.pasteStyle') || IPasteStyle.MARKDOWN const pasteStyle = picgo.getConfig<IPasteStyle>(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const customLink = picgo.getConfig<string>('settings.customLink') const customLink = picgo.getConfig<string>(configPaths.settings.customLink)
const txt = await pasteTemplate(pasteStyle, item, customLink) const txt = await pasteTemplate(pasteStyle, item, customLink)
if (copy) { if (copy) {
clipboard.writeText(txt) clipboard.writeText(txt)

View File

@ -30,6 +30,7 @@ import {
} from '~/universal/events/constants' } from '~/universal/events/constants'
import { PicGo as PicGoCore } from 'piclist' import { PicGo as PicGoCore } from 'piclist'
import { T } from '~/main/i18n' import { T } from '~/main/i18n'
import { configPaths } from '~/universal/utils/configPaths'
interface GuiMenuItem { interface GuiMenuItem {
label: string label: string
@ -37,7 +38,7 @@ interface GuiMenuItem {
} }
const buildMiniPageMenu = () => { const buildMiniPageMenu = () => {
const isListeningClipboard = db.get('settings.isListeningClipboard') || false const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const ClipboardWatcher = clipboardPoll const ClipboardWatcher = clipboardPoll
const submenu = buildPicBedListMenu() const submenu = buildPicBedListMenu()
const template = [ const template = [
@ -45,7 +46,7 @@ const buildMiniPageMenu = () => {
label: T('OPEN_MAIN_WINDOW'), label: T('OPEN_MAIN_WINDOW'),
click () { click () {
windowManager.get(IWindowList.SETTING_WINDOW)!.show() windowManager.get(IWindowList.SETTING_WINDOW)!.show()
const autoCloseMiniWindow = db.get('settings.autoCloseMiniWindow') || false const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
if (autoCloseMiniWindow) { if (autoCloseMiniWindow) {
if (windowManager.has(IWindowList.MINI_WINDOW)) { if (windowManager.has(IWindowList.MINI_WINDOW)) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide() windowManager.get(IWindowList.MINI_WINDOW)!.hide()
@ -73,7 +74,7 @@ const buildMiniPageMenu = () => {
{ {
label: T('START_WATCH_CLIPBOARD'), label: T('START_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', true) db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening() ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => { ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed') picgo.log.info('clipboard changed')
@ -86,7 +87,7 @@ const buildMiniPageMenu = () => {
{ {
label: T('STOP_WATCH_CLIPBOARD'), label: T('STOP_WATCH_CLIPBOARD'),
click () { click () {
db.set('settings.isListeningClipboard', false) db.set(configPaths.settings.isListeningClipboard, false)
ClipboardWatcher.stopListening() ClipboardWatcher.stopListening()
ClipboardWatcher.removeAllListeners() ClipboardWatcher.removeAllListeners()
buildMiniPageMenu() buildMiniPageMenu()
@ -147,7 +148,7 @@ const buildMainPageMenu = (win: BrowserWindow) => {
const buildPicBedListMenu = () => { const buildPicBedListMenu = () => {
const picBeds = getPicBeds() const picBeds = getPicBeds()
const currentPicBed = picgo.getConfig('picBed.uploader') const currentPicBed = picgo.getConfig(configPaths.picBed.uploader)
const currentPicBedName = picBeds.find(item => item.type === currentPicBed)?.name const currentPicBedName = picBeds.find(item => item.type === currentPicBed)?.name
const picBedConfigList = picgo.getConfig<IUploaderConfig>('uploader') const picBedConfigList = picgo.getConfig<IUploaderConfig>('uploader')
const currentPicBedMenuItem = [{ const currentPicBedMenuItem = [{
@ -184,8 +185,8 @@ const buildPicBedListMenu = () => {
click: !hasSubmenu click: !hasSubmenu
? function () { ? function () {
picgo.saveConfig({ picgo.saveConfig({
'picBed.current': item.type, [configPaths.picBed.current]: item.type,
'picBed.uploader': item.type [configPaths.picBed.uploader]: item.type
}) })
if (windowManager.has(IWindowList.SETTING_WINDOW)) { if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed')
@ -204,19 +205,19 @@ const buildPicBedListMenu = () => {
const handleRestoreState = (item: string, name: string): void => { const handleRestoreState = (item: string, name: string): void => {
if (item === 'uploader') { if (item === 'uploader') {
const current = picgo.getConfig('picBed.current') const current = picgo.getConfig(configPaths.picBed.current)
if (current === name) { if (current === name) {
picgo.saveConfig({ picgo.saveConfig({
'picBed.current': 'smms', [configPaths.picBed.current]: 'smms',
'picBed.uploader': 'smms' [configPaths.picBed.uploader]: 'smms'
}) })
} }
} }
if (item === 'transformer') { if (item === 'transformer') {
const current = picgo.getConfig('picBed.transformer') const current = picgo.getConfig(configPaths.picBed.transformer)
if (current === name) { if (current === name) {
picgo.saveConfig({ picgo.saveConfig({
'picBed.transformer': 'path' [configPaths.picBed.transformer]: 'path'
}) })
} }
} }
@ -286,20 +287,20 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
// handle transformer // handle transformer
if (plugin.config.transformer.name) { if (plugin.config.transformer.name) {
const currentTransformer = picgo.getConfig<string>('picBed.transformer') || 'path' const currentTransformer = picgo.getConfig<string>(configPaths.picBed.transformer) || 'path'
const pluginTransformer = plugin.config.transformer.name const pluginTransformer = plugin.config.transformer.name
const obj = { const obj = {
label: `${currentTransformer === pluginTransformer ? T('DISABLE') : T('ENABLE')}transformer - ${plugin.config.transformer.name}`, label: `${currentTransformer === pluginTransformer ? T('DISABLE') : T('ENABLE')}transformer - ${plugin.config.transformer.name}`,
click () { click () {
const transformer = plugin.config.transformer.name const transformer = plugin.config.transformer.name
const currentTransformer = picgo.getConfig<string>('picBed.transformer') || 'path' const currentTransformer = picgo.getConfig<string>(configPaths.picBed.transformer) || 'path'
if (currentTransformer === transformer) { if (currentTransformer === transformer) {
picgo.saveConfig({ picgo.saveConfig({
'picBed.transformer': 'path' [configPaths.picBed.transformer]: 'path'
}) })
} else { } else {
picgo.saveConfig({ picgo.saveConfig({
'picBed.transformer': transformer [configPaths.picBed.transformer]: transformer
}) })
} }
} }

View File

@ -14,7 +14,7 @@ import {
import beforeOpen from '~/main/utils/beforeOpen' import beforeOpen from '~/main/utils/beforeOpen'
import ipcList from '~/main/events/ipcList' import ipcList from '~/main/events/ipcList'
import busEventList from '~/main/events/busEventList' import busEventList from '~/main/events/busEventList'
import { IRemoteNoticeTriggerHook, IWindowList } from '#/types/enum' import { II18nLanguage, IRemoteNoticeTriggerHook, ISartMode, IWindowList } from '#/types/enum'
import windowManager from 'apis/app/window/windowManager' import windowManager from 'apis/app/window/windowManager'
import { import {
uploadChoosedFiles, uploadChoosedFiles,
@ -45,7 +45,9 @@ import path from 'path'
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static' import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
import fs from 'fs-extra' import fs from 'fs-extra'
import { startFileServer } from '../fileServer' import { startFileServer } from '../fileServer'
import webServer from '../server/webServer'
import axios from 'axios' import axios from 'axios'
import { configPaths } from '~/universal/utils/configPaths'
const isDevelopment = process.env.NODE_ENV !== 'production' const isDevelopment = process.env.NODE_ENV !== 'production'
const handleStartUpFiles = (argv: string[], cwd: string) => { const handleStartUpFiles = (argv: string[], cwd: string) => {
@ -73,10 +75,10 @@ autoUpdater.setFeedURL({
autoUpdater.autoDownload = false autoUpdater.autoDownload = false
autoUpdater.on('update-available', async (info: UpdateInfo) => { autoUpdater.on('update-available', async (info: UpdateInfo) => {
const lang = db.get('settings.language') || 'zh-CN' const lang = db.get(configPaths.settings.language) || II18nLanguage.ZH_CN
let updateLog = '' let updateLog = ''
try { try {
const url = lang === 'zh-CN' ? 'https://release.piclist.cn/currentVersion.md' : 'https://release.piclist.cn/currentVersion_en.md' const url = lang === II18nLanguage.ZH_CN ? 'https://release.piclist.cn/currentVersion.md' : 'https://release.piclist.cn/currentVersion_en.md'
const res = await axios.get(url) const res = await axios.get(url)
updateLog = res.data updateLog = res.data
} catch (e: any) { } catch (e: any) {
@ -97,7 +99,7 @@ autoUpdater.on('update-available', async (info: UpdateInfo) => {
} else { } else {
shell.openExternal('https://github.com/Kuingsmile/PicList/releases/latest') shell.openExternal('https://github.com/Kuingsmile/PicList/releases/latest')
} }
db.set('settings.showUpdateTip', !result.checkboxChecked) db.set(configPaths.settings.showUpdateTip, !result.checkboxChecked)
}).catch((err) => { }).catch((err) => {
logger.error(err) logger.error(err)
}) })
@ -151,27 +153,27 @@ class LifeCycle {
createProtocol('picgo') createProtocol('picgo')
windowManager.create(IWindowList.TRAY_WINDOW) windowManager.create(IWindowList.TRAY_WINDOW)
windowManager.create(IWindowList.SETTING_WINDOW) windowManager.create(IWindowList.SETTING_WINDOW)
const isAutoListenClipboard = db.get('settings.isAutoListenClipboard') || false const isAutoListenClipboard = db.get(configPaths.settings.isAutoListenClipboard) || false
const ClipboardWatcher = clipboardPoll const ClipboardWatcher = clipboardPoll
if (isAutoListenClipboard) { if (isAutoListenClipboard) {
db.set('settings.isListeningClipboard', true) db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening() ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => { ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed') picgo.log.info('clipboard changed')
uploadClipboardFiles() uploadClipboardFiles()
}) })
} else { } else {
db.set('settings.isListeningClipboard', false) db.set(configPaths.settings.isListeningClipboard, false)
} }
const isHideDock = db.get('settings.isHideDock') || false const isHideDock = db.get(configPaths.settings.isHideDock) || false
const startMode = db.get('settings.startMode') || 'quiet' const startMode = db.get(configPaths.settings.startMode) || ISartMode.QUIET
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
isHideDock ? app.dock.hide() : setDockMenu() isHideDock ? app.dock.hide() : setDockMenu()
startMode !== 'no-tray' && createTray() startMode !== ISartMode.NO_TRAY && createTray()
} else { } else {
createTray() createTray()
} }
db.set('needReload', false) db.set(configPaths.needReload, false)
updateChecker() updateChecker()
// 不需要阻塞 // 不需要阻塞
process.nextTick(() => { process.nextTick(() => {
@ -179,6 +181,7 @@ class LifeCycle {
}) })
server.startup() server.startup()
startFileServer() startFileServer()
webServer.start()
if (process.env.NODE_ENV !== 'development') { if (process.env.NODE_ENV !== 'development') {
handleStartUpFiles(process.argv, process.cwd()) handleStartUpFiles(process.argv, process.cwd())
} }
@ -192,15 +195,15 @@ class LifeCycle {
} }
await remoteNoticeHandler.init() await remoteNoticeHandler.init()
remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.APP_START) remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.APP_START)
if (startMode === 'mini') { if (startMode === ISartMode.MINI) {
windowManager.create(IWindowList.MINI_WINDOW) windowManager.create(IWindowList.MINI_WINDOW)
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)! const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.removeAllListeners() miniWindow.removeAllListeners()
if (db.get('settings.miniWindowOntop')) { if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true) miniWindow.setAlwaysOnTop(true)
} }
const { width, height } = screen.getPrimaryDisplay().workAreaSize const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get('settings.miniWindowPosition') const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) { if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1]) miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else { } else {
@ -208,13 +211,13 @@ class LifeCycle {
} }
const setPositionFunc = () => { const setPositionFunc = () => {
const position = miniWindow.getPosition() const position = miniWindow.getPosition()
db.set('settings.miniWindowPosition', position) db.set(configPaths.settings.miniWindowPosition, position)
} }
miniWindow.on('close', setPositionFunc) miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc) miniWindow.on('move', setPositionFunc)
miniWindow.show() miniWindow.show()
miniWindow.focus() miniWindow.focus()
} else if (startMode === 'main') { } else if (startMode === ISartMode.MAIN) {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)! const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
settingWindow.show() settingWindow.show()
settingWindow.focus() settingWindow.focus()
@ -249,7 +252,7 @@ class LifeCycle {
} }
}) })
app.setLoginItemSettings({ app.setLoginItemSettings({
openAtLogin: db.get('settings.autoStart') || false openAtLogin: db.get(configPaths.settings.autoStart) || false
}) })
if (process.platform === 'win32') { if (process.platform === 'win32') {
app.setAppUserModelId('com.kuingsmile.piclist') app.setAppUserModelId('com.kuingsmile.piclist')

View File

@ -7,6 +7,7 @@ import { ILogType } from '#/types/enum'
import { ILogColor, ILogger } from 'piclist/dist/types' import { ILogColor, ILogger } from 'piclist/dist/types'
import { ManageApiType, Undefinable } from '~/universal/types/manage' import { ManageApiType, Undefinable } from '~/universal/types/manage'
import { enforceNumber, isDev } from '#/utils/common' import { enforceNumber, isDev } from '#/utils/common'
import { configPaths } from '~/universal/utils/configPaths'
export class ManageLogger implements ILogger { export class ManageLogger implements ILogger {
private readonly level = { private readonly level = {
@ -29,9 +30,9 @@ export class ManageLogger implements ILogger {
`[PicList ${type.toUpperCase()}]` `[PicList ${type.toUpperCase()}]`
) )
console.log(logHeader, ...msg) console.log(logHeader, ...msg)
this.logLevel = this.ctx.getConfig('settings.logLevel') this.logLevel = this.ctx.getConfig(configPaths.settings.logLevel)
this.logPath = this.logPath =
this.ctx.getConfig<Undefinable<string>>('settings.logPath') || this.ctx.getConfig<Undefinable<string>>(configPaths.settings.logPath) ||
path.join(this.ctx.baseDir, './manage.log') path.join(this.ctx.baseDir, './manage.log')
setTimeout(() => { setTimeout(() => {
try { try {
@ -61,7 +62,7 @@ export class ManageLogger implements ILogger {
const logFileSizeLimit = const logFileSizeLimit =
enforceNumber( enforceNumber(
this.ctx.getConfig<Undefinable<number>>( this.ctx.getConfig<Undefinable<number>>(
'settings.logFileSizeLimit' configPaths.settings.logFileSizeLimit
) || 10 ) || 10
) * ) *
1024 * 1024 *

79
src/main/server/apiDoc.ts Normal file
View File

@ -0,0 +1,79 @@
export const markdownContent = `
## Server的使用
PicList内置了一个小型的服务器HTTP请求来上传图片
\`0.0.0.0\`,默认监听端口:\`36677\`
###
PicList提供了接口鉴权功能
![202310102349225](https://assets.piclist.cn/image/202310102349225.webp)
URL查询参数\`key\`即可,例如:\`http://xxx:36677/upload?key=xxx\`
###
- : \`POST\`
- url: \`http://127.0.0.1:36677/upload\` (此处以默认配置为例)
- body: \`multipart/form-data\`格式key任选value为图片文件
### HTTP调用上传剪贴板图片
- : \`POST\`
- url: \`http://127.0.0.1:36677/upload\` (此处以默认配置为例)
- body: \`{list: ['xxx.jpg']}\` 必须是JSON格式
### configName和picbed参数
PicList支持通过设置\`picbed\`\`configName\`两个URL查询参数来指定上传图床和配置文件。例如
\`http://127.0.0.1:36677/upload?picbed=aws-s3&configName=piclist-test\`
使\`aws-s3\`图床,并且使用\`piclist-test\`配置文件。
\`\`\`json
{
"success": true, // or false
"result": ["url"]
}
\`\`\`
### HTTP调用上传具体路径图片
- method: \`POST\`
- url: \`http://127.0.0.1:36677/upload\` (此处以默认配置为例)
- request body: \`{list: ['xxx.jpg']}\` 必须是JSON格式
\`\`\`json
{
"success": true, // or false
"result": ["url"]
}
\`\`\`
### HTTP调用删除图片
- method: \`POST\`
- url: \`http://127.0.0.1:36677/delete\` (此处以默认配置为例)
- request body: \`{list: [{xx:xx}]}\` 必须是JSON格式
list中的每一项都是一个对象\`fullResult\`字段组成。
\`\`\`json
{
"success": true, // or false
"message": xxx
}
\`\`\`
`

View File

@ -11,7 +11,10 @@ import multer from 'multer'
import { app } from 'electron' import { app } from 'electron'
import path from 'path' import path from 'path'
import fs from 'fs-extra' import fs from 'fs-extra'
import { configPaths } from '~/universal/utils/configPaths'
const DEFAULT_PORT = 36677
const DEFAULT_HOST = '0.0.0.0'
const appPath = app.getPath('userData') const appPath = app.getPath('userData')
const serverTempDir = path.join(appPath, 'serverTemp') const serverTempDir = path.join(appPath, 'serverTemp')
@ -42,43 +45,46 @@ class Server {
private config: IServerConfig private config: IServerConfig
constructor () { constructor () {
let config = picgo.getConfig<IServerConfig>('settings.server') this.config = this.getConfigWithDefaults()
const result = this.checkIfConfigIsValid(config)
if (result) {
this.config = config
if (this.config.host === '127.0.0.1') {
this.config.host = '0.0.0.0'
}
} else {
config = {
port: 36677,
host: '0.0.0.0',
enable: true
}
this.config = config
picgo.saveConfig({
'settings.server': config
})
}
this.httpServer = http.createServer(this.handleRequest) this.httpServer = http.createServer(this.handleRequest)
} }
private checkIfConfigIsValid (config: IObj | undefined) { getConfigWithDefaults () {
let config = picgo.getConfig<IServerConfig>(configPaths.settings.server)
if (!this.isValidConfig(config)) {
config = { port: DEFAULT_PORT, host: DEFAULT_HOST, enable: true }
picgo.saveConfig({ [configPaths.settings.server]: config })
}
config.host = config.host === '127.0.0.1' ? '0.0.0.0' : config.host
return config
}
private isValidConfig (config: IObj | undefined) {
return config && config.port && config.host && (config.enable !== undefined) return config && config.port && config.host && (config.enable !== undefined)
} }
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => { private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
if (request.method === 'OPTIONS') { switch (request.method) {
handleResponse({ case 'OPTIONS':
response handleResponse({ response })
}) break
return case 'POST':
this.handlePostRequest(request, response)
break
case 'GET':
this.handleGetRequest(request, response)
break
default:
logger.warn(`[PicList Server] don't support [${request.method}] method`)
response.statusCode = 405
response.end()
}
} }
if (request.method === 'POST') { private handlePostRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
const [url, query] = request.url!.split('?') const [url, query] = (request.url || '').split('?')
if (!routers.getHandler(url!)) { if (!routers.getHandler(url, 'POST')) {
logger.warn(`[PicList Server] don't support [${url}] url`) logger.warn(`[PicList Server] don't support [${url}] endpoint`)
handleResponse({ handleResponse({
response, response,
statusCode: 404, statusCode: 404,
@ -87,6 +93,17 @@ class Server {
} }
}) })
} else { } else {
const remoteAddress = request.socket.remoteAddress || 'unknown'
logger.info('[PicList Server] get a POST request from IP:', remoteAddress)
let urlSP = query ? new URLSearchParams(query) : undefined
if (remoteAddress === '::1' || remoteAddress === '127.0.0.1') {
const serverKey = picgo.getConfig<string>(configPaths.settings.serverKey) || ''
if (urlSP) {
urlSP.set('key', serverKey)
} else {
urlSP = new URLSearchParams('key=' + serverKey)
}
}
if (request.headers['content-type'] && request.headers['content-type'].startsWith('multipart/form-data')) { if (request.headers['content-type'] && request.headers['content-type'].startsWith('multipart/form-data')) {
// @ts-ignore // @ts-ignore
uploadMulter.any()(request, response, (err: any) => { uploadMulter.any()(request, response, (err: any) => {
@ -103,12 +120,12 @@ class Server {
// @ts-ignore // @ts-ignore
const list = request.files.map(file => file.path) const list = request.files.map(file => file.path)
logger.info('[PicList Server] get a formData request') logger.info('[PicList Server] get a formData request')
const handler = routers.getHandler(url)?.handler const handler = routers.getHandler(url!, 'POST')?.handler
if (handler) { if (handler) {
handler({ handler({
list, list,
response, response,
urlparams: query ? new URLSearchParams(query) : undefined urlparams: urlSP
}) })
} }
}) })
@ -132,19 +149,31 @@ class Server {
}) })
} }
logger.info('[PicList Server] get the request', body) logger.info('[PicList Server] get the request', body)
const handler = routers.getHandler(url!)?.handler const handler = routers.getHandler(url!, 'POST')?.handler
handler!({ handler!({
...postObj, ...postObj,
response, response,
urlparams: query ? new URLSearchParams(query) : undefined urlparams: urlSP
}) })
}) })
} }
} }
} else { }
logger.warn(`[PicList Server] don't support [${request.method}] method`)
private handleGetRequest = (_request: http.IncomingMessage, response: http.ServerResponse) => {
const [url, query] = (_request.url || '').split('?')
if (!routers.getHandler(url, 'GET')) {
logger.info(`[PicList Server] don't support [${url}] endpoint`)
response.statusCode = 404 response.statusCode = 404
response.end() response.end()
} else {
const handler = routers.getHandler(url, 'GET')?.handler
if (handler) {
handler({
response,
urlparams: query ? new URLSearchParams(query) : undefined
})
}
} }
} }
@ -155,10 +184,11 @@ class Server {
port = parseInt(port, 10) port = parseInt(port, 10)
} }
this.httpServer.listen(port, this.config.host).on('error', async (err: ErrnoException) => { this.httpServer.listen(port, this.config.host).on('error', async (err: ErrnoException) => {
if (err.errno === 'EADDRINUSE') { if (err.code === 'EADDRINUSE') {
try { try {
// make sure the system has a PicGo Server instance // make sure the system has a PicGo Server instance
await axios.post(ensureHTTPLink(`${this.config.host}:${port}/heartbeat`)) await axios.post(ensureHTTPLink(`${this.config.host}:${port}/heartbeat`))
logger.info(`[PicList Server] server is already running at ${port}`)
this.shutdown(true) this.shutdown(true)
} catch (e) { } catch (e) {
logger.warn(`[PicList Server] ${port} is busy, trying with port ${(port as number) + 1}`) logger.warn(`[PicList Server] ${port} is busy, trying with port ${(port as number) + 1}`)
@ -166,12 +196,13 @@ class Server {
// to solve the auto number problem // to solve the auto number problem
this.listen((port as number) + 1) this.listen((port as number) + 1)
} }
} else {
logger.error('[PicList Server]', err)
} }
}) })
} }
startup () { startup () {
console.log('startup', this.config.enable)
if (this.config.enable) { if (this.config.enable) {
this.listen(this.config.port) this.listen(this.config.port)
} }
@ -185,11 +216,8 @@ class Server {
} }
restart () { restart () {
this.config = picgo.getConfig('settings.server')
if (this.config.host === '127.0.0.1') {
this.config.host = '0.0.0.0'
}
this.shutdown() this.shutdown()
this.config = this.getConfigWithDefaults()
this.startup() this.startup()
} }
} }

View File

@ -1,20 +1,36 @@
type HttpMethod = 'GET' | 'POST'
class Router { class Router {
private router = new Map<string, {handler: routeHandler, urlparams?: URLSearchParams}>() private router = new Map<string, Map<HttpMethod, {handler: routeHandler, urlparams?: URLSearchParams}>>()
private addRoute (method: HttpMethod, url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
if (!this.router.has(url)) {
this.router.set(url, new Map())
}
this.router.get(url)!.set(method, { handler: callback, urlparams })
}
get (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { get (url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
this.router.set(url, { handler: callback, urlparams }) this.addRoute('GET', url, callback, urlparams)
} }
post (url: string, callback: routeHandler, urlparams?: URLSearchParams): void { post (url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
this.router.set(url, { handler: callback, urlparams }) this.addRoute('POST', url, callback, urlparams)
} }
getHandler (url: string) { any (url: string, callback: routeHandler, urlparams?: URLSearchParams): void {
if (this.router.has(url)) { this.addRoute('GET', url, callback, urlparams)
return this.router.get(url) this.addRoute('POST', url, callback, urlparams)
} else {
return null
} }
getHandler (url: string, method: HttpMethod) {
if (this.router.has(url)) {
const methods = this.router.get(url)!
if (methods.has(method)) {
return methods.get(method)
}
}
return null
} }
} }

View File

@ -12,6 +12,10 @@ import { changeCurrentUploader } from '../utils/handleUploaderConfig'
import { app } from 'electron' import { app } from 'electron'
import fs from 'fs-extra' import fs from 'fs-extra'
import { AESHelper } from '../utils/aesHelper' import { AESHelper } from '../utils/aesHelper'
import { marked } from 'marked'
import { markdownContent } from './apiDoc'
import http from 'http'
import { configPaths } from '~/universal/utils/configPaths'
const appPath = app.getPath('userData') const appPath = app.getPath('userData')
const serverTempDir = path.join(appPath, 'serverTemp') const serverTempDir = path.join(appPath, 'serverTemp')
@ -22,6 +26,16 @@ const LOG_PATH = path.join(STORE_PATH, 'piclist.log')
const errorMessage = `upload error. see ${LOG_PATH} for more detail.` const errorMessage = `upload error. see ${LOG_PATH} for more detail.`
const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.` const deleteErrorMessage = `delete error. see ${LOG_PATH} for more detail.`
async function responseForGet ({ response } : {response: http.ServerResponse}) {
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
const htmlContent = marked(markdownContent)
response.write(htmlContent)
response.end()
}
router.get('/', responseForGet)
router.get('/upload', responseForGet)
router.post('/upload', async ({ router.post('/upload', async ({
response, response,
list = [], list = [],
@ -32,19 +46,19 @@ router.post('/upload', async ({
urlparams?: URLSearchParams urlparams?: URLSearchParams
}): Promise<void> => { }): Promise<void> => {
try { try {
const picbed = urlparams?.get('picbed')
const passedKey = urlparams?.get('key') const passedKey = urlparams?.get('key')
const serverKey = picgo.getConfig('settings.serverKey') || '' const serverKey = picgo.getConfig<string>(configPaths.settings.serverKey) || ''
if (serverKey && passedKey !== serverKey) { if (serverKey && passedKey !== serverKey) {
handleResponse({ handleResponse({
response, response,
body: { body: {
success: false, success: false,
message: 'server key is not correct' message: 'server key is uncorrect'
} }
}) })
return return
} }
const picbed = urlparams?.get('picbed')
let currentPicBedType = '' let currentPicBedType = ''
let currentPicBedConfig = {} as IStringKeyMap let currentPicBedConfig = {} as IStringKeyMap
let currentPicBedConfigId = '' let currentPicBedConfigId = ''
@ -176,36 +190,21 @@ router.post('/delete', async ({
return return
} }
try { try {
// 区分是否是加密的数据如果不是直接传入list如果是解密后再传入
const treatList = list.map(item => { const treatList = list.map(item => {
if (item.isEncrypted) { if (!item.isEncrypted) return item
const aesHelper = new AESHelper() const aesHelper = new AESHelper()
const data = aesHelper.decrypt(item.EncryptedData) return JSON.parse(aesHelper.decrypt(item.EncryptedData))
return JSON.parse(data)
} else {
return item
}
}) })
const result = await deleteChoosedFiles(treatList) const result = await deleteChoosedFiles(treatList)
const successCount = result.filter(item => item).length const successCount = result.filter(item => item).length
const failCount = result.filter(item => !item).length const failCount = result.length - successCount
if (successCount) {
handleResponse({ handleResponse({
response, response,
body: { body: {
success: true, success: !!successCount,
message: `delete success: ${successCount}, fail: ${failCount}` message: successCount ? `delete success: ${successCount}, fail: ${failCount}` : deleteErrorMessage
} }
}) })
} else {
handleResponse({
response,
body: {
success: false,
message: deleteErrorMessage
}
})
}
} catch (err: any) { } catch (err: any) {
logger.error(err) logger.error(err)
handleResponse({ handleResponse({
@ -218,7 +217,7 @@ router.post('/delete', async ({
} }
}) })
router.post('/heartbeat', async ({ router.any('/heartbeat', async ({
response response
} : { } : {
response: IHttpResponse, response: IHttpResponse,

View File

@ -0,0 +1,109 @@
import http from 'http'
import fs from 'fs-extra'
import path from 'path'
import picgo from '@core/picgo'
import logger from '../../apis/core/picgo/logger'
import { encodeFilePath } from '~/universal/utils/common'
import { configPaths } from '~/universal/utils/configPaths'
const defaultPath = process.platform === 'win32' ? 'C:\\Users' : '/'
function generateDirectoryListingHtml (files: any[], requestPath: any) {
let html = '<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><h1>Directory Listing</h1><ul>'
files.forEach((file: string) => {
const filePath = path.join(requestPath, file)
html += `<li><a href="${encodeFilePath(filePath)}">${file}</a></li>`
})
html += '</ul></body></html>'
return html
}
function serveDirectory (res: http.ServerResponse, filePath: fs.PathLike, requestPath: any) {
fs.readdir(filePath, (err, files) => {
if (err) {
res.writeHead(500)
res.end('Error listing directory contents')
} else {
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(generateDirectoryListingHtml(files, requestPath))
}
})
}
function serveFile (res:http.ServerResponse, filePath: fs.PathLike) {
const readStream = fs.createReadStream(filePath)
readStream.pipe(res)
readStream.on('error', () => {
res.writeHead(500)
res.end('Error reading file')
})
}
class WebServer {
private server!: http.Server
private config!: IStringKeyMap
constructor () {
this.loadConfig()
this.initServer()
}
loadConfig (): void {
this.config = {
enableWebServer: picgo.getConfig<boolean>(configPaths.settings.enableWebServer) || false,
webServerHost: picgo.getConfig<string>(configPaths.settings.webServerHost) || '0.0.0.0',
webServerPort: picgo.getConfig<number>(configPaths.settings.webServerPort) || 37777,
webServerPath: picgo.getConfig<string>(configPaths.settings.webServerPath) || defaultPath
}
}
initServer (): void {
this.server = http.createServer((req, res) => {
const requestPath = req.url?.split('?')[0]
const filePath = path.join(this.config.webServerPath, decodeURIComponent(requestPath || ''))
try {
const stats = fs.statSync(filePath)
if (stats.isDirectory()) {
serveDirectory(res, filePath, requestPath)
} else {
serveFile(res, filePath)
}
} catch (err) {
res.writeHead(404)
res.end('404 Not Found')
}
})
}
start () {
if (this.config.enableWebServer) {
this.server
.listen(
this.config.webServerPort === 36699 ? 37777 : this.config.webServerPort,
this.config.webServerHost, () => {
logger.info(`Web server is running at http://${this.config.webServerHost}:${this.config.webServerPort}, root path is ${this.config.webServerPath}`)
})
.on('error', (err) => {
logger.error(err)
})
} else {
logger.info('Web server is not enabled')
}
}
stop () {
this.server.close(() => {
logger.info('Web server is stopped')
})
}
restart () {
this.stop()
this.loadConfig()
this.initServer()
this.start()
}
}
export default new WebServer()

View File

@ -1,8 +1,10 @@
import crypto from 'crypto' import crypto from 'crypto'
import picgo from '@core/picgo' import picgo from '@core/picgo'
import { DEFAULT_AES_PASSWORD } from '~/universal/utils/static'
import { configPaths } from '~/universal/utils/configPaths'
function getDerivedKey (): Buffer { function getDerivedKey (): Buffer {
const userPassword = picgo.getConfig<string>('settings.aesPassword') || 'PicList-aesPassword' const userPassword = picgo.getConfig<string>(configPaths.settings.aesPassword) || DEFAULT_AES_PASSWORD
const fixedSalt = Buffer.from('a8b3c4d2e4f5098712345678feedc0de', 'hex') const fixedSalt = Buffer.from('a8b3c4d2e4f5098712345678feedc0de', 'hex')
const fixedIterations = 100000 const fixedIterations = 100000
const keyLength = 32 const keyLength = 32

View File

@ -5,9 +5,11 @@ import { handleUrlEncode } from '~/universal/utils/common'
import axios from 'axios' import axios from 'axios'
import FormData from 'form-data' import FormData from 'form-data'
import logger from '../apis/core/picgo/logger' import logger from '../apis/core/picgo/logger'
import { configPaths } from '~/universal/utils/configPaths'
import { IShortUrlServer } from '~/universal/types/enum'
export const handleCopyUrl = (str: string): void => { export const handleCopyUrl = (str: string): void => {
if (db.get('settings.autoCopy') !== false) { if (db.get(configPaths.settings.autoCopy) !== false) {
clipboard.writeText(str) clipboard.writeText(str)
} }
} }
@ -122,16 +124,16 @@ export const getClipboardFilePath = (): string => {
return '' return ''
} }
export const handleUrlEncodeWithSetting = (url: string) => db.get('settings.encodeOutputURL') ? handleUrlEncode(url) : url export const handleUrlEncodeWithSetting = (url: string) => db.get(configPaths.settings.encodeOutputURL) ? handleUrlEncode(url) : url
const c1nApi = 'https://c1n.cn/link/short' const c1nApi = 'https://c1n.cn/link/short'
export const generateShortUrl = async (url: string) => { export const generateShortUrl = async (url: string) => {
const server = db.get('settings.shortUrlServer') || 'c1n' const server = db.get(configPaths.settings.shortUrlServer) || IShortUrlServer.C1N
if (server === 'c1n') { if (server === IShortUrlServer.C1N) {
const form = new FormData() const form = new FormData()
form.append('url', url) form.append('url', url)
const c1nToken = db.get('settings.c1nToken') || '' const c1nToken = db.get(configPaths.settings.c1nToken) || ''
if (!c1nToken) { if (!c1nToken) {
logger.warn('c1n token is not set') logger.warn('c1n token is not set')
return url return url
@ -148,9 +150,9 @@ export const generateShortUrl = async (url: string) => {
} catch (e: any) { } catch (e: any) {
logger.error(e) logger.error(e)
} }
} else if (server === 'yourls') { } else if (server === IShortUrlServer.YOURLS) {
let domain = db.get('settings.yourlsDomain') || '' let domain = db.get(configPaths.settings.yourlsDomain) || ''
const signature = db.get('settings.yourlsSignature') || '' const signature = db.get(configPaths.settings.yourlsSignature) || ''
if (domain && signature) { if (domain && signature) {
if (!/^https?:\/\//.test(domain)) { if (!/^https?:\/\//.test(domain)) {
domain = `http://${domain}` domain = `http://${domain}`
@ -169,8 +171,8 @@ export const generateShortUrl = async (url: string) => {
} else { } else {
logger.warn('Yourls server or signature is not set') logger.warn('Yourls server or signature is not set')
} }
} else if (server === 'cf_worker') { } else if (server === IShortUrlServer.CFWORKER) {
let cfWorkerHost = db.get('settings.cfWorkerHost') || '' let cfWorkerHost = db.get(configPaths.settings.cfWorkerHost) || ''
cfWorkerHost = cfWorkerHost.replace(/\/$/, '') cfWorkerHost = cfWorkerHost.replace(/\/$/, '')
if (cfWorkerHost) { if (cfWorkerHost) {
try { try {

View File

@ -12,8 +12,8 @@ interface DogecloudTokenFull {
accessKeyId: string accessKeyId: string
secretAccessKey: string secretAccessKey: string
sessionToken: string sessionToken: string
}, }
ExpiredAt: number, ExpiredAt: number
Buckets: { Buckets: {
name: string name: string
s3Bucket: string s3Bucket: string

View File

@ -1,8 +1,9 @@
import picgo from '@core/picgo' import picgo from '@core/picgo'
import { configPaths } from '~/universal/utils/configPaths'
const getPicBeds = () => { const getPicBeds = () => {
const picBedTypes = picgo.helper.uploader.getIdList() const picBedTypes = picgo.helper.uploader.getIdList()
const picBedFromDB = picgo.getConfig<IPicBedType[]>('picBed.list') || [] const picBedFromDB = picgo.getConfig<IPicBedType[]>(configPaths.picBed.list) || []
const picBeds = picBedTypes.map((item: string) => { const picBeds = picBedTypes.map((item: string) => {
const visible = picBedFromDB.find((i: IPicBedType) => i.type === item) // object or undefined const visible = picBedFromDB.find((i: IPicBedType) => i.type === item) // object or undefined
return { return {

View File

@ -1,6 +1,9 @@
import db from '~/main/apis/core/datastore' import db from '~/main/apis/core/datastore'
import { i18nManager } from '~/main/i18n' import { i18nManager } from '~/main/i18n'
import { II18nLanguage } from '~/universal/types/enum'
import { configPaths } from '~/universal/utils/configPaths'
export const initI18n = () => { export const initI18n = () => {
const currentLanguage = db.get('settings.language') || 'zh-CN' const currentLanguage = db.get(configPaths.settings.language) || II18nLanguage.ZH_CN
i18nManager.setCurrentLanguage(currentLanguage) i18nManager.setCurrentLanguage(currentLanguage)
} }

View File

@ -1,6 +1,7 @@
import { v4 as uuid } from 'uuid' import { v4 as uuid } from 'uuid'
import { trimValues } from '#/utils/common' import { trimValues } from '#/utils/common'
import picgo from '@core/picgo' import picgo from '@core/picgo'
import { configPaths } from '~/universal/utils/configPaths'
export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IPicGoPluginConfig[] => { export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IPicGoPluginConfig[] => {
for (const i in config) { for (const i in config) {
@ -61,8 +62,8 @@ export const changeCurrentUploader = (type: string, config?: IStringKeyMap, id?:
}) })
} }
picgo.saveConfig({ picgo.saveConfig({
'picBed.current': type, [configPaths.picBed.current]: type,
'picBed.uploader': type [configPaths.picBed.uploader]: type
}) })
} }

View File

@ -2,6 +2,7 @@ import { IPasteStyle } from '#/types/enum'
import { generateShortUrl } from '~/main/utils/common' import { generateShortUrl } from '~/main/utils/common'
import db from '~/main/apis/core/datastore' import db from '~/main/apis/core/datastore'
import { handleUrlEncodeWithSetting } from './common' import { handleUrlEncodeWithSetting } from './common'
import { configPaths } from '~/universal/utils/configPaths'
export const formatCustomLink = (customLink: string, item: ImgInfo) => { export const formatCustomLink = (customLink: string, item: ImgInfo) => {
const fileName = item.fileName!.replace(new RegExp(`\\${item.extname}$`), '') const fileName = item.fileName!.replace(new RegExp(`\\${item.extname}$`), '')
@ -28,7 +29,7 @@ export default async (style: IPasteStyle, item: ImgInfo, customLink: string | un
url = item.imgUrl || item.url || '' url = item.imgUrl || item.url || ''
} }
url = handleUrlEncodeWithSetting(url) url = handleUrlEncodeWithSetting(url)
const useShortUrl = db.get('settings.useShortUrl') || false const useShortUrl = db.get(configPaths.settings.useShortUrl) || false
if (useShortUrl) { if (useShortUrl) {
url = await generateShortUrl(url) url = await generateShortUrl(url)
} }

View File

@ -6,18 +6,7 @@ import db from '~/main/apis/core/datastore'
import { HttpsProxyAgent } from 'hpagent' import { HttpsProxyAgent } from 'hpagent'
import { Octokit } from '@octokit/rest' import { Octokit } from '@octokit/rest'
import logger from 'apis/core/picgo/logger' import logger from 'apis/core/picgo/logger'
import { configPaths } from '~/universal/utils/configPaths'
interface SyncConfig {
type: string
file?: string
username: string
repo: string
branch: string
token: string
endpoint?: string
proxy?: string
interval?: number
}
const STORE_PATH = app.getPath('userData') const STORE_PATH = app.getPath('userData')
@ -28,7 +17,7 @@ const configFileNames = [
'manage.bak.json' 'manage.bak.json'
] ]
function getOctokit (syncConfig: SyncConfig) { function getOctokit (syncConfig: ISyncConfig) {
const { token, proxy } = syncConfig const { token, proxy } = syncConfig
return new Octokit({ return new Octokit({
auth: token, auth: token,
@ -47,7 +36,7 @@ function getOctokit (syncConfig: SyncConfig) {
} }
function getSyncConfig () { function getSyncConfig () {
return db.get('settings.sync') || { return db.get(configPaths.settings.sync) || {
type: 'github', type: 'github',
username: '', username: '',
repo: '', repo: '',
@ -57,12 +46,12 @@ function getSyncConfig () {
} }
} }
function syncConfigValidator (syncConfig: SyncConfig) { function syncConfigValidator (syncConfig: ISyncConfig) {
const { type, username, repo, branch, token } = syncConfig const { type, username, repo, branch, token } = syncConfig
return type && username && repo && branch && token return type && username && repo && branch && token
} }
async function uploadLocalToRemote (syncConfig: SyncConfig, fileName: string) { async function uploadLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
const localFilePath = path.join(STORE_PATH, fileName) const localFilePath = path.join(STORE_PATH, fileName)
if (!fs.existsSync(localFilePath)) { if (!fs.existsSync(localFilePath)) {
return false return false
@ -120,7 +109,7 @@ async function uploadLocalToRemote (syncConfig: SyncConfig, fileName: string) {
} }
} }
async function updateLocalToRemote (syncConfig: SyncConfig, fileName: string) { async function updateLocalToRemote (syncConfig: ISyncConfig, fileName: string) {
const localFilePath = path.join(STORE_PATH, fileName) const localFilePath = path.join(STORE_PATH, fileName)
if (!fs.existsSync(localFilePath)) { if (!fs.existsSync(localFilePath)) {
return false return false
@ -201,7 +190,7 @@ async function updateLocalToRemote (syncConfig: SyncConfig, fileName: string) {
} }
} }
async function downloadRemoteToLocal (syncConfig: SyncConfig, fileName: string) { async function downloadRemoteToLocal (syncConfig: ISyncConfig, fileName: string) {
const localFilePath = path.join(STORE_PATH, fileName) const localFilePath = path.join(STORE_PATH, fileName)
const { username, repo, branch, token, proxy, type } = syncConfig const { username, repo, branch, token, proxy, type } = syncConfig
if (type === 'gitee') { if (type === 'gitee') {
@ -304,7 +293,7 @@ async function uploadFile (fileName: string, all = false) {
} }
} }
async function uploadFunc (syncConfig: SyncConfig, fileName: string) { async function uploadFunc (syncConfig: ISyncConfig, fileName: string) {
let result = false let result = false
try { try {
result = await updateLocalToRemote(syncConfig, fileName) result = await updateLocalToRemote(syncConfig, fileName)
@ -342,7 +331,7 @@ async function downloadFile (fileName: string, all = false) {
} }
} }
async function downloadFunc (syncConfig: SyncConfig, fileName: string) { async function downloadFunc (syncConfig: ISyncConfig, fileName: string) {
const result = await downloadRemoteToLocal(syncConfig, fileName) const result = await downloadRemoteToLocal(syncConfig, fileName)
if (!result) { if (!result) {
logger.error(`download ${fileName} failed`) logger.error(`download ${fileName} failed`)

View File

@ -1,10 +1,11 @@
import db from '~/main/apis/core/datastore' import db from '~/main/apis/core/datastore'
import { autoUpdater } from 'electron-updater' import { autoUpdater } from 'electron-updater'
import { configPaths } from '~/universal/utils/configPaths'
const updateChecker = async () => { const updateChecker = async () => {
let showTip = db.get('settings.showUpdateTip') let showTip = db.get(configPaths.settings.showUpdateTip)
if (showTip === undefined) { if (showTip === undefined) {
db.set('settings.showUpdateTip', true) db.set(configPaths.settings.showUpdateTip, true)
showTip = true showTip = true
} }
if (showTip) { if (showTip) {

View File

@ -1,8 +1,18 @@
import axios from 'axios' import axios from 'axios'
import path from 'path' import path from 'path'
interface IConfigMap {
fileName: string
config: {
version: string
url: string
uploadPath: string
token: string
}
}
export default class AlistApi { export default class AlistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> { static async delete (configMap: IConfigMap): Promise<boolean> {
const { fileName, config } = configMap const { fileName, config } = configMap
try { try {
const { version, url, uploadPath, token } = config const { version, url, uploadPath, token } = config

View File

@ -2,13 +2,7 @@ import OSS from 'ali-oss'
interface IConfigMap { interface IConfigMap {
fileName: string fileName: string
config: { config: PartialKeys<IAliYunConfig, 'path'>
accessKeyId: string
accessKeySecret: string
bucket: string
area: string
path?: string
}
} }
export default class AliyunApi { export default class AliyunApi {

View File

@ -3,12 +3,7 @@ import { Octokit } from '@octokit/rest'
interface IConfigMap { interface IConfigMap {
fileName: string fileName: string
hash: string hash: string
config: { config: PartialKeys<IGitHubConfig, 'path'>
repo: string
token: string
branch: string
path?: string
}
} }
export default class GithubApi { export default class GithubApi {

View File

@ -1,11 +1,7 @@
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
interface IConfigMap { interface IConfigMap {
config?: { config?: Partial<IImgurConfig>
clientId?: string
username?: string
accessToken?: string
}
hash?: string hash?: string
} }

View File

@ -1,13 +1,8 @@
import Qiniu from 'qiniu' import Qiniu from 'qiniu'
interface IConfigMap { interface IConfigMap {
fileName: string; fileName: string
config: { config: PartialKeys<IQiniuConfig, 'path'>
accessKey: string;
secretKey: string;
bucket: string;
path?: string;
}
} }
export default class QiniuApi { export default class QiniuApi {

View File

@ -2,9 +2,7 @@ import axios, { AxiosResponse } from 'axios'
interface IConfigMap { interface IConfigMap {
hash?: string hash?: string
config?: { config?: Partial<ISMMSConfig>
token?: string
}
} }
export default class SmmsApi { export default class SmmsApi {

View File

@ -1,14 +1,8 @@
import COS from 'cos-nodejs-sdk-v5' import COS from 'cos-nodejs-sdk-v5'
interface IConfigMap { interface IConfigMap {
fileName: string; fileName: string
config: { config: PartialKeys<ITcYunConfig, 'path'>
secretId: string;
secretKey: string;
bucket: string;
area: string;
path?: string;
};
} }
export default class TcyunApi { export default class TcyunApi {

View File

@ -1,7 +1,12 @@
import Upyun from 'upyun' import Upyun from 'upyun'
interface IConfigMap {
fileName: string
config: PartialKeys<IUpYunConfig, 'path'>
}
export default class UpyunApi { export default class UpyunApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> { static async delete (configMap: IConfigMap): Promise<boolean> {
const { fileName, config: { bucket, operator, password, path } } = configMap const { fileName, config: { bucket, operator, password, path } } = configMap
try { try {
const service = new Upyun.Service(bucket, operator, password) const service = new Upyun.Service(bucket, operator, password)

View File

@ -1,8 +1,13 @@
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'
interface IConfigMap {
fileName: string
config: PartialKeys<IWebdavPlistConfig, 'path'>
}
export default class WebdavApi { export default class WebdavApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> { static async delete (configMap: IConfigMap): Promise<boolean> {
const { fileName, config: { host, username, password, path, sslEnabled, authType } } = configMap const { fileName, config: { host, username, password, path, sslEnabled, authType } } = configMap
const endpoint = formatEndpoint(host, sslEnabled) const endpoint = formatEndpoint(host, sslEnabled)
const options: WebDAVClientOptions = { const options: WebDAVClientOptions = {

View File

@ -279,6 +279,8 @@ import {
// //
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender' import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
import { openURL } from '@/utils/common' import { openURL } from '@/utils/common'
import { configPaths, manualPageOpenType } from '~/universal/utils/configPaths'
import { II18nLanguage } from '~/universal/types/enum'
const version = ref(process.env.NODE_ENV === 'production' ? pkg.version : 'Dev') const version = ref(process.env.NODE_ENV === 'production' ? pkg.version : 'Dev')
const routerConfig = reactive(config) const routerConfig = reactive(config)
@ -326,10 +328,10 @@ const handleGetPicPeds = () => {
const handleSelect = async (index: string) => { const handleSelect = async (index: string) => {
defaultActive.value = index defaultActive.value = index
if (index === routerConfig.DocumentPage) { if (index === routerConfig.DocumentPage) {
const manualPageOpenSetting = await getConfig('settings.manualPageOpen') const manualPageOpenSetting = await getConfig<manualPageOpenType>(configPaths.settings.manualPageOpen)
const lang = await getConfig('settings.language') || 'zh-CN' const lang = await getConfig(configPaths.settings.language) || II18nLanguage.ZH_CN
const openManual = () => ipcRenderer.send('openManualWindow') const openManual = () => ipcRenderer.send('openManualWindow')
const openExternal = () => openURL(lang === 'zh-CN' ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html') const openExternal = () => openURL(lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html')
if (!manualPageOpenSetting) { if (!manualPageOpenSetting) {
ElMessageBox.confirm($T('MANUAL_PAGE_OPEN_TIP'), $T('MANUAL_PAGE_OPEN_TIP_TITLE'), { ElMessageBox.confirm($T('MANUAL_PAGE_OPEN_TIP'), $T('MANUAL_PAGE_OPEN_TIP_TITLE'), {
@ -338,10 +340,10 @@ const handleSelect = async (index: string) => {
type: 'info', type: 'info',
center: true center: true
}).then(() => { }).then(() => {
saveConfig('settings.manualPageOpen', 'browser') saveConfig(configPaths.settings.manualPageOpen, 'browser')
openExternal() openExternal()
}).catch(() => { }).catch(() => {
saveConfig('settings.manualPageOpen', 'window') saveConfig(configPaths.settings.manualPageOpen, 'window')
openManual() openManual()
}) })
} else { } else {

View File

@ -11,7 +11,7 @@ import Dexie, { Table } from 'dexie'
*/ */
export interface IFileCache { export interface IFileCache {
key: string, key: string
value: any value: any
} }

View File

@ -29,14 +29,25 @@ export function renameFileNameWithRandomString (oldName: string, length: number
return `${randomStringGenerator(length)}${path.extname(oldName)}` return `${randomStringGenerator(length)}${path.extname(oldName)}`
} }
function renameFormatHelper (num: number): string {
return num.toString().length === 1 ? `0${num}` : num.toString()
}
function getMd5 (input: crypto.BinaryLike): string {
return crypto.createHash('md5').update(input).digest('hex')
}
export function renameFileNameWithCustomString (oldName: string, customFormat: string, affixFileName?: string): string { export function renameFileNameWithCustomString (oldName: string, customFormat: string, affixFileName?: string): string {
const date = new Date()
const year = date.getFullYear().toString()
const fileBaseName = path.basename(oldName, path.extname(oldName))
const conversionMap : {[key: string]: () => string} = { const conversionMap : {[key: string]: () => string} = {
'{Y}': () => new Date().getFullYear().toString(), '{Y}': () => year,
'{y}': () => new Date().getFullYear().toString().slice(2), '{y}': () => year.slice(2),
'{m}': () => (new Date().getMonth() + 1).toString().length === 1 ? `0${new Date().getMonth() + 1}` : (new Date().getMonth() + 1).toString(), '{m}': () => renameFormatHelper(date.getMonth() + 1),
'{d}': () => new Date().getDate().toString().length === 1 ? `0${new Date().getDate()}` : new Date().getDate().toString(), '{d}': () => renameFormatHelper(date.getDate()),
'{md5}': () => crypto.createHash('md5').update(path.basename(oldName, path.extname(oldName))).digest('hex'), '{md5}': () => getMd5(fileBaseName),
'{md5-16}': () => crypto.createHash('md5').update(path.basename(oldName, path.extname(oldName))).digest('hex').slice(0, 16), '{md5-16}': () => getMd5(fileBaseName).slice(0, 16),
'{str-10}': () => randomStringGenerator(10), '{str-10}': () => randomStringGenerator(10),
'{str-20}': () => randomStringGenerator(20), '{str-20}': () => randomStringGenerator(20),
'{filename}': () => affixFileName ? path.basename(affixFileName, path.extname(affixFileName)) : path.basename(oldName, path.extname(oldName)), '{filename}': () => affixFileName ? path.basename(affixFileName, path.extname(affixFileName)) : path.basename(oldName, path.extname(oldName)),
@ -171,7 +182,7 @@ export const svg = `
export function customStrMatch (str: string, pattern: string) : boolean { export function customStrMatch (str: string, pattern: string) : boolean {
if (!str || !pattern) return false if (!str || !pattern) return false
try { try {
const reg = new RegExp(pattern, 'g') const reg = new RegExp(pattern, 'ug')
return reg.test(str) return reg.test(str)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
@ -184,7 +195,7 @@ export function customStrReplace (str: string, pattern: string, replacement: str
replacement = replacement || '' replacement = replacement || ''
let result = str let result = str
try { try {
const reg = new RegExp(pattern, 'g') const reg = new RegExp(pattern, 'ug')
result = str.replace(reg, replacement) result = str.replace(reg, replacement)
result = renameFileNameWithCustomString(result, result, str) result = renameFileNameWithCustomString(result, result, str)
} catch (e) { } catch (e) {

View File

@ -499,6 +499,8 @@ import ALLApi from '@/apis/allApi'
import { customRenameFormatTable, customStrMatch, customStrReplace } from '../manage/utils/common' import { customRenameFormatTable, customStrMatch, customStrReplace } from '../manage/utils/common'
import { picBedsCanbeDeleted } from '#/utils/static' import { picBedsCanbeDeleted } from '#/utils/static'
import path from 'path' import path from 'path'
import { configPaths } from '~/universal/utils/configPaths'
import { IPasteStyle } from '~/universal/types/enum'
const images = ref<ImgInfo[]>([]) const images = ref<ImgInfo[]>([])
const dialogVisible = ref(false) const dialogVisible = ref(false)
@ -731,7 +733,7 @@ function remove (item: ImgInfo) {
type: 'warning' type: 'warning'
}).then(async () => { }).then(async () => {
const file = await $$db.getById(item.id!) const file = await $$db.getById(item.id!)
if (await getConfig('settings.deleteCloudFile') && picBedsCanbeDeleted.includes(item?.type || 'placeholder')) { if (await getConfig(configPaths.settings.deleteCloudFile) && picBedsCanbeDeleted.includes(item?.type || 'placeholder')) {
const result = await ALLApi.delete(item) const result = await ALLApi.delete(item)
if (result) { if (result) {
ElNotification({ ElNotification({
@ -767,7 +769,7 @@ function remove (item: ImgInfo) {
function handleDeleteCloudFile (val: ICheckBoxValueType) { function handleDeleteCloudFile (val: ICheckBoxValueType) {
saveConfig({ saveConfig({
'settings.deleteCloudFile': val [configPaths.settings.deleteCloudFile]: val
}) })
} }
@ -825,7 +827,7 @@ function multiRemove () {
}).then(async () => { }).then(async () => {
const files: IResult<ImgInfo>[] = [] const files: IResult<ImgInfo>[] = []
const imageIDList = Object.keys(choosedList) const imageIDList = Object.keys(choosedList)
const isDeleteCloudFile = await getConfig('settings.deleteCloudFile') const isDeleteCloudFile = await getConfig(configPaths.settings.deleteCloudFile)
if (isDeleteCloudFile) { if (isDeleteCloudFile) {
for (let i = 0; i < imageIDList.length; i++) { for (let i = 0; i < imageIDList.length; i++) {
const key = imageIDList[i] const key = imageIDList[i]
@ -919,12 +921,12 @@ function toggleHandleBar () {
} }
async function handlePasteStyleChange (val: string) { async function handlePasteStyleChange (val: string) {
saveConfig('settings.pasteStyle', val) saveConfig(configPaths.settings.pasteStyle, val)
pasteStyle.value = val pasteStyle.value = val
} }
function handleUseShortUrlChange (value: string) { function handleUseShortUrlChange (value: string) {
saveConfig('settings.useShortUrl', value === $T('UPLOAD_SHORT_URL')) saveConfig(configPaths.settings.useShortUrl, value === $T('UPLOAD_SHORT_URL'))
useShortUrl.value = value useShortUrl.value = value
} }
@ -1046,8 +1048,8 @@ onBeforeUnmount(() => {
}) })
onActivated(async () => { onActivated(async () => {
pasteStyle.value = (await getConfig('settings.pasteStyle')) || 'markdown' pasteStyle.value = (await getConfig(configPaths.settings.pasteStyle)) || IPasteStyle.MARKDOWN
useShortUrl.value = (await getConfig('settings.useShortUrl') ? $T('UPLOAD_SHORT_URL') : $T('UPLOAD_NORMAL_URL')) useShortUrl.value = (await getConfig(configPaths.settings.useShortUrl) ? $T('UPLOAD_SHORT_URL') : $T('UPLOAD_NORMAL_URL'))
initDeleteCloud() initDeleteCloud()
}) })

View File

@ -654,6 +654,18 @@
{{ $T('SETTINGS_CLICK_TO_SET') }} {{ $T('SETTINGS_CLICK_TO_SET') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
<el-form-item
:label="$T('SETTINGS_SET_WEB_SERVER')"
>
<el-button
type="primary"
round
size="small"
@click="webServerVisible = true"
>
{{ $T('SETTINGS_CLICK_TO_SET') }}
</el-button>
</el-form-item>
<el-form-item <el-form-item
:label="$T('SETTINGS_SET_SERVER')" :label="$T('SETTINGS_SET_SERVER')"
> >
@ -732,6 +744,7 @@
:title="$T('SETTINGS_CUSTOM_LINK_FORMAT')" :title="$T('SETTINGS_CUSTOM_LINK_FORMAT')"
:modal-append-to-body="false" :modal-append-to-body="false"
center center
draggable
append-to-body append-to-body
> >
<el-form <el-form
@ -783,6 +796,7 @@
:modal-append-to-body="false" :modal-append-to-body="false"
width="70%" width="70%"
center center
draggable
append-to-body append-to-body
> >
<el-form <el-form
@ -840,6 +854,7 @@
:modal-append-to-body="false" :modal-append-to-body="false"
width="70%" width="70%"
center center
draggable
append-to-body append-to-body
> >
<el-form <el-form
@ -896,6 +911,7 @@
:title="$T('SETTINGS_CHECK_UPDATE')" :title="$T('SETTINGS_CHECK_UPDATE')"
:modal-append-to-body="false" :modal-append-to-body="false"
center center
draggable
append-to-body append-to-body
> >
<div> <div>
@ -1025,6 +1041,7 @@
:modal-append-to-body="false" :modal-append-to-body="false"
width="500px" width="500px"
center center
draggable
append-to-body append-to-body
> >
<el-form <el-form
@ -1122,6 +1139,7 @@
:title="$T('SETTINGS_SET_PICGO_SERVER')" :title="$T('SETTINGS_SET_PICGO_SERVER')"
:modal-append-to-body="false" :modal-append-to-body="false"
center center
draggable
append-to-body append-to-body
> >
<div class="notice-text"> <div class="notice-text">
@ -1187,6 +1205,69 @@
</el-button> </el-button>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog
v-model="webServerVisible"
class="server-dialog"
width="60%"
:title="$T('SETTINGS_SET_WEB_SERVER')"
:modal-append-to-body="false"
align-center
draggable
append-to-body
@close="confirmWebServerSetting"
>
<div class="notice-text">
{{ $T('SETTINGS_TIPS_WEB_SERVER_NOTICE') }}
</div>
<el-form
label-position="right"
label-width="180px"
>
<el-form-item
:label="$T('SETTINGS_SET_ENABLE_WEB_SERVER')"
>
<el-switch
v-model="form.enableWebServer"
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleEnableWebServerChange"
/>
</el-form-item>
<template v-if="form.enableWebServer">
<el-form-item
:label="$T('SETTINGS_SET_WEB_SERVER_HOST')"
>
<el-input
v-model="form.webServerHost"
type="input"
:placeholder="$T('SETTINGS_TIP_PLACEHOLDER_WEB_HOST')"
@change="handleWebServerHostChange"
/>
</el-form-item>
<el-form-item
:label="$T('SETTINGS_SET_WEB_SERVER_PORT')"
>
<el-input-number
v-model="form.webServerPort"
:min="1"
:max="65535"
:placeholder="$T('SETTINGS_TIP_PLACEHOLDER_WEB_PORT')"
@change="handleWebServerPortChange"
/>
</el-form-item>
<el-form-item
:label="$T('SETTINGS_SET_WEB_SERVER_PATH')"
>
<el-input
v-model="form.webServerPath"
type="input"
:placeholder="$T('SETTINGS_SET_WEB_SERVER_PATH')"
@change="handleWebServerPathChange"
/>
</el-form-item>
</template>
</el-form>
</el-dialog>
<el-dialog <el-dialog
v-model="syncVisible" v-model="syncVisible"
class="server-dialog" class="server-dialog"
@ -1194,6 +1275,7 @@
:title="$T('SETTINGS_SYNC_CONFIG_TITLE')" :title="$T('SETTINGS_SYNC_CONFIG_TITLE')"
:modal-append-to-body="false" :modal-append-to-body="false"
center center
draggable
append-to-body append-to-body
> >
<div class="notice-text"> <div class="notice-text">
@ -1300,6 +1382,7 @@
:title="$T('SETTINGS_UP_DOWN_DESC')" :title="$T('SETTINGS_UP_DOWN_DESC')"
:modal-append-to-body="false" :modal-append-to-body="false"
center center
draggable
append-to-body append-to-body
> >
<el-form <el-form
@ -1652,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 } from '~/universal/types/enum' import { IRPCActionType, ISartMode } from '~/universal/types/enum'
// Electron // Electron
import { import {
@ -1687,6 +1770,7 @@ import { invokeToMain } from '@/manage/utils/dataSender'
// //
import { buildInRenameFormatTable } from '../manage/utils/common' import { buildInRenameFormatTable } from '../manage/utils/common'
import { configPaths, ISartModeValues } from '~/universal/utils/configPaths'
const imageProcessDialogVisible = ref(false) const imageProcessDialogVisible = ref(false)
const activeName = ref<'system' | 'syncAndConfigure' | 'upload' | 'advanced' | 'upadte'>('system') const activeName = ref<'system' | 'syncAndConfigure' | 'upload' | 'advanced' | 'upadte'>('system')
@ -1780,14 +1864,14 @@ function handleSaveConfig () {
const formatConvertObjFilter = Object.fromEntries(formatConvertObjEntriesFilter) const formatConvertObjFilter = Object.fromEntries(formatConvertObjEntriesFilter)
formatConvertObj.value = JSON.stringify(formatConvertObjFilter) formatConvertObj.value = JSON.stringify(formatConvertObjFilter)
compressForm.formatConvertObj = formatConvertObjFilter compressForm.formatConvertObj = formatConvertObjFilter
saveConfig('buildIn.compress', toRaw(compressForm)) saveConfig(configPaths.buildIn.compress, toRaw(compressForm))
saveConfig('buildIn.watermark', toRaw(waterMarkForm)) saveConfig(configPaths.buildIn.watermark, toRaw(waterMarkForm))
closeDialog() closeDialog()
} }
async function initForm () { async function initForm () {
const compress = await getConfig<IBuildInCompressOptions>('buildIn.compress') const compress = await getConfig<IBuildInCompressOptions>(configPaths.buildIn.compress)
const watermark = await getConfig<IBuildInWaterMarkOptions>('buildIn.watermark') const watermark = await getConfig<IBuildInWaterMarkOptions>(configPaths.buildIn.watermark)
if (compress) { if (compress) {
compressForm.quality = compress.quality ?? 100 compressForm.quality = compress.quality ?? 100
compressForm.isConvert = compress.isConvert ?? false compressForm.isConvert = compress.isConvert ?? false
@ -1871,7 +1955,11 @@ const form = reactive<ISettingForm>({
deleteLocalFile: false, deleteLocalFile: false,
serverKey: '', serverKey: '',
aesPassword: '', aesPassword: '',
manualPageOpen: 'browser' manualPageOpen: 'browser',
enableWebServer: false,
webServerHost: '0.0.0.0',
webServerPort: 37777,
webServerPath: ''
}) })
const languageList = i18nManager.languageList.map(item => ({ const languageList = i18nManager.languageList.map(item => ({
@ -1888,6 +1976,7 @@ const logFileVisible = ref(false)
const customLinkVisible = ref(false) const customLinkVisible = ref(false)
const checkUpdateVisible = ref(false) const checkUpdateVisible = ref(false)
const serverVisible = ref(false) const serverVisible = ref(false)
const webServerVisible = ref(false)
const syncVisible = ref(false) const syncVisible = ref(false)
const upDownConfigVisible = ref(false) const upDownConfigVisible = ref(false)
const proxyVisible = ref(false) const proxyVisible = ref(false)
@ -1898,10 +1987,6 @@ const customLink = reactive({
value: '![$fileName]($url)' value: '![$fileName]($url)'
}) })
const shortKey = reactive<IShortKeyMap>({
upload: ''
})
const mainWindowWidth = ref(1200) const mainWindowWidth = ref(1200)
const mainWindowHeight = ref(800) const mainWindowHeight = ref(800)
const rawPicGoSize = ref(false) const rawPicGoSize = ref(false)
@ -1963,7 +2048,7 @@ const syncType = [
async function cancelSyncSetting () { async function cancelSyncSetting () {
syncVisible.value = false syncVisible.value = false
sync.value = await getConfig('settings.sync') || { sync.value = await getConfig(configPaths.settings.sync) || {
type: 'github', type: 'github',
username: '', username: '',
repo: '', repo: '',
@ -1977,7 +2062,7 @@ async function cancelSyncSetting () {
function confirmSyncSetting () { function confirmSyncSetting () {
saveConfig({ saveConfig({
'settings.sync': sync.value [configPaths.settings.sync]: sync.value
}) })
syncVisible.value = false syncVisible.value = false
} }
@ -2039,10 +2124,13 @@ async function initData () {
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.manualPageOpen = settings.manualPageOpen || 'window'
form.enableWebServer = settings.enableWebServer || false
form.webServerHost = settings.webServerHost || '0.0.0.0'
form.webServerPort = settings.webServerPort || 37777
form.webServerPath = settings.webServerPath || ''
currentLanguage.value = settings.language ?? 'zh-CN' currentLanguage.value = settings.language ?? 'zh-CN'
currentStartMode.value = settings.startMode || 'quiet' currentStartMode.value = settings.startMode || 'quiet'
customLink.value = settings.customLink || '![$fileName]($url)' customLink.value = settings.customLink || '![$fileName]($url)'
shortKey.upload = settings.shortKey.upload
proxy.value = picBed.proxy || '' proxy.value = picBed.proxy || ''
npmRegistry.value = settings.registry || '' npmRegistry.value = settings.registry || ''
npmProxy.value = settings.proxy || '' npmProxy.value = settings.proxy || ''
@ -2060,7 +2148,7 @@ async function initData () {
if (advancedRename.value.enable) { if (advancedRename.value.enable) {
form.autoRename = false form.autoRename = false
saveConfig({ saveConfig({
'settings.autoRename': false [configPaths.settings.autoRename]: false
}) })
} }
sync.value = settings.sync || { sync.value = settings.sync || {
@ -2112,13 +2200,13 @@ function openLogSetting () {
async function cancelCustomLink () { async function cancelCustomLink () {
customLinkVisible.value = false customLinkVisible.value = false
customLink.value = await getConfig<string>('settings.customLink') || '![$fileName]($url)' customLink.value = await getConfig<string>(configPaths.settings.customLink) || '![$fileName]($url)'
} }
function confirmCustomLink () { function confirmCustomLink () {
$customLink.value?.validate((valid: boolean) => { $customLink.value?.validate((valid: boolean) => {
if (valid) { if (valid) {
saveConfig('settings.customLink', customLink.value) saveConfig(configPaths.settings.customLink, customLink.value)
customLinkVisible.value = false customLinkVisible.value = false
sendToMain('updateCustomLink') sendToMain('updateCustomLink')
} else { } else {
@ -2128,7 +2216,7 @@ function confirmCustomLink () {
} }
function handleEncodeOutputURL (val: ICheckBoxValueType) { function handleEncodeOutputURL (val: ICheckBoxValueType) {
saveConfig('settings.encodeOutputURL', val) saveConfig(configPaths.settings.encodeOutputURL, val)
const successNotification = new Notification($T('SETTINGS_ENCODE_OUTPUT_URL'), { const successNotification = new Notification($T('SETTINGS_ENCODE_OUTPUT_URL'), {
body: $T('TIPS_SET_SUCCEED') body: $T('TIPS_SET_SUCCEED')
}) })
@ -2139,17 +2227,17 @@ function handleEncodeOutputURL (val: ICheckBoxValueType) {
async function handleCancelAdvancedRename () { async function handleCancelAdvancedRename () {
advancedRenameVisible.value = false advancedRenameVisible.value = false
advancedRename.value = toRaw((await getConfig<any>('buildIn.rename')) || { advancedRename.value = toRaw((await getConfig<any>(configPaths.buildIn.rename)) || {
enable: false, enable: false,
format: '{filename}' format: '{filename}'
}) })
} }
function handleSaveAdvancedRename () { function handleSaveAdvancedRename () {
saveConfig('buildIn.rename', toRaw(advancedRename.value)) saveConfig(configPaths.buildIn.rename, toRaw(advancedRename.value))
if (advancedRename.value.enable) { if (advancedRename.value.enable) {
form.autoRename = false form.autoRename = false
saveConfig('settings.autoRename', false) saveConfig(configPaths.settings.autoRename, false)
} }
advancedRenameVisible.value = false advancedRenameVisible.value = false
const successNotification = new Notification($T('SETTINGS_ADVANCED_RENAME'), { const successNotification = new Notification($T('SETTINGS_ADVANCED_RENAME'), {
@ -2162,15 +2250,15 @@ function handleSaveAdvancedRename () {
async function cancelProxy () { async function cancelProxy () {
proxyVisible.value = false proxyVisible.value = false
proxy.value = await getConfig<string>('picBed.proxy') || '' proxy.value = await getConfig<string>(configPaths.picBed.proxy) || ''
} }
function confirmProxy () { function confirmProxy () {
proxyVisible.value = false proxyVisible.value = false
saveConfig({ saveConfig({
'picBed.proxy': proxy.value, [configPaths.picBed.proxy]: proxy.value,
'settings.proxy': npmProxy.value, [configPaths.settings.proxy]: npmProxy.value,
'settings.registry': npmRegistry.value [configPaths.settings.registry]: npmRegistry.value
}) })
const successNotification = new Notification($T('SETTINGS_SET_PROXY_AND_MIRROR'), { const successNotification = new Notification($T('SETTINGS_SET_PROXY_AND_MIRROR'), {
body: $T('TIPS_SET_SUCCEED') body: $T('TIPS_SET_SUCCEED')
@ -2198,15 +2286,15 @@ function handleMigrateFromPicGo () {
} }
function updateHelperChange (val: ICheckBoxValueType) { function updateHelperChange (val: ICheckBoxValueType) {
saveConfig('settings.showUpdateTip', val) saveConfig(configPaths.settings.showUpdateTip, val)
} }
function autoImportChange (val: ICheckBoxValueType) { function autoImportChange (val: ICheckBoxValueType) {
saveConfig('settings.autoImport', val) saveConfig(configPaths.settings.autoImport, val)
} }
function handleAutoImportPicBedChange (val: string[]) { function handleAutoImportPicBedChange (val: string[]) {
saveConfig('settings.autoImportPicBed', val) saveConfig(configPaths.settings.autoImportPicBed, val)
} }
function handleHideDockChange (val: ICheckBoxValueType) { function handleHideDockChange (val: ICheckBoxValueType) {
@ -2215,16 +2303,16 @@ function handleHideDockChange (val: ICheckBoxValueType) {
form.isHideDock = false form.isHideDock = false
return return
} }
saveConfig('settings.isHideDock', val) saveConfig(configPaths.settings.isHideDock, val)
sendToMain(HIDE_DOCK, val) sendToMain(HIDE_DOCK, val)
} }
function useBuiltinClipboardChange (val: ICheckBoxValueType) { function useBuiltinClipboardChange (val: ICheckBoxValueType) {
saveConfig('settings.useBuiltinClipboard', val) saveConfig(configPaths.settings.useBuiltinClipboard, val)
} }
function handleIsAutoListenClipboard (val: ICheckBoxValueType) { function handleIsAutoListenClipboard (val: ICheckBoxValueType) {
saveConfig('settings.isAutoListenClipboard', val) saveConfig(configPaths.settings.isAutoListenClipboard, val)
} }
function handleShowPicBedListChange (val: ICheckBoxValueType[]) { function handleShowPicBedListChange (val: ICheckBoxValueType[]) {
@ -2237,37 +2325,37 @@ function handleShowPicBedListChange (val: ICheckBoxValueType[]) {
return item return item
}) })
saveConfig({ saveConfig({
'picBed.list': list [configPaths.picBed.list]: list
}) })
sendToMain(GET_PICBEDS) sendToMain(GET_PICBEDS)
} }
function handleAutoStartChange (val: ICheckBoxValueType) { function handleAutoStartChange (val: ICheckBoxValueType) {
saveConfig('settings.autoStart', val) saveConfig(configPaths.settings.autoStart, val)
sendToMain('autoStart', val) sendToMain('autoStart', val)
} }
function handleDeleteCloudFile (val: ICheckBoxValueType) { function handleDeleteCloudFile (val: ICheckBoxValueType) {
saveConfig({ saveConfig({
'settings.deleteCloudFile': val [configPaths.settings.deleteCloudFile]: val
}) })
} }
function handleDeleteLocalFile (val: ICheckBoxValueType) { function handleDeleteLocalFile (val: ICheckBoxValueType) {
saveConfig({ saveConfig({
'settings.deleteLocalFile': val [configPaths.settings.deleteLocalFile]: val
}) })
} }
function handleRename (val: ICheckBoxValueType) { function handleRename (val: ICheckBoxValueType) {
saveConfig({ saveConfig({
'settings.rename': val [configPaths.settings.rename]: val
}) })
} }
function handleAutoRename (val: ICheckBoxValueType) { function handleAutoRename (val: ICheckBoxValueType) {
saveConfig({ saveConfig({
'settings.autoRename': val [configPaths.settings.autoRename]: val
}) })
} }
@ -2296,26 +2384,50 @@ function cancelCheckVersion () {
checkUpdateVisible.value = false checkUpdateVisible.value = false
} }
function handleEnableWebServerChange (val: ICheckBoxValueType) {
saveConfig(configPaths.settings.enableWebServer, val)
}
function handleWebServerHostChange (val: string) {
saveConfig(configPaths.settings.webServerHost, val)
}
function handleWebServerPortChange (val?: number, oldVal?: number) {
saveConfig(configPaths.settings.webServerPort, Number(val) || 37777)
}
function handleWebServerPathChange (val: string) {
saveConfig(configPaths.settings.webServerPath, val)
}
function confirmWebServerSetting () {
if (form.enableWebServer) {
sendToMain('restartWebServer')
} else {
sendToMain('stopWebServer')
}
}
function handleServerKeyChange (val: string) { function handleServerKeyChange (val: string) {
saveConfig('settings.serverKey', val) saveConfig(configPaths.settings.serverKey, val)
} }
function handleUploadNotification (val: ICheckBoxValueType) { function handleUploadNotification (val: ICheckBoxValueType) {
saveConfig({ saveConfig({
'settings.uploadNotification': val [configPaths.settings.uploadNotification]: val
}) })
} }
function handleUploadResultNotification (val: ICheckBoxValueType) { function handleUploadResultNotification (val: ICheckBoxValueType) {
saveConfig({ saveConfig({
'settings.uploadResultNotification': val [configPaths.settings.uploadResultNotification]: val
}) })
} }
async function cancelWindowSize () { async function cancelWindowSize () {
mainWindowSizeVisible.value = false mainWindowSizeVisible.value = false
mainWindowWidth.value = await getConfig<number>('settings.mainWindowWidth') || 1200 mainWindowWidth.value = await getConfig<number>(configPaths.settings.mainWindowWidth) || 1200
mainWindowHeight.value = await getConfig<number>('settings.mainWindowHeight') || 800 mainWindowHeight.value = await getConfig<number>(configPaths.settings.mainWindowHeight) || 800
} }
async function confirmWindowSize () { async function confirmWindowSize () {
@ -2323,8 +2435,8 @@ async function confirmWindowSize () {
const width = enforceNumber(mainWindowWidth.value) const width = enforceNumber(mainWindowWidth.value)
const height = enforceNumber(mainWindowHeight.value) const height = enforceNumber(mainWindowHeight.value)
saveConfig({ saveConfig({
'settings.mainWindowWidth': rawPicGoSize.value ? 800 : width < 100 ? 100 : width, [configPaths.settings.mainWindowWidth]: rawPicGoSize.value ? 800 : width < 100 ? 100 : width,
'settings.mainWindowHeight': rawPicGoSize.value ? 450 : height < 100 ? 100 : height [configPaths.settings.mainWindowHeight]: rawPicGoSize.value ? 450 : height < 100 ? 100 : height
}) })
const successNotification = new Notification($T('SETTINGS_MAIN_WINDOW_SIZE'), { const successNotification = new Notification($T('SETTINGS_MAIN_WINDOW_SIZE'), {
@ -2336,15 +2448,15 @@ async function confirmWindowSize () {
} }
function handleAutoCloseMainWindowChange (val: ICheckBoxValueType) { function handleAutoCloseMainWindowChange (val: ICheckBoxValueType) {
saveConfig('settings.autoCloseMainWindow', val) saveConfig(configPaths.settings.autoCloseMainWindow, val)
} }
function handleAutoCloseMiniWindowChange (val: ICheckBoxValueType) { function handleAutoCloseMiniWindowChange (val: ICheckBoxValueType) {
saveConfig('settings.autoCloseMiniWindow', val) saveConfig(configPaths.settings.autoCloseMiniWindow, val)
} }
function handleMiniWindowOntop (val: ICheckBoxValueType) { function handleMiniWindowOntop (val: ICheckBoxValueType) {
saveConfig('settings.miniWindowOntop', val) saveConfig(configPaths.settings.miniWindowOntop, val)
$message.info($T('TIPS_NEED_RELOAD')) $message.info($T('TIPS_NEED_RELOAD'))
} }
@ -2352,18 +2464,18 @@ async function handleMiniIconPath (evt: 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('settings.customMiniIcon', form.customMiniIcon) saveConfig(configPaths.settings.customMiniIcon, form.customMiniIcon)
$message.info($T('TIPS_NEED_RELOAD')) $message.info($T('TIPS_NEED_RELOAD'))
} }
} }
function handleIsCustomMiniIcon (val: ICheckBoxValueType) { function handleIsCustomMiniIcon (val: ICheckBoxValueType) {
saveConfig('settings.isCustomMiniIcon', val) saveConfig(configPaths.settings.isCustomMiniIcon, val)
$message.info($T('TIPS_NEED_RELOAD')) $message.info($T('TIPS_NEED_RELOAD'))
} }
function handleAutoCopyUrl (val: ICheckBoxValueType) { function handleAutoCopyUrl (val: ICheckBoxValueType) {
saveConfig('settings.autoCopy', val) saveConfig(configPaths.settings.autoCopy, val)
const successNotification = new Notification($T('SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD'), { const successNotification = new Notification($T('SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD'), {
body: $T('TIPS_SET_SUCCEED') body: $T('TIPS_SET_SUCCEED')
}) })
@ -2373,7 +2485,7 @@ function handleAutoCopyUrl (val: ICheckBoxValueType) {
} }
function handleUseShortUrl (val: ICheckBoxValueType) { function handleUseShortUrl (val: ICheckBoxValueType) {
saveConfig('settings.useShortUrl', val) saveConfig(configPaths.settings.useShortUrl, val)
const successNotification = new Notification($T('SETTINGS_SHORT_URL'), { const successNotification = new Notification($T('SETTINGS_SHORT_URL'), {
body: $T('TIPS_SET_SUCCEED') body: $T('TIPS_SET_SUCCEED')
}) })
@ -2383,27 +2495,27 @@ function handleUseShortUrl (val: ICheckBoxValueType) {
} }
function handleShortUrlServerChange (val: string) { function handleShortUrlServerChange (val: string) {
saveConfig('settings.shortUrlServer', val) saveConfig(configPaths.settings.shortUrlServer, val)
} }
function handleC1nTokenChange (val: string) { function handleC1nTokenChange (val: string) {
saveConfig('settings.c1nToken', val) saveConfig(configPaths.settings.c1nToken, val)
} }
function handleYourlsDomainChange (val: string) { function handleYourlsDomainChange (val: string) {
saveConfig('settings.yourlsDomain', val) saveConfig(configPaths.settings.yourlsDomain, val)
} }
function handleYourlsSignatureChange (val: string) { function handleYourlsSignatureChange (val: string) {
saveConfig('settings.yourlsSignature', val) saveConfig(configPaths.settings.yourlsSignature, val)
} }
function handleCfWorkerHostChange (val: string) { function handleCfWorkerHostChange (val: string) {
saveConfig('settings.cfWorkerHost', val) saveConfig(configPaths.settings.cfWorkerHost, val)
} }
function handleAesPasswordChange (val: string) { function handleAesPasswordChange (val: string) {
saveConfig('settings.aesPassword', val || 'PicList-aesPassword') saveConfig(configPaths.settings.aesPassword, val || 'PicList-aesPassword')
} }
function confirmLogLevelSetting () { function confirmLogLevelSetting () {
@ -2411,8 +2523,8 @@ function confirmLogLevelSetting () {
return $message.error($T('TIPS_PLEASE_CHOOSE_LOG_LEVEL')) return $message.error($T('TIPS_PLEASE_CHOOSE_LOG_LEVEL'))
} }
saveConfig({ saveConfig({
'settings.logLevel': form.logLevel, [configPaths.settings.logLevel]: form.logLevel,
'settings.logFileSizeLimit': form.logFileSizeLimit [configPaths.settings.logFileSizeLimit]: form.logFileSizeLimit
}) })
const successNotification = new Notification($T('SETTINGS_SET_LOG_FILE'), { const successNotification = new Notification($T('SETTINGS_SET_LOG_FILE'), {
body: $T('TIPS_SET_SUCCEED') body: $T('TIPS_SET_SUCCEED')
@ -2425,8 +2537,8 @@ function confirmLogLevelSetting () {
async function cancelLogLevelSetting () { async function cancelLogLevelSetting () {
logFileVisible.value = false logFileVisible.value = false
let logLevel = await getConfig<string | string[]>('settings.logLevel') let logLevel = await getConfig<string | string[]>(configPaths.settings.logLevel)
const logFileSizeLimit = await getConfig<number>('settings.logFileSizeLimit') || 10 const logFileSizeLimit = await getConfig<number>(configPaths.settings.logFileSizeLimit) || 10
if (!Array.isArray(logLevel)) { if (!Array.isArray(logLevel)) {
if (logLevel && logLevel.length > 0) { if (logLevel && logLevel.length > 0) {
logLevel = [logLevel] logLevel = [logLevel]
@ -2501,7 +2613,7 @@ async function downloadAll () {
function confirmServerSetting () { function confirmServerSetting () {
server.value.port = parseInt(server.value.port as unknown as string, 10) server.value.port = parseInt(server.value.port as unknown as string, 10)
saveConfig({ saveConfig({
'settings.server': server.value [configPaths.settings.server]: server.value
}) })
const successNotification = new Notification($T('SETTINGS_SET_PICGO_SERVER'), { const successNotification = new Notification($T('SETTINGS_SET_PICGO_SERVER'), {
body: $T('TIPS_SET_SUCCEED') body: $T('TIPS_SET_SUCCEED')
@ -2515,7 +2627,7 @@ function confirmServerSetting () {
async function cancelServerSetting () { async function cancelServerSetting () {
serverVisible.value = false serverVisible.value = false
server.value = await getConfig('settings.server') || { server.value = await getConfig(configPaths.settings.server) || {
port: 36677, port: 36677,
host: '0.0.0.0', host: '0.0.0.0',
enable: true enable: true
@ -2546,28 +2658,28 @@ function handleLevelDisabled (val: string) {
function handleLanguageChange (val: string) { function handleLanguageChange (val: string) {
i18nManager.setCurrentLanguage(val) i18nManager.setCurrentLanguage(val)
saveConfig({ saveConfig({
'settings.language': val [configPaths.settings.language]: val
}) })
sendToMain(GET_PICBEDS) sendToMain(GET_PICBEDS)
} }
function handleStartModeChange (val: 'quiet' | 'mini' | 'main' | 'no-tray') { function handleStartModeChange (val: ISartModeValues) {
if (val === '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 = 'quiet' currentStartMode.value = ISartMode.QUIET
return return
} }
$message.info($T('TIPS_NEED_RELOAD')) $message.info($T('TIPS_NEED_RELOAD'))
} }
saveConfig({ saveConfig({
'settings.startMode': val [configPaths.settings.startMode]: val
}) })
} }
function handleManualPageOpenChange (val: string) { function handleManualPageOpenChange (val: string) {
saveConfig({ saveConfig({
'settings.manualPageOpen': val [configPaths.settings.manualPageOpen]: val
}) })
} }

View File

@ -274,6 +274,7 @@ import axios from 'axios'
// //
import { IRPCActionType } from '~/universal/types/enum' import { IRPCActionType } from '~/universal/types/enum'
import { configPaths } from '~/universal/utils/configPaths'
const $confirm = ElMessageBox.confirm const $confirm = ElMessageBox.confirm
const searchText = ref('') const searchText = ref('')
@ -416,7 +417,7 @@ onBeforeMount(async () => {
}) })
getPluginList() getPluginList()
getSearchResult = debounce(_getSearchResult, 50) getSearchResult = debounce(_getSearchResult, 50)
needReload.value = await getConfig<boolean>('needReload') || false needReload.value = await getConfig<boolean>(configPaths.needReload) || false
}) })
async function buildContextMenu (plugin: IPicGoPlugin) { async function buildContextMenu (plugin: IPicGoPlugin) {
@ -577,19 +578,19 @@ function handleSearchResult (item: INPMSearchResultObject) {
// restore Uploader & Transformer // restore Uploader & Transformer
async function handleRestoreState (item: string, name: string) { async function handleRestoreState (item: string, name: string) {
if (item === 'uploader') { if (item === 'uploader') {
const current = await getConfig('picBed.current') const current = await getConfig(configPaths.picBed.current)
if (current === name) { if (current === name) {
saveConfig({ saveConfig({
'picBed.current': 'smms', [configPaths.picBed.current]: 'smms',
'picBed.uploader': 'smms' [configPaths.picBed.uploader]: 'smms'
}) })
} }
} }
if (item === 'transformer') { if (item === 'transformer') {
const current = await getConfig('picBed.transformer') const current = await getConfig(configPaths.picBed.transformer)
if (current === name) { if (current === name) {
saveConfig({ saveConfig({
'picBed.transformer': 'path' [configPaths.picBed.transformer]: 'path'
}) })
} }
} }

View File

@ -132,6 +132,7 @@ import { getConfig, sendToMain } from '@/utils/dataSender'
// //
import { T as $T } from '@/i18n' import { T as $T } from '@/i18n'
import { configPaths } from '~/universal/utils/configPaths'
const list = ref<IShortKeyConfig[]>([]) const list = ref<IShortKeyConfig[]>([])
const keyBindingVisible = ref(false) const keyBindingVisible = ref(false)
@ -140,7 +141,7 @@ const shortKey = ref('')
const currentIndex = ref(0) const currentIndex = ref(0)
onBeforeMount(async () => { onBeforeMount(async () => {
const shortKeyConfig = (await getConfig<IShortKeyConfigs>('settings.shortKey'))! const shortKeyConfig = (await getConfig<IShortKeyConfigs>(configPaths.settings.shortKey._path))!
list.value = Object.keys(shortKeyConfig).map(item => { list.value = Object.keys(shortKeyConfig).map(item => {
return { return {
...shortKeyConfig[item], ...shortKeyConfig[item],

View File

@ -88,6 +88,7 @@ import { getConfig, sendToMain } from '@/utils/dataSender'
// //
import { handleUrlEncode } from '#/utils/common' import { handleUrlEncode } from '#/utils/common'
import { configPaths } from '~/universal/utils/configPaths'
const files = ref<IResult<ImgInfo>[]>([]) const files = ref<IResult<ImgInfo>[]>([])
const notification = reactive({ const notification = reactive({
@ -128,8 +129,8 @@ const formatCustomLink = (customLink: string, item: ImgInfo) => {
} }
async function copyTheLink (item: ImgInfo) { async function copyTheLink (item: ImgInfo) {
const pasteStyle = await getConfig<IPasteStyle>('settings.pasteStyle') || IPasteStyle.MARKDOWN const pasteStyle = await getConfig<IPasteStyle>(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const customLink = await getConfig<string>('settings.customLink') const customLink = await getConfig<string>(configPaths.settings.customLink)
const txt = await pasteTemplate(pasteStyle, item, customLink) const txt = await pasteTemplate(pasteStyle, item, customLink)
clipboard.writeText(txt) clipboard.writeText(txt)
const myNotification = new Notification(notification.title, notification) const myNotification = new Notification(notification.title, notification)
@ -143,10 +144,10 @@ async function pasteTemplate (style: IPasteStyle, item: ImgInfo, customLink: str
if (item.type === 'aws-s3' || item.type === 'aws-s3-plist') { if (item.type === 'aws-s3' || item.type === 'aws-s3-plist') {
url = item.imgUrl || item.url || '' url = item.imgUrl || item.url || ''
} }
if ((await getConfig('settings.encodeOutputURL')) === true) { if ((await getConfig(configPaths.settings.encodeOutputURL)) === true) {
url = handleUrlEncode(url) url = handleUrlEncode(url)
} }
const useShortUrl = await getConfig('settings.useShortUrl') || false const useShortUrl = await getConfig(configPaths.settings.useShortUrl) || false
if (useShortUrl) { if (useShortUrl) {
url = await ipcRenderer.invoke('getShortUrl', url) url = await ipcRenderer.invoke('getShortUrl', url)
} }

View File

@ -466,7 +466,8 @@ import { useRouter } from 'vue-router'
// //
import { PICBEDS_PAGE } from '@/router/config' import { PICBEDS_PAGE } from '@/router/config'
import { IRPCActionType } from '~/universal/types/enum' import { IPasteStyle, IRPCActionType } from '~/universal/types/enum'
import { configPaths } from '~/universal/utils/configPaths'
const $router = useRouter() const $router = useRouter()
@ -538,14 +539,14 @@ function handleSaveConfig () {
const formatConvertObjFilter = Object.fromEntries(formatConvertObjEntriesFilter) const formatConvertObjFilter = Object.fromEntries(formatConvertObjEntriesFilter)
formatConvertObj.value = JSON.stringify(formatConvertObjFilter) formatConvertObj.value = JSON.stringify(formatConvertObjFilter)
compressForm.formatConvertObj = formatConvertObjFilter compressForm.formatConvertObj = formatConvertObjFilter
saveConfig('buildIn.compress', toRaw(compressForm)) saveConfig(configPaths.buildIn.compress, toRaw(compressForm))
saveConfig('buildIn.watermark', toRaw(waterMarkForm)) saveConfig(configPaths.buildIn.watermark, toRaw(waterMarkForm))
closeDialog() closeDialog()
} }
async function initData () { async function initData () {
const compress = await getConfig<IBuildInCompressOptions>('buildIn.compress') const compress = await getConfig<IBuildInCompressOptions>(configPaths.buildIn.compress)
const watermark = await getConfig<IBuildInWaterMarkOptions>('buildIn.watermark') const watermark = await getConfig<IBuildInWaterMarkOptions>(configPaths.buildIn.watermark)
if (compress) { if (compress) {
compressForm.quality = compress.quality ?? 100 compressForm.quality = compress.quality ?? 100
compressForm.isConvert = compress.isConvert ?? false compressForm.isConvert = compress.isConvert ?? false
@ -637,7 +638,7 @@ function onProgressChange (val: number) {
async function handlePicBedNameClick (_picBedName: string, picBedConfigName: string | undefined) { async function handlePicBedNameClick (_picBedName: string, picBedConfigName: string | undefined) {
const formatedpicBedConfigName = picBedConfigName || 'Default' const formatedpicBedConfigName = picBedConfigName || 'Default'
const currentPicBed = await getConfig<string>('picBed.current') const currentPicBed = await getConfig<string>(configPaths.picBed.current)
const currentPicBedConfig = await getConfig<any[]>(`uploader.${currentPicBed}`) as any || {} const currentPicBedConfig = await getConfig<any[]>(`uploader.${currentPicBed}`) as any || {}
const configList = await triggerRPC<IUploaderConfigItem>(IRPCActionType.GET_PICBED_CONFIG_LIST, currentPicBed) const configList = await triggerRPC<IUploaderConfigItem>(IRPCActionType.GET_PICBED_CONFIG_LIST, currentPicBed)
const currentConfigList = configList?.configList ?? [] const currentConfigList = configList?.configList ?? []
@ -721,23 +722,23 @@ function ipcSendFiles (files: FileList) {
} }
async function getPasteStyle () { async function getPasteStyle () {
pasteStyle.value = await getConfig('settings.pasteStyle') || 'markdown' pasteStyle.value = await getConfig(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
customLink.value = await getConfig('settings.customLink') || '![$fileName]($url)' customLink.value = await getConfig(configPaths.settings.customLink) || '![$fileName]($url)'
} }
async function getUseShortUrl () { async function getUseShortUrl () {
useShortUrl.value = await getConfig('settings.useShortUrl') || false useShortUrl.value = await getConfig(configPaths.settings.useShortUrl) || false
} }
async function handleUseShortUrlChange () { async function handleUseShortUrlChange () {
saveConfig({ saveConfig({
'settings.useShortUrl': useShortUrl.value [configPaths.settings.useShortUrl]: useShortUrl.value
}) })
} }
function handlePasteStyleChange (val: string | number | boolean) { function handlePasteStyleChange (val: string | number | boolean) {
saveConfig({ saveConfig({
'settings.pasteStyle': val [configPaths.settings.pasteStyle]: val
}) })
} }
@ -766,7 +767,7 @@ function handleInputBoxValue (val: string) {
} }
async function getDefaultPicBed () { async function getDefaultPicBed () {
const currentPicBed = await getConfig<string>('picBed.current') const currentPicBed = await getConfig<string>(configPaths.picBed.current)
picBed.value.forEach(item => { picBed.value.forEach(item => {
if (item.type === currentPicBed) { if (item.type === currentPicBed) {
picBedName.value = item.name picBedName.value = item.name

View File

@ -118,6 +118,7 @@ import { PICBEDS_PAGE, UPLOADER_CONFIG_PAGE } from '@/router/config'
// //
import { useStore } from '@/hooks/useStore' import { useStore } from '@/hooks/useStore'
import { configPaths } from '~/universal/utils/configPaths'
const $router = useRouter() const $router = useRouter()
const $route = useRoute() const $route = useRoute()
@ -187,8 +188,8 @@ function addNewConfig () {
function setDefaultPicBed (type: string) { function setDefaultPicBed (type: string) {
saveConfig({ saveConfig({
'picBed.current': type, [configPaths.picBed.current]: type,
'picBed.uploader': type [configPaths.picBed.uploader]: type
}) })
store?.setDefaultPicBed(type) store?.setDefaultPicBed(type)

View File

@ -132,6 +132,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'
const type = ref('') const type = ref('')
const config = ref<IPicGoPluginConfig[]>([]) const config = ref<IPicGoPluginConfig[]>([])
@ -227,8 +228,8 @@ function handleNameClick () {
async function handleCopyApi () { async function handleCopyApi () {
try { try {
const { port = 36677, host = '127.0.0.1' } = await getConfig<IStringKeyMap>('settings.server') || {} const { port = 36677, host = '127.0.0.1' } = await getConfig<IStringKeyMap>(configPaths.settings.server) || {}
const serverKey = await getConfig('settings.serverKey') || '' const serverKey = await getConfig(configPaths.settings.serverKey) || ''
const uploader = await getConfig('uploader') as IStringKeyMap || {} const uploader = await getConfig('uploader') as IStringKeyMap || {}
const picBedConfigList = uploader[$route.params.type as string].configList || [] const picBedConfigList = uploader[$route.params.type as string].configList || []
const picBedConfig = picBedConfigList.find((item: IUploaderConfigListItem) => item._id === $route.params.configId) const picBedConfig = picBedConfigList.find((item: IUploaderConfigListItem) => item._id === $route.params.configId)

View File

@ -1,14 +1,15 @@
import { reactive, InjectionKey, readonly, App, UnwrapRef, ref } from 'vue' import { reactive, InjectionKey, readonly, App, UnwrapRef, ref } from 'vue'
import { saveConfig } from '@/utils/dataSender' import { saveConfig } from '@/utils/dataSender'
import { configPaths } from '~/universal/utils/configPaths'
export interface IState { export interface IState {
defaultPicBed: string; defaultPicBed: string
} }
export interface IStore { export interface IStore {
state: UnwrapRef<IState> state: UnwrapRef<IState>
setDefaultPicBed: (type: string) => void; setDefaultPicBed: (type: string) => void
updateForceUpdateTime: () => void; updateForceUpdateTime: () => void
} }
export const storeKey: InjectionKey<IStore> = Symbol('store') export const storeKey: InjectionKey<IStore> = Symbol('store')
@ -23,8 +24,8 @@ const forceUpdateTime = ref<number>(Date.now())
// methods // methods
const setDefaultPicBed = (type: string) => { const setDefaultPicBed = (type: string) => {
saveConfig({ saveConfig({
'picBed.current': type, [configPaths.picBed.current]: type,
'picBed.uploader': type [configPaths.picBed.uploader]: type
}) })
state.defaultPicBed = type state.defaultPicBed = type
} }

View File

@ -5,7 +5,7 @@ declare type IWindowList = import('./enum').IWindowList
declare interface IWindowListItem { declare interface IWindowListItem {
isValid: boolean isValid: boolean
multiple: boolean multiple: boolean
options: () => IBrowserWindowOptions, options: () => IBrowserWindowOptions
callback: (window: BrowserWindow, windowManager: IWindowManager) => void callback: (window: BrowserWindow, windowManager: IWindowManager) => void
} }

View File

@ -96,3 +96,22 @@ export enum IToolboxItemCheckStatus {
SUCCESS = 'success', SUCCESS = 'success',
ERROR = 'error', ERROR = 'error',
} }
export enum ISartMode {
QUIET = 'quiet',
MINI = 'mini',
MAIN = 'main',
NO_TRAY = 'no-tray'
}
export enum II18nLanguage {
ZH_CN = 'zh-CN',
ZH_TW = 'zh-TW',
EN = 'en'
}
export enum IShortUrlServer {
C1N = 'c1n',
YOURLS = 'yourls',
CFWORKER = 'cf_worker'
}

View File

@ -204,6 +204,14 @@ interface ILocales {
SETTINGS_SET_SERVER_HOST: string SETTINGS_SET_SERVER_HOST: string
SETTINGS_SET_SERVER_PORT: string SETTINGS_SET_SERVER_PORT: string
SETTINGS_SET_SERVER_KEY: string SETTINGS_SET_SERVER_KEY: string
SETTINGS_SET_WEB_SERVER: string
SETTINGS_TIPS_WEB_SERVER_NOTICE: string
SETTINGS_SET_ENABLE_WEB_SERVER: string
SETTINGS_SET_WEB_SERVER_HOST: string
SETTINGS_SET_WEB_SERVER_PORT: string
SETTINGS_SET_WEB_SERVER_PATH: string
SETTINGS_TIP_PLACEHOLDER_WEB_HOST: string
SETTINGS_TIP_PLACEHOLDER_WEB_PORT: string
SETTINGS_TIP_PLACEHOLDER_HOST: string SETTINGS_TIP_PLACEHOLDER_HOST: string
SETTINGS_TIP_PLACEHOLDER_PORT: string SETTINGS_TIP_PLACEHOLDER_PORT: string
SETTINGS_TIP_PLACEHOLDER_KEY: string SETTINGS_TIP_PLACEHOLDER_KEY: string

View File

@ -4,39 +4,39 @@ import { ILogger } from "piclist/dist/types";
type Undefinable<T> = T | undefined; type Undefinable<T> = T | undefined;
declare interface ManageError extends Error { declare interface ManageError extends Error {
code?: number; code?: number
param?: string; param?: string
stack?: string; stack?: string
picbed?: string; picbed?: string
} }
type PicBedMangeConfig = IStringKeyMap; type PicBedMangeConfig = IStringKeyMap;
interface PicBedManageConfigMap { interface PicBedManageConfigMap {
[key: string]: PicBedMangeConfig; [key: string]: PicBedMangeConfig
} }
interface ManageApiType { interface ManageApiType {
/** /**
* logger * logger
*/ */
logger: ILogger; logger: ILogger
/** /**
* congif path * congif path
*/ */
configPath: string; configPath: string
/** /**
* basedir * basedir
*/ */
baseDir: string; baseDir: string
/** /**
* current picBed name * current picBed name
*/ */
currentPicBed: string; currentPicBed: string
/** /**
* current picBed config * current picBed config
*/ */
currentPicBedConfig: PicBedMangeConfig; currentPicBedConfig: PicBedMangeConfig
/** /**
* get manage config * get manage config
*/ */
@ -62,136 +62,136 @@ interface ManageApiType {
*/ */
getBucketListRecursively: ( getBucketListRecursively: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<any | ManageError>; ) => Promise<any | ManageError>
/** /**
* get bucket list * get bucket list
*/ */
getBucketListBackstage: ( getBucketListBackstage: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<any | ManageError>; ) => Promise<any | ManageError>
/** /**
* get bucket list * get bucket list
*/ */
getBucketList: ( getBucketList: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<any | ManageError>; ) => Promise<any | ManageError>
getBucketDomain: ( getBucketDomain: (
param: IStringKeyMap param: IStringKeyMap
) => Promise<any>; ) => Promise<any>
/** /**
* get bucket info * get bucket info
*/ */
getBucketInfo: ( getBucketInfo: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<IStringKeyMap | ManageError>; ) => Promise<IStringKeyMap | ManageError>
/** /**
* create bucket * create bucket
*/ */
createBucket: ( createBucket: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* delete bucket * delete bucket
*/ */
deleteBucket: ( deleteBucket: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* get Operator list * get Operator list
* specific for upyun * specific for upyun
*/ */
getOperatorList: ( getOperatorList: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<string[] | ManageError>; ) => Promise<string[] | ManageError>
/** /**
* add Operator * add Operator
* specific for upyun * specific for upyun
*/ */
addOperator: ( addOperator: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* delete Operator * delete Operator
* specific for upyun * specific for upyun
*/ */
deleteOperator: ( deleteOperator: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* get bucket ACL policy * get bucket ACL policy
*/ */
getBucketAclPolicy: ( getBucketAclPolicy: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<IStringKeyMap | ManageError>; ) => Promise<IStringKeyMap | ManageError>
/** /**
* set bucket ACL policy * set bucket ACL policy
*/ */
setBucketAclPolicy: ( setBucketAclPolicy: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* get bucket file list * get bucket file list
*/ */
getBucketFileList: ( getBucketFileList: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<IStringKeyMap | ManageError>; ) => Promise<IStringKeyMap | ManageError>
/** /**
* delete bucket file * delete bucket file
*/ */
deleteBucketFile: ( deleteBucketFile: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* delete folder * delete folder
*/ */
deleteBucketFolder: ( deleteBucketFolder: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* rename bucket file * rename bucket file
*/ */
renameBucketFile: ( renameBucketFile: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* download bucket file * download bucket file
*/ */
downloadBucketFile: ( downloadBucketFile: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* copy or move between buckets * copy or move between buckets
*/ */
copyMoveBucketFile: ( copyMoveBucketFile: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* create folder * create folder
*/ */
createBucketFolder: ( createBucketFolder: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* upload file * upload file
*/ */
uploadBucketFile: ( uploadBucketFile: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<boolean>; ) => Promise<boolean>
/** /**
* get presigned url * get presigned url
*/ */
getPreSignedUrl: ( getPreSignedUrl: (
param?: IStringKeyMap param?: IStringKeyMap
) => Promise<string>; ) => Promise<string>
} }
/** PicList 存储管理功能配置文件类型定义 */ /** PicList 存储管理功能配置文件类型定义 */
interface ManageConfigType { interface ManageConfigType {
picBed: { picBed: {
[others: string]: any; [others: string]: any
}; }
settings: { settings: {
[others: string]: any; [others: string]: any
}; }
[others: string]: any; [others: string]: any
} }

View File

@ -35,6 +35,18 @@ interface IServerConfig {
enable: boolean enable: boolean
} }
interface ISyncConfig {
type: string
file?: string
username: string
repo: string
branch: string
token: string
endpoint?: string
proxy?: string
interval?: number
}
// Image && PicBed // Image && PicBed
interface ImgInfo { interface ImgInfo {
buffer?: Buffer buffer?: Buffer
@ -86,25 +98,25 @@ interface IOldShortKeyConfigs {
} }
interface IKeyCommandType { interface IKeyCommandType {
key: string, key: string
command: string command: string
} }
// Main process // Main process
interface IBrowserWindowOptions { interface IBrowserWindowOptions {
height: number, height: number
width: number, width: number
show: boolean, show: boolean
fullscreenable: boolean, fullscreenable: boolean
resizable: boolean, resizable: boolean
webPreferences: { webPreferences: {
nodeIntegration: boolean, nodeIntegration: boolean
nodeIntegrationInWorker: boolean, nodeIntegrationInWorker: boolean
contextIsolation: boolean, contextIsolation: boolean
backgroundThrottling: boolean backgroundThrottling: boolean
webSecurity?: boolean webSecurity?: boolean
}, }
vibrancy?: string | any, vibrancy?: string | any
frame?: boolean frame?: boolean
center?: boolean center?: boolean
title?: string title?: string
@ -275,67 +287,148 @@ interface IShortKeyHandlerObj {
type IShortKeyHandler = (ctx: ICtx, guiApi?: IGuiApi) => Promise<void | ICtx> type IShortKeyHandler = (ctx: ICtx, guiApi?: IGuiApi) => Promise<void | ICtx>
type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
interface shortKeyHandlerMap { interface shortKeyHandlerMap {
from: string from: string
handle: IShortKeyHandler handle: IShortKeyHandler
} }
// PicBeds // PicBeds
interface ITelegraphConfig {
proxy?: string
}
interface ILocalConfig {
path: string
customUrl?: string
webPath?: string
}
interface IAliYunConfig { interface IAliYunConfig {
accessKeyId: string accessKeyId: string
accessKeySecret: string, accessKeySecret: string
bucket: string, bucket: string
area: string, area: string
path: string, path: string
customUrl: string customUrl: string
options: string options: string
} }
interface IGitHubConfig { interface IGitHubConfig {
repo: string, repo: string
token: string, token: string
path: string, path: string
customUrl: string, customUrl: string
branch: string branch: string
} }
interface IImgurConfig { interface IImgurConfig {
clientId: string, clientId: string
proxy: string proxy: string
username: string
accessToken: string
album: string
} }
interface IQiniuConfig { interface IQiniuConfig {
accessKey: string, accessKey: string
secretKey: string, secretKey: string
bucket: string, bucket: string
url: string, url: string
area: string, area: 'z0' | 'z1' | 'z2' | 'na0' | 'as0' | string
options: string, options: string
path: string path: string
} }
interface ISMMSConfig { interface ISMMSConfig {
token: string token: string
backupDomain?: string
} }
interface ITcYunConfig { interface ITcYunConfig {
secretId: string, secretId: string
secretKey: string, secretKey: string
bucket: string, bucket: string
appId: string, appId: string
area: string, endpoint: string
path: string, area: string
customUrl: string, path: string
version: 'v4' | 'v5', customUrl: string
version: 'v4' | 'v5'
options: string options: string
slim: boolean
} }
interface IUpYunConfig { interface IUpYunConfig {
bucket: string, bucket: string
operator: string, operator: string
password: string, password: string
options: string, options: string
path: string path: string
url: string
antiLeechToken: string
expireTime: number
endpoint: string
}
interface IWebdavPlistConfig {
host: string
sslEnabled: boolean
username: string
password: string
path: string
webpath: string
customUrl: string
authType: string
options: string
}
interface ISftpPlistConfig {
host: string
port?: number
username: string
password?: string
privateKey?: string
passphrase?: string
uploadPath?: string
customUrl?: string
webPath?: string
fileUser?: string
fileMode?: string
dirMode?: string
}
interface IPicListConfig {
host: string
port?: number
picbed?: string
configName?: string
serverKey?: string
}
interface ILskyConfig {
version: string
host: string
token: string
strategyId: string
albumId: string
permission: IStringKeyMap
}
interface IAwsS3PListUserConfig {
accessKeyID: string
secretAccessKey: string
bucketName: string
uploadPath: string
region?: string
endpoint?: string
proxy?: string
urlPrefix?: string
pathStyleAccess?: boolean
rejectUnauthorized?: boolean
acl?: string
disableBucketPrefixToURL?: boolean | string
} }
type ILoggerType = string | Error | boolean | number | undefined type ILoggerType = string | Error | boolean | number | undefined
@ -362,9 +455,9 @@ type ILogArgvType = string | number
type ILogArgvTypeWithError = ILogArgvType | Error type ILogArgvTypeWithError = ILogArgvType | Error
interface IMiniWindowPos { interface IMiniWindowPos {
x: number, x: number
y: number, y: number
height: number, height: number
width: number width: number
} }

View File

@ -13,26 +13,30 @@ interface ISettingForm {
autoCopyUrl: boolean autoCopyUrl: boolean
checkBetaUpdate: boolean checkBetaUpdate: boolean
useBuiltinClipboard: boolean useBuiltinClipboard: boolean
language: string language: 'zh-CN' | 'zh-TW' | 'en'
logFileSizeLimit: number, logFileSizeLimit: number
deleteCloudFile: boolean, deleteCloudFile: boolean
isCustomMiniIcon: boolean, isCustomMiniIcon: boolean
customMiniIcon: string, customMiniIcon: string
isHideDock: boolean, isHideDock: boolean
autoImport: boolean, autoImport: boolean
autoImportPicBed: string[], autoImportPicBed: string[]
encodeOutputURL: boolean, encodeOutputURL: boolean
isAutoListenClipboard: boolean, isAutoListenClipboard: boolean
useShortUrl: boolean, useShortUrl: boolean
c1nToken: string, c1nToken: string
shortUrlServer: string, shortUrlServer: 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: string manualPageOpen: 'window' | 'browser'
enableWebServer: boolean
webServerHost: string
webServerPort: number
webServerPath: string
} }
interface IShortKeyMap { interface IShortKeyMap {

View File

@ -33,7 +33,15 @@ export const enforceNumber = (num: number | string) => isNaN(+num) ? 0 : +num
export const isDev = process.env.NODE_ENV === 'development' export const isDev = process.env.NODE_ENV === 'development'
export const trimValues = <T extends IStringKeyMap>(obj: T): {[K in keyof T]: T[K] extends string ? string : T[K]} => { export const trimValues = <T extends IStringKeyMap>(obj: T): {[K in keyof T]: T[K] extends string ? string : T[K]} => {
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, typeof value === 'string' ? value.trim() : value])) as {[K in keyof T]: T[K] extends string ? string : T[K]} return Object
.fromEntries(
Object
.entries(obj)
.map(([key, value]) =>
[key, typeof value === 'string'
? value.trim()
: value])
) as {[K in keyof T]: T[K] extends string ? string : T[K]}
} }
export function isNeedToShorten (alias: string, cutOff = 20) { export function isNeedToShorten (alias: string, cutOff = 20) {
@ -52,3 +60,11 @@ export function safeSliceF (str:string, total: number) {
} }
return result return result
} }
export function encodeFilePath (filePath: string) {
return filePath
.replace(/\\/g, '/')
.split('/')
.map(encodeURIComponent)
.join('/')
}

View File

@ -0,0 +1,257 @@
import { II18nLanguage, IPasteStyle, ISartMode, IShortUrlServer } from '../types/enum'
import { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
export type ISartModeValues = typeof ISartMode[keyof typeof ISartMode]
export type IPasteStyleValues = typeof IPasteStyle[keyof typeof IPasteStyle]
export type II18nLanguageValues = typeof II18nLanguage[keyof typeof II18nLanguage]
export type IShortUrlServerValues = typeof IShortUrlServer[keyof typeof IShortUrlServer]
export type manualPageOpenType = 'window' | 'browser'
interface IPicGoPlugins {
[key: `picgo-plugin-${string}`]: boolean
}
export interface IConfigStruct {
picBed: {
uploader: string,
current?: string,
smms?: ISMMSConfig,
qiniu?: IQiniuConfig,
upyun?: IUpYunConfig
tcyun?: ITcYunConfig
github?: IGitHubConfig
aliyun?: IAliYunConfig
imgur?: IImgurConfig
webdavplist?: IWebdavPlistConfig
local?: ILocalConfig
sftpplist?: ISftpPlistConfig
telegraphplist?: ITelegraphConfig
lskyplist?: ILskyConfig
'aws-s3-plist': IAwsS3PListUserConfig
proxy?: string
transformer?: string
list: IPicBedType[]
[others: string]: any
},
settings: {
shortKey: {
[key: string]: IShortKeyConfig
}
logLevel: string[]
logPath: string
logFileSizeLimit: number
isAutoListenClipboard: boolean
isListeningClipboard: boolean
showUpdateTip: boolean
miniWindowPosition: [number, number]
miniWindowOntop: boolean
mainWindowWidth: number
mainWindowHeight: number
isHideDock: boolean
autoCloseMiniWindow: boolean
autoCloseMainWindow: boolean
isCustomMiniIcon: boolean
customMiniIcon: string
startMode: ISartModeValues
autoRename: boolean
deleteCloudFile: boolean
server: IServerConfig
serverKey: string
pasteStyle: IPasteStyleValues
aesPassword: string
rename: boolean
sync: ISyncConfig
tempDirPath: string
language: II18nLanguageValues
customLink: string
manualPageOpen: manualPageOpenType
encodeOutputURL: boolean
useShortUrl: boolean
shortUrlServer: IShortUrlServerValues
c1nToken: string
cfWorkerHost: string
yourlsDomain: string
yourlsSignature: string
isSilentNotice: boolean
proxy: string
registry: string
autoCopy: boolean
enableWebServer: boolean
webServerHost: string
webServerPort: number
webServerPath: string
deleteLocalFile: boolean
uploadResultNotification: boolean
uploadNotification: boolean
useBuiltinClipboard: boolean
autoStart: boolean
autoImport: boolean
autoImportPicBed: string[]
}
needReload: boolean
picgoPlugins: IPicGoPlugins
uploader: IUploaderConfig
buildIn: {
compress: IBuildInCompressOptions
waterMark: IBuildInWaterMarkOptions
rename: {
enable: boolean
format: string
}
}
debug: boolean
PICGO_ENV: string
}
interface IConfigPaths {
picBed: {
current: string
uploader: string
proxy: string
transformer: string
list: string
},
settings: {
shortKey: {
_path: string
'picgo:upload': string
}
logLevel: string
logPath: string
logFileSizeLimit: string
isAutoListenClipboard: string
isListeningClipboard: string
showUpdateTip: string
miniWindowPosition: string
miniWindowOntop: string
isHideDock: string
mainWindowWidth: string
mainWindowHeight: string
autoCloseMiniWindow: string
autoCloseMainWindow: string
isCustomMiniIcon: string
customMiniIcon: string
startMode: string
autoRename: string
deleteCloudFile: string
server: string
serverKey: string
pasteStyle: string
aesPassword: string
rename: string
sync: string
tempDirPath: string
language: string
customLink: string
manualPageOpen: string
encodeOutputURL: string
useShortUrl: string
shortUrlServer: string
c1nToken: string
cfWorkerHost: string
yourlsDomain: string
yourlsSignature: string
isSilentNotice: string
proxy: string
registry: string
autoCopy: string
enableWebServer: string
webServerHost: string
webServerPort: string
webServerPath: string
deleteLocalFile: string
uploadResultNotification: string
uploadNotification: string
useBuiltinClipboard: string
autoStart: string
autoImport: string
autoImportPicBed: string
}
needReload: string
picgoPlugins: string
uploader: string
buildIn: {
compress: string
watermark: string
rename: string
}
debug: string
PICGO_ENV: string
}
export const configPaths: IConfigPaths = {
picBed: {
current: 'picBed.current',
uploader: 'picBed.uploader',
proxy: 'picBed.proxy',
transformer: 'picBed.transformer',
list: 'picBed.list'
},
settings: {
shortKey: {
_path: 'settings.shortKey',
'picgo:upload': 'settings.shortKey[picgo:upload]'
},
logLevel: 'settings.logLevel',
logPath: 'settings.logPath',
logFileSizeLimit: 'settings.logFileSizeLimit',
isAutoListenClipboard: 'settings.isAutoListenClipboard',
isListeningClipboard: 'settings.isListeningClipboard',
showUpdateTip: 'settings.showUpdateTip',
miniWindowPosition: 'settings.miniWindowPosition',
miniWindowOntop: 'settings.miniWindowOntop',
isHideDock: 'settings.isHideDock',
mainWindowWidth: 'settings.mainWindowWidth',
mainWindowHeight: 'settings.mainWindowHeight',
autoCloseMiniWindow: 'settings.autoCloseMiniWindow',
autoCloseMainWindow: 'settings.autoCloseMainWindow',
isCustomMiniIcon: 'settings.isCustomMiniIcon',
customMiniIcon: 'settings.customMiniIcon',
startMode: 'settings.startMode',
autoRename: 'settings.autoRename',
deleteCloudFile: 'settings.deleteCloudFile',
server: 'settings.server',
serverKey: 'settings.serverKey',
pasteStyle: 'settings.pasteStyle',
aesPassword: 'settings.aesPassword',
rename: 'settings.rename',
sync: 'settings.sync',
tempDirPath: 'settings.tempDirPath',
language: 'settings.language',
customLink: 'settings.customLink',
manualPageOpen: 'settings.manualPageOpen',
encodeOutputURL: 'settings.encodeOutputURL',
useShortUrl: 'settings.useShortUrl',
shortUrlServer: 'settings.shortUrlServer',
c1nToken: 'settings.c1nToken',
cfWorkerHost: 'settings.cfWorkerHost',
yourlsDomain: 'settings.yourlsDomain',
yourlsSignature: 'settings.yourlsSignature',
isSilentNotice: 'settings.isSilentNotice',
proxy: 'settings.proxy',
registry: 'settings.registry',
autoCopy: 'settings.autoCopy',
enableWebServer: 'settings.enableWebServer',
webServerHost: 'settings.webServerHost',
webServerPort: 'settings.webServerPort',
webServerPath: 'settings.webServerPath',
deleteLocalFile: 'settings.deleteLocalFile',
uploadResultNotification: 'settings.uploadResultNotification',
uploadNotification: 'settings.uploadNotification',
useBuiltinClipboard: 'settings.useBuiltinClipboard',
autoStart: 'settings.autoStart',
autoImport: 'settings.autoImport',
autoImportPicBed: 'settings.autoImportPicBed'
},
needReload: 'needReload',
picgoPlugins: 'picgoPlugins',
uploader: 'uploader',
buildIn: {
compress: 'buildIn.compress',
watermark: 'buildIn.waterMark',
rename: 'buildIn.rename'
},
debug: 'debug',
PICGO_ENV: 'PICGO_ENV'
}

View File

@ -22,3 +22,5 @@ export const picBedsCanbeDeleted = [
'upyun', 'upyun',
'webdavplist' 'webdavplist'
] ]
export const DEFAULT_AES_PASSWORD = 'aesPassword'

View File

@ -5079,12 +5079,12 @@ axios@^0.27.2:
follow-redirects "^1.14.9" follow-redirects "^1.14.9"
form-data "^4.0.0" form-data "^4.0.0"
axios@^1.6.2: axios@^1.6.8:
version "1.6.2" version "1.6.8"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==
dependencies: dependencies:
follow-redirects "^1.15.0" follow-redirects "^1.15.6"
form-data "^4.0.0" form-data "^4.0.0"
proxy-from-env "^1.1.0" proxy-from-env "^1.1.0"
@ -8382,11 +8382,16 @@ follow-redirects@^1.0.0:
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd"
integrity sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A== integrity sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==
follow-redirects@^1.14.8, follow-redirects@^1.14.9, follow-redirects@^1.15.0, follow-redirects@^1.15.1: follow-redirects@^1.14.8, follow-redirects@^1.14.9, follow-redirects@^1.15.1:
version "1.15.2" version "1.15.2"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
follow-redirects@^1.15.6:
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
for-each@^0.3.3: for-each@^0.3.3:
version "0.3.3" version "0.3.3"
resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
@ -12392,10 +12397,10 @@ performance-now@^2.1.0:
resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
piclist@^1.7.12: piclist@^1.8.3:
version "1.7.12" version "1.8.3"
resolved "https://registry.yarnpkg.com/piclist/-/piclist-1.7.12.tgz#e26e234452dfa9b08c8e2e03896e195b8f74ce88" resolved "https://registry.yarnpkg.com/piclist/-/piclist-1.8.3.tgz#611cab63cdd65f3549a7c11cdfe809357f81b474"
integrity sha512-UZa3tHrhk3iJxXs8kTJyYJFsWW+o0JO2xXL7Xb0wMKkmXsRs2VyjD02cLkhCiYL/lkTmv1tcWWyQYAw3gcJshA== integrity sha512-Gi7J/trUrGDy6ARL8N76eToFWvOxWRLPUl7c6Bf4xJBVGVt6nG7TMIjPh9qzlpT2y2Z9qTmjQ+UOQBsSN5qONg==
dependencies: dependencies:
"@aws-sdk/client-s3" "3.421.0" "@aws-sdk/client-s3" "3.421.0"
"@aws-sdk/lib-storage" "3.421.0" "@aws-sdk/lib-storage" "3.421.0"
@ -12403,7 +12408,7 @@ piclist@^1.7.12:
"@picgo/i18n" "^1.0.0" "@picgo/i18n" "^1.0.0"
"@picgo/store" "^2.1.0" "@picgo/store" "^2.1.0"
"@smithy/node-http-handler" "2.1.6" "@smithy/node-http-handler" "2.1.6"
axios "^1.6.2" axios "^1.6.8"
chalk "^2.4.1" chalk "^2.4.1"
commander "^8.1.0" commander "^8.1.0"
cross-spawn "^7.0.3" cross-spawn "^7.0.3"