Compare commits

..
Author SHA1 Message Date
PiEgg f1817eb1e1 🎉 Release: v2.4.0-beta.10 2025-06-08 10:38:22 +08:00
PiEgg 2bd5d0653b 🐛 Fix: encoded url filename unreadable 2025-06-08 10:37:31 +08:00
PiEgg 9841418779 Feature: finish form uploader for picgo server 2025-06-07 17:09:46 +08:00
PiEgg 7bc70628f9 🔨 Refactor: refactor the form uploader 2025-06-02 17:16:52 +08:00
happy-gameandGitHub a928b4c8ab Feature(server): add support for form upload in PicGo Server (#1327)
ISSUES CLOSED: #428
2025-03-17 09:01:15 +08:00
happy-gameandGitHub 7df37a2526 🐛 Fix: unable to use clip in wayland (#1301) 2024-12-11 17:29:09 +08:00
happy-gameandGitHub dacb926f17 🐛 Fix: auto-copy url can't be turned off (#1300) 2024-12-06 11:35:59 +08:00
PiEgg 1ea074e75f 🎉 Release: v2.4.0-beta.9 2024-12-02 20:02:06 +08:00
PiEgg 04140def7c 🐛 Fix: plugin list search bug
ISSUES CLOSED: #1297
2024-12-02 20:01:15 +08:00
PiEgg c9fe4023f0 🐛 Fix: clipboard filename missing second
ISSUES CLOSED: #1293
2024-11-25 14:51:41 +08:00
PiEgg c8ba547edb 🐛 Fix: copy text bug
ISSUES CLOSED: #1210, #1280
2024-10-05 08:34:04 +08:00
PiEgg 316928edc3 📦 Chore: update ci macos version 2024-07-16 23:03:20 +08:00
PiEgg ff35335126 🎉 Release: v2.4.0-beta.8 2024-07-16 22:58:25 +08:00
PiEgg ff7336b99e 🐛 Fix: tencent cos url encode bug
ISSUES CLOSED: #1265
2024-07-16 22:57:59 +08:00
PiEgg 917ec73027 🎉 Release: v2.4.0-beta.7 2024-04-22 09:53:45 +08:00
PiEgg 8e91582adc 🐛 Fix: config page scroll bug
ISSUES CLOSED: #1237
2024-04-19 09:39:44 +08:00
PiEgg aaec99f466 Feature: add startup mode
ISSUES CLOSED: #915
2024-02-28 15:59:20 +08:00
PiEgg 50e0a64519 🐛 Fix: tray menu open bug
ISSUES CLOSED: #1217
2024-02-25 09:55:41 +08:00
PiEgg 8cede85732 🎉 Release: v2.4.0-beta.6 2023-11-19 09:27:56 +08:00
PiEgg 050a3dd602 🐛 Fix: can't add new config for picbed
ISSUES CLOSED: #1184
2023-10-22 14:00:51 +08:00
木偶andGitHub cd07b33e6b 🐛 Fix: app.asar directroy copy error (#1180)
ISSUES CLOSED: #1179
2023-10-22 13:23:37 +08:00
38 changed files with 538 additions and 110 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-11]
os: [ubuntu-latest, macos-14]
# create steps
steps:
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-11]
os: [ubuntu-latest, macos-14]
# create steps
steps:
+8 -3
View File
@@ -1,6 +1,7 @@
{
"eslint.enable": true,
"eslint.alwaysShowStatus": true,
"eslint.format.enable": true,
"eslint.validate": [
"javascript",
"javascriptreact",
@@ -20,7 +21,11 @@
"stylusSupremacy.sortProperties": "grouped",
"stylusSupremacy.quoteChar": "\"",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": false
}
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"prettier.enable": false,
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
}
+67
View File
@@ -1,3 +1,70 @@
# :tada: 2.4.0-beta.10 (2025-06-08)
### :sparkles: Features
* finish form uploader for picgo server ([9841418](https://github.com/Molunerfinn/PicGo/commit/9841418))
* **server:** add support for form upload in PicGo Server ([#1327](https://github.com/Molunerfinn/PicGo/issues/1327)) ([a928b4c](https://github.com/Molunerfinn/PicGo/commit/a928b4c)), closes [#428](https://github.com/Molunerfinn/PicGo/issues/428)
### :bug: Bug Fixes
* auto-copy url can't be turned off ([#1300](https://github.com/Molunerfinn/PicGo/issues/1300)) ([dacb926](https://github.com/Molunerfinn/PicGo/commit/dacb926))
* encoded url filename unreadable ([2bd5d06](https://github.com/Molunerfinn/PicGo/commit/2bd5d06))
* unable to use clip in wayland ([#1301](https://github.com/Molunerfinn/PicGo/issues/1301)) ([7df37a2](https://github.com/Molunerfinn/PicGo/commit/7df37a2))
# :tada: 2.4.0-beta.9 (2024-12-02)
### :bug: Bug Fixes
* clipboard filename missing second ([c9fe402](https://github.com/Molunerfinn/PicGo/commit/c9fe402)), closes [#1293](https://github.com/Molunerfinn/PicGo/issues/1293)
* copy text bug ([c8ba547](https://github.com/Molunerfinn/PicGo/commit/c8ba547)), closes [#1210](https://github.com/Molunerfinn/PicGo/issues/1210) [#1280](https://github.com/Molunerfinn/PicGo/issues/1280)
* plugin list search bug ([04140de](https://github.com/Molunerfinn/PicGo/commit/04140de)), closes [#1297](https://github.com/Molunerfinn/PicGo/issues/1297)
### :package: Chore
* update ci macos version ([316928e](https://github.com/Molunerfinn/PicGo/commit/316928e))
# :tada: 2.4.0-beta.8 (2024-07-16)
### :bug: Bug Fixes
* tencent cos url encode bug ([ff7336b](https://github.com/Molunerfinn/PicGo/commit/ff7336b)), closes [#1265](https://github.com/Molunerfinn/PicGo/issues/1265)
# :tada: 2.4.0-beta.7 (2024-04-22)
### :sparkles: Features
* add startup mode ([aaec99f](https://github.com/Molunerfinn/PicGo/commit/aaec99f)), closes [#915](https://github.com/Molunerfinn/PicGo/issues/915)
### :bug: Bug Fixes
* config page scroll bug ([8e91582](https://github.com/Molunerfinn/PicGo/commit/8e91582)), closes [#1237](https://github.com/Molunerfinn/PicGo/issues/1237)
* tray menu open bug ([50e0a64](https://github.com/Molunerfinn/PicGo/commit/50e0a64)), closes [#1217](https://github.com/Molunerfinn/PicGo/issues/1217)
# :tada: 2.4.0-beta.6 (2023-11-19)
### :bug: Bug Fixes
* app.asar directroy copy error ([#1180](https://github.com/Molunerfinn/PicGo/issues/1180)) ([cd07b33](https://github.com/Molunerfinn/PicGo/commit/cd07b33)), closes [#1179](https://github.com/Molunerfinn/PicGo/issues/1179)
* can't add new config for picbed ([050a3dd](https://github.com/Molunerfinn/PicGo/commit/050a3dd)), closes [#1184](https://github.com/Molunerfinn/PicGo/issues/1184)
# :tada: 2.4.0-beta.5 (2023-09-10)
+4 -2
View File
@@ -1,6 +1,6 @@
{
"name": "picgo",
"version": "2.4.0-beta.5",
"version": "2.4.0-beta.10",
"private": true,
"scripts": {
"build": "vue-cli-service electron:build",
@@ -34,7 +34,8 @@
"lowdb": "^1.0.0",
"marked": "^7.0.4",
"mitt": "^3.0.0",
"picgo": "^1.5.6",
"multer": "^1.4.5-lts.1",
"picgo": "^1.5.9",
"qrcode.vue": "^3.3.3",
"shell-path": "2.1.0",
"uuid": "^9.0.0",
@@ -54,6 +55,7 @@
"@types/inquirer": "^6.5.0",
"@types/js-yaml": "^4.0.5",
"@types/lowdb": "^1.0.9",
"@types/multer": "^1.4.12",
"@types/node": "^16.10.2",
"@types/request-promise-native": "^1.0.17",
"@types/semver": "^7.3.8",
+10 -6
View File
@@ -1,4 +1,4 @@
LANG_DISPLAY_LABEL: 'English'
LANG_DISPLAY_LABEL: "English"
ABOUT: About
OPEN_MAIN_WINDOW: Open Main Window
CHOOSE_DEFAULT_PICBED: Choose Default Picbed
@@ -28,7 +28,7 @@ OPEN_TOOLBOX: Open Toolbox
# ---renderer i18n begin---
CHOOSE_YOUR_DEFAULT_PICBED: 'Choose ${d} as your default picbed:'
CHOOSE_YOUR_DEFAULT_PICBED: "Choose ${d} as your default picbed:"
UPLOAD_AREA: Upload Area
GALLERY: Gallery
PICBEDS_SETTINGS: Picbeds Settings
@@ -85,7 +85,7 @@ SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD: Auto Copy URL After Upload
SETTINGS_TIPS_PLACEHOLDER_URL: Use $url to represent url position
SETTINGS_TIPS_PLACEHOLDER_FILENAME: Use $fileName to represent file name position
SETTINGS_TIPS_PLACEHOLDER_EXTNAME: Use $extName to represent file's ext position
SETTINGS_TIPS_SUCH_AS: 'Such as: $url/$fileName'
SETTINGS_TIPS_SUCH_AS: "Such as: $url/$fileName"
SETTINGS_UPLOAD_PROXY: Upload Proxy
SETTINGS_PLUGIN_INSTALL_PROXY: Proxy for Plugin Install
SETTINGS_PLUGIN_INSTALL_MIRROR: Mirror for Plugin Install
@@ -121,6 +121,10 @@ UPLOADER_CONFIG_PLACEHOLDER: Please Enter Configuration Name
SELECTED_SETTING_HINT: Selected
SETTINGS_ENCODE_OUTPUT_URL: Encode Output(or Copyed) URL
SETTINGS_SHOW_DOCK_ICON: Show Dock icon
SETTINGS_STARTUP_MODE: Startup Mode
SETTINGS_STARTUP_MODE_MAIN_WINDOW: Open Main Window
SETTINGS_STARTUP_MODE_MINI_WINDOW: Open Mini Window
SETTINGS_STARTUP_MODE_HIDE: Silent Startup
# shortcut-page
@@ -202,10 +206,10 @@ UPDATE_PLUGIN: Update Plugin
# toolbox
TOOLBOX: Toolbox
TOOLBOX_TITLE: Troubleshoot PicGo runtime issues
TOOLBOX_TITLE: Troubleshoot PicGo runtime issues
TOOLBOX_SUB_TITLE: Scan the following items immediately to fix usage issues
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: Check if the configuration file is damaged
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: Check if the album file is damaged
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: Check if the album file is damaged
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: Check if there is a problem with clipboard picture upload
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: Check if the proxy settings are normal
TOOLBOX_FIX_DONE_NEED_RELOAD: Repair completed, need to restart to take effect, restart or not
@@ -236,7 +240,7 @@ TIPS_PLUGIN_OVERWRITE_GALLERY: Plugin is trying to overwrite the album gallery,
TIPS_UPLOAD_NOT_PICTURES: The latest clipboard item is not a picture
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT: PicGo config file broken, has been restored to default
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP: PicGo config file broken, has been restored to backup
TIPS_PICGO_BACKUP_FILE_VERSION: 'Backup file version: ${v}'
TIPS_PICGO_BACKUP_FILE_VERSION: "Backup file version: ${v}"
TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR: Custom config file parse error, please check the path content
TIPS_SHORTCUT_MODIFIED_SUCCEED: Shortcut modified successfully
TIPS_SHORTCUT_MODIFIED_CONFLICT: Shortcut conflict, please reset
+5 -1
View File
@@ -121,6 +121,10 @@ UPLOADER_CONFIG_PLACEHOLDER: 请输入配置名称
SELECTED_SETTING_HINT: 已选中
SETTINGS_ENCODE_OUTPUT_URL: 输出(复制) URL 时进行转义
SETTINGS_SHOW_DOCK_ICON: 显示 Dock 栏图标
SETTINGS_STARTUP_MODE: 启动模式
SETTINGS_STARTUP_MODE_MAIN_WINDOW: 打开主窗口
SETTINGS_STARTUP_MODE_MINI_WINDOW: 打开 Mini 窗口
SETTINGS_STARTUP_MODE_HIDE: 静默启动
# shortcut-page
@@ -236,7 +240,7 @@ TIPS_PLUGIN_OVERWRITE_GALLERY: 有插件正在试图覆盖相册列表,是否
TIPS_UPLOAD_NOT_PICTURES: 剪贴板最新的一条记录不是图片
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT: PicGo 配置文件损坏,已经恢复为默认配置
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP: PicGo 配置文件损坏,已经恢复为备份配置
TIPS_PICGO_BACKUP_FILE_VERSION: '备份文件版本: ${v}'
TIPS_PICGO_BACKUP_FILE_VERSION: "备份文件版本: ${v}"
TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR: 自定义文件解析出错,请检查路径内容是否正确
TIPS_SHORTCUT_MODIFIED_SUCCEED: 快捷键已经修改成功
TIPS_SHORTCUT_MODIFIED_CONFLICT: 快捷键冲突,请重新设置
+11 -7
View File
@@ -121,6 +121,10 @@ UPLOADER_CONFIG_PLACEHOLDER: 請輸入配置名稱
SELECTED_SETTING_HINT: 已選中
SETTINGS_ENCODE_OUTPUT_URL: 輸出(複製) URL 時進行轉義
SETTINGS_SHOW_DOCK_ICON: 顯示 Dock 欄圖示
SETTINGS_STARTUP_MODE: 啟動模式
SETTINGS_STARTUP_MODE_MAIN_WINDOW: 打開主視窗
SETTINGS_STARTUP_MODE_MINI_WINDOW: 打開 Mini 視窗
SETTINGS_STARTUP_MODE_HIDE: 靜默啟動
# shortcut-page
@@ -202,27 +206,27 @@ UPDATE_PLUGIN: 更新插件
# toolbox
TOOLBOX: 工具箱
TOOLBOX_TITLE: 排查 PicGo 執行時問題
TOOLBOX_TITLE: 排查 PicGo 執行時問題
TOOLBOX_SUB_TITLE: 立即掃描以下項目,修復使用問題
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: 檢查配置文件是否損壞
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: 檢查相冊文件是否損壞
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: 檢查剪貼板圖片上傳是否存在問題
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: 檢查代理設置是否正常
TOOLBOX_FIX_DONE_NEED_RELOAD: 修復完成,需要重啓生效,是否重啓
TOOLBOX_CANT_AUTO_FIX: 無法自動修復,請自行修復以下問題
TOOLBOX_CANT_AUTO_FIX: 無法自動修復,請自行修復以下問題
TOOLBOX_START_SCAN: 開始掃描
TOOLBOX_RE_SCAN: 重新掃描
TOOLBOX_START_FIX: 開始修復
TOOLBOX_SUCCESS_TIPS: 恭喜你,沒有檢查出問題
TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS: 配置文件路徑是:${path}
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: 配置文件已損壞
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: 相冊文件路徑是:${path}
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: 配置文件已損壞
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: 相冊文件路徑是:${path}
TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS: 相冊文件已損壞
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: 代理設置正常
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: 代理設置正常
TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS: 無代理設置
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT: 代理設置不正確
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING: 代理設置不可用
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: 剪貼板圖片臨時文件夾路徑是:${path}
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: 剪貼板圖片臨時文件夾路徑是:${path}
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS: 剪貼板圖片臨時文件夾不存在:${path}
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: 請自行創建文件夾:${path}
@@ -236,7 +240,7 @@ TIPS_PLUGIN_OVERWRITE_GALLERY: 有插件正在試圖覆蓋相簿列表,是否
TIPS_UPLOAD_NOT_PICTURES: 剪貼簿最新的一條記錄不是圖片
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT: PicGo 設定檔案已損壞,已經恢復為預設設定
TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP: PicGo 設定檔案已損壞,已經恢復為備份設定
TIPS_PICGO_BACKUP_FILE_VERSION: '備份檔案版本: ${v}'
TIPS_PICGO_BACKUP_FILE_VERSION: "備份檔案版本: ${v}"
TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR: 自訂設定檔案解析出錯,請檢查路徑內容是否正確
TIPS_SHORTCUT_MODIFIED_SUCCEED: 快捷鍵已經修改成功
TIPS_SHORTCUT_MODIFIED_CONFLICT: 快捷鍵衝突,請重新設定
+7 -12
View File
@@ -17,18 +17,13 @@ if [ "$XDG_SESSION_TYPE" = "x11" ]; then
echo $filePath
fi
elif [ "$XDG_SESSION_TYPE" = "wayland" ]; then
command -v wl-copy >/dev/null 2>&1 || { echo >&1 "no wl-clipboard"; exit 1; }
filePath=`wl-copy -o 2>/dev/null | grep ^file:// | cut -c8-`
if [ ! -n "$filePath" ] ;then
if
wl-copy -t image/png -o >/dev/null 2>&1
then
wl-copy -t image/png image/png -o >$1 2>/dev/null
echo $1
else
echo "no image"
fi
command -v wl-paste >/dev/null 2>&1 || { echo >&1 "no wl-clipboard"; exit 1; }
isImage=`wl-paste --list-types | grep image`
if [ -n "$isImage" ]; then
wl-paste --type image/png > $1 2>/dev/null
echo $1
else
echo $filePath
echo "no image"
exit 1
fi
fi
+49 -27
View File
@@ -19,6 +19,7 @@ import { privacyManager } from '~/main/utils/privacyManager'
import { T } from '~/main/i18n'
import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion'
import { buildPicBedListMenu } from '~/main/events/remotes/menu'
import { isLinux, isMacOS } from '~/universal/utils/common'
let contextMenu: Menu | null
let menu: Menu | null
let tray: Tray | null
@@ -137,7 +138,9 @@ export function createContextMenu () {
const getTrayIcon = () => {
if (process.platform === 'darwin') {
const isMacOSGreaterThan11 = isMacOSVersionGreaterThanOrEqualTo('11')
return isMacOSGreaterThan11 ? `${__static}/menubar-newdarwinTemplate.png` : `${__static}/menubar.png`
return isMacOSGreaterThan11
? `${__static}/menubar-newdarwinTemplate.png`
: `${__static}/menubar.png`
} else {
return `${__static}/menubar-nodarwin.png`
}
@@ -153,7 +156,9 @@ export function createTray () {
windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
}
createContextMenu()
tray!.popUpContextMenu(contextMenu!)
setTimeout(() => {
tray!.popUpContextMenu(contextMenu!)
}, 0)
})
tray.on('click', (event, bounds) => {
if (process.platform === 'darwin') {
@@ -174,7 +179,10 @@ export function createTray () {
} else {
if (decodePath !== '') {
// 带有中文的路径,无法直接被img.src所使用,会被转义
const base64 = await fs.readFile(decodePath.replace('file://', ''), { encoding: 'base64' })
const base64 = await fs.readFile(
decodePath.replace('file://', ''),
{ encoding: 'base64' }
)
obj.push({
imgUrl: `data:image/png;base64,${base64}`
})
@@ -190,7 +198,9 @@ export function createTray () {
})
}
}
windowManager.get(IWindowList.TRAY_WINDOW)!.webContents.send('clipboardFiles', obj)
windowManager
.get(IWindowList.TRAY_WINDOW)!
.webContents.send('clipboardFiles', obj)
}, 0)
} else {
if (windowManager.has(IWindowList.TRAY_WINDOW)) {
@@ -229,7 +239,9 @@ export function createTray () {
if (imgs !== false) {
const pasteText: string[] = []
for (let i = 0; i < imgs.length; i++) {
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
pasteText.push(
pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink'))
)
const notification = new Notification({
title: T('UPLOAD_SUCCEED'),
body: imgs[i].imgUrl!
@@ -245,16 +257,16 @@ export function createTray () {
}
})
// toggleWindow()
} else if (process.platform === 'linux') {
// click事件在Ubuntu上无法触发,Unity不支持(在Mac和Windows上可以触发)
// 需要使用 setContextMenu 设置菜单
} else if (isLinux) {
// click事件在Ubuntu上无法触发,Unity不支持(在Mac和Windows上可以触发)
// 需要使用 setContextMenu 设置菜单
createContextMenu()
tray!.setContextMenu(contextMenu)
}
}
export function handleDockIcon () {
if (process.platform === 'darwin') {
if (isMacOS) {
if (db.get('settings.showDockIcon') !== false) {
app.dock.show()
app.dock.setMenu(createContextMenu())
@@ -269,25 +281,35 @@ export function createMenu () {
return menu
}
if (process.env.NODE_ENV !== 'development') {
const template = [{
label: 'Edit',
submenu: [
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
{ type: 'separator' },
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' },
{
label: 'Quit',
accelerator: 'CmdOrCtrl+Q',
click () {
app.quit()
const template = [
{
label: 'Edit',
submenu: [
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
selector: 'redo:'
},
{ type: 'separator' },
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
{
label: 'Select All',
accelerator: 'CmdOrCtrl+A',
selector: 'selectAll:'
},
{
label: 'Quit',
accelerator: 'CmdOrCtrl+Q',
click () {
app.quit()
}
}
}
]
}]
]
}
]
// @ts-ignore
menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
+4 -2
View File
@@ -21,6 +21,7 @@ import path from 'path'
import { privacyManager } from '~/main/utils/privacyManager'
import writeFile from 'write-file-atomic'
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
import { cleanupFormUploaderFiles } from '~/main/utils/cleanupFormUploaderFiles'
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
return new Promise((resolve) => {
@@ -85,7 +86,7 @@ class Uploader {
let name: undefined | string | null
let fileName: string | undefined
if (autoRename) {
fileName = dayjs().add(index, 'ms').format('YYYYMMDDHHmmSSS') + item.extname
fileName = dayjs().add(index, 'ms').format('YYYYMMDDHHmmssSSS') + item.extname
} else {
fileName = item.fileName
}
@@ -126,7 +127,7 @@ class Uploader {
}
const buffer = nativeImage.toPNG()
const baseDir = picgo.baseDir
const fileName = `${dayjs().format('YYYYMMDDHHmmSSS')}.png`
const fileName = `${dayjs().format('YYYYMMDDHHmmssSSS')}.png`
filePath = path.join(baseDir, CLIPBOARD_IMAGE_FOLDER, fileName)
await writeFile(filePath, buffer)
return await this.upload([filePath])
@@ -176,6 +177,7 @@ class Uploader {
return false
} finally {
ipcMain.removeAllListeners(GET_RENAME_FILE_NAME)
cleanupFormUploaderFiles(img)
}
}
}
+18 -2
View File
@@ -5,13 +5,14 @@ import {
RENAME_WINDOW_URL,
TOOLBOX_WINDOW_URL
} from './constants'
import { IWindowList } from '#/types/enum'
import { IStartupMode, IWindowList } from '#/types/enum'
import bus from '@core/bus'
import { CREATE_APP_MENU } from '@core/bus/constants'
import db from '~/main/apis/core/datastore'
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
import { app } from 'electron'
import { T } from '~/main/i18n'
import { isLinux } from '~/universal/utils/common'
// import { URLSearchParams } from 'url'
const windowList = new Map<IWindowList, IWindowListItem>()
@@ -25,6 +26,21 @@ const handleWindowParams = (windowURL: string) => {
return windowURL
}
export const isWindowShouldShowOnStartup = (currentWindow: IWindowList) => {
const startupMode = db.get('settings.startupMode') || (isLinux ? IStartupMode.SHOW_MINI_WINDOW : IStartupMode.HIDE)
switch (currentWindow) {
case IWindowList.MINI_WINDOW: {
return startupMode === IStartupMode.SHOW_MINI_WINDOW
}
case IWindowList.SETTING_WINDOW: {
return startupMode === IStartupMode.SHOW_MAIN_WINDOW
}
default: {
return false
}
}
}
windowList.set(IWindowList.TRAY_WINDOW, {
isValid: process.platform !== 'linux',
multiple: false,
@@ -113,7 +129,7 @@ windowList.set(IWindowList.MINI_WINDOW, {
const obj: IBrowserWindowOptions = {
height: 64,
width: 64,
show: process.platform === 'linux',
show: isLinux,
frame: false,
fullscreenable: false,
skipTaskbar: true,
+12 -1
View File
@@ -5,6 +5,7 @@ import { app as APP } from 'electron'
import { getLogger } from '@core/utils/localLogger'
import dayjs from 'dayjs'
import { T } from '~/main/i18n'
import { FORM_IMAGE_FOLDER } from '~/universal/utils/static'
const STORE_PATH = APP.getPath('userData')
const configFilePath = path.join(STORE_PATH, 'data.json')
const configFileBackupPath = path.join(STORE_PATH, 'data.bak.json')
@@ -131,9 +132,19 @@ function getGalleryDBPath (): {
}
}
function getFormImageFolderPath (): string {
const STORE_PATH = dbPathDir()
const formImagesPath = path.join(STORE_PATH, FORM_IMAGE_FOLDER)
if (!fs.existsSync(formImagesPath)) {
fs.mkdirSync(formImagesPath, { recursive: true })
}
return formImagesPath
}
export {
dbChecker,
dbPathChecker,
dbPathDir,
getGalleryDBPath
getGalleryDBPath,
getFormImageFolderPath
}
+5 -4
View File
@@ -29,7 +29,8 @@ import {
OPEN_WINDOW,
GET_LANGUAGE_LIST,
SET_CURRENT_LANGUAGE,
GET_CURRENT_LANGUAGE
GET_CURRENT_LANGUAGE,
GET_PICBED_CONFIG
} from '#/events/constants'
import { GalleryDB } from 'apis/core/datastore'
@@ -223,14 +224,14 @@ const handleNPMError = (): IDispose => {
}
const handleGetPicBedConfig = () => {
ipcMain.on('getPicBedConfig', (event: IpcMainEvent, type: string) => {
ipcMain.on(GET_PICBED_CONFIG, (event: IpcMainEvent, type: string) => {
const name = picgo.helper.uploader.get(type)?.name || type
if (picgo.helper.uploader.get(type)?.config) {
const _config = picgo.helper.uploader.get(type)!.config!(picgo)
const config = handleConfigWithFunction(_config)
event.sender.send('getPicBedConfig', config, name)
event.sender.send(GET_PICBED_CONFIG, config, name)
} else {
event.sender.send('getPicBedConfig', [], name)
event.sender.send(GET_PICBED_CONFIG, [], name)
}
})
}
+13 -1
View File
@@ -37,6 +37,7 @@ import fixPath from './fixPath'
import { initI18n } from '~/main/utils/handleI18n'
import { remoteNoticeHandler } from 'apis/app/remoteNotice'
import { isMacOS } from '../utils/getMacOSVersion'
import { isWindowShouldShowOnStartup } from '../apis/app/window/windowList'
const isDevelopment = process.env.NODE_ENV !== 'production'
@@ -79,7 +80,7 @@ class LifeCycle {
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e: any) {
console.error('Vue Devtools failed to install:', e.toString())
console.error('Vue Devtools failed to install:', e?.toString())
}
}
windowManager.create(IWindowList.TRAY_WINDOW)
@@ -87,6 +88,17 @@ class LifeCycle {
settingWindow?.once('show', () => {
remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.SETTING_WINDOW_OPEN)
})
if (isWindowShouldShowOnStartup(IWindowList.SETTING_WINDOW)) {
settingWindow?.show()
settingWindow?.focus()
}
if (!isMacOS) {
if (isWindowShouldShowOnStartup(IWindowList.MINI_WINDOW)) {
const miniWindow = windowManager.create(IWindowList.MINI_WINDOW)
miniWindow?.show()
miniWindow?.focus()
}
}
createTray()
handleDockIcon()
db.set('needReload', false)
+3
View File
@@ -7,6 +7,7 @@ import {
import picgo from '@core/picgo'
import logger from '@core/picgo/logger'
import axios from 'axios'
import formUploader from './middlewares/formUploader'
class Server {
private httpServer: http.Server
@@ -56,6 +57,8 @@ class Server {
success: false
}
})
} else if (formUploader.isFileUpload(request)) {
formUploader.handleFileUpload(request, response)
} else {
let body: string = ''
let postObj: IObj
+125
View File
@@ -0,0 +1,125 @@
import http from 'http'
import multer from 'multer'
import path from 'path'
import fs from 'fs'
import { dbPathDir } from 'apis/core/datastore/dbChecker'
import logger from '@core/picgo/logger'
import { handleResponse } from '../utils'
import routers from '../routerManager'
import { FORM_IMAGE_FOLDER } from '~/universal/utils/static'
// Multer 错误类型定义
export interface MulterError extends Error {
code: string
field?: string
storageErrors?: any[]
}
// Multer 中间件适配器类型
export type MulterMiddleware = (
req: http.IncomingMessage,
res: http.ServerResponse,
callback: (error?: MulterError) => void
) => void;
// 扩展 multer 函数的返回类型
declare module 'multer' {
interface Multer {
array(fieldname: string, maxCount?: number): MulterMiddleware;
single(fieldname: string): MulterMiddleware;
fields(fields: { name: string; maxCount?: number }[]): MulterMiddleware;
none(): MulterMiddleware;
}
}
class FormUploader {
private upload!: multer.Multer
private formImagesPath!: string
constructor () {
this.initializeStorage()
this.setupMulter()
}
private initializeStorage () {
const STORE_PATH = dbPathDir()
this.formImagesPath = path.join(STORE_PATH, FORM_IMAGE_FOLDER)
if (!fs.existsSync(this.formImagesPath)) {
fs.mkdirSync(this.formImagesPath, { recursive: true })
}
}
private setupMulter () {
const storage = multer.diskStorage({
destination: (req: http.IncomingMessage, file: Express.Multer.File, cb: (error: Error | null, destination: string) => void) => {
cb(null, this.formImagesPath)
},
filename: (req: http.IncomingMessage, file: Express.Multer.File, cb: (error: Error | null, filename: string) => void) => {
cb(null, file.originalname || Date.now() + path.extname(file.originalname))
}
})
this.upload = multer({
storage
})
}
/**
* 处理文件上传的中间件
*/
public handleFileUpload = (request: http.IncomingMessage, response: http.ServerResponse): void => {
logger.info('[PicGo Server] handling file upload')
this.upload.array('files')(request, response, async (err?: MulterError) => {
if (err) {
logger.error('[PicGo Server] file upload error', err)
return handleResponse({
response,
body: {
success: false,
message: 'File upload failed'
}
})
}
try {
const files = request.files
if (!files || files.length === 0) {
return handleResponse({
response,
body: {
success: false,
message: 'No files were uploaded'
}
})
}
const filePaths = files.map((file) => file.path)
logger.info('[PicGo Server] files uploaded: ' + filePaths.join(', '))
const handler = routers.getHandler(request.url!)
handler!({
list: filePaths,
response
})
} catch (err: any) {
logger.error('[PicGo Server] process upload files error', err)
handleResponse({
response,
body: {
success: false,
message: 'Failed to process uploaded files'
}
})
}
})
}
/**
* 检查请求是否为文件上传
*/
public isFileUpload (request: http.IncomingMessage): boolean {
return !!(request.headers['content-type'] && request.headers['content-type'].includes('multipart/form-data'))
}
}
export default new FormUploader()
+24 -1
View File
@@ -16,6 +16,29 @@ function beforeOpen () {
resolveClipboardImageGenerator()
resolveOtherI18nFiles()
}
function copyFileOutsideOfElectronAsar (
sourceInAsarArchive: string,
destOutsideAsarArchive: string
) {
if (fs.existsSync(sourceInAsarArchive)) {
// file will be copied
if (fs.statSync(sourceInAsarArchive).isFile()) {
const file = destOutsideAsarArchive;
const dir = path.dirname(file)
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true })
}
fs.writeFileSync(file, fs.readFileSync(sourceInAsarArchive))
} else if (fs.statSync(sourceInAsarArchive).isDirectory()) {
fs.readdirSync(sourceInAsarArchive).forEach(function (fileOrFolderName) {
copyFileOutsideOfElectronAsar(
`${sourceInAsarArchive}/${fileOrFolderName}`,
`${destOutsideAsarArchive}/${fileOrFolderName}`
);
});
}
}
}
/**
* macOS 右键菜单
@@ -26,7 +49,7 @@ function resolveMacWorkFlow () {
return true
} else {
try {
fs.copySync(path.join(__static, 'Upload pictures with PicGo.workflow'), dest)
copyFileOutsideOfElectronAsar(path.join(__static, 'Upload pictures with PicGo.workflow'), dest)
} catch (e) {
console.log(e)
}
@@ -0,0 +1,24 @@
import path from 'path'
import fs from 'fs-extra'
import { getFormImageFolderPath } from '@core/datastore/dbChecker'
import logger from '@core/picgo/logger'
export const cleanupFormUploaderFiles = (filePathList?: string[]): void => {
const formImageFolderPath = getFormImageFolderPath()
if (Array.isArray(filePathList)) {
filePathList.forEach(async filePath => {
try {
// 检查文件路径是否在 formImageFolderPath 目录下
const relativePath = path.relative(formImageFolderPath, filePath)
const isWithinFolder = !relativePath.startsWith('..') && !path.isAbsolute(relativePath)
if (isWithinFolder && await fs.pathExists(filePath)) {
await fs.remove(filePath)
logger.info(`[PicGo] Deleted temp file: ${filePath}`)
}
} catch (error: any) {
logger.error(`[PicGo] Failed to delete temp file ${filePath}:`, error)
}
})
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ import { clipboard, Notification, dialog } from 'electron'
import { handleUrlEncode } from '~/universal/utils/common'
export const handleCopyUrl = (str: string): void => {
if (db.get('settings.autoCopy') !== false) {
if (db.get('settings.autoCopyUrl') !== false) {
clipboard.writeText(str)
}
}
+10 -10
View File
@@ -45,13 +45,7 @@ const $route = useRoute()
const $form = ref<IFormInstance>()
const configList = ref<IPicGoPluginConfig[]>([])
const formModel = reactive<IStringKeyMap>({})
watch(toRefs(props.config), (val: IPicGoPluginConfig[]) => {
handleConfig(val)
}, {
deep: true,
immediate: true
})
const isUploader = props.type === 'uploader'
async function validate (): Promise<IStringKeyMap | false> {
const res = await $form.value?.validate() || false
@@ -74,14 +68,13 @@ function getConfigType () {
}
}
const isUploader = props.type === 'uploader'
const handleConfigForm = useConfigForm()
async function handleConfig (inputConfig: IPicGoPluginConfig[]) {
const currentConfig = await getCurConfigFormData()
const resetConfig = isUploader && !$route.params.configId
Object.assign(formModel, currentConfig)
configList.value = handleConfigForm(inputConfig, formModel, currentConfig)
configList.value = handleConfigForm(inputConfig, formModel, currentConfig, resetConfig)
}
async function getCurConfigFormData () {
@@ -101,6 +94,13 @@ async function resetConfig () {
Object.assign(formModel, config)
}
watch(toRefs(props.config), (val: IPicGoPluginConfig[]) => {
handleConfig(val)
}, {
deep: true,
immediate: true
})
defineExpose({
validate,
getConfigType,
+3 -1
View File
@@ -4,13 +4,15 @@ import { cloneDeep, union } from 'lodash'
* @param configList origin config list
* @param formModel el-form form model for default value
* @param currentConfig current config
* @param resetConfigForm reset form model -> clear default value
* @returns transformed config list
*/
export const useConfigForm = () => {
return (configList: IPicGoPluginConfig[], formModel: IStringKeyMap, currentConfig?: IStringKeyMap) => {
return (configList: IPicGoPluginConfig[], formModel: IStringKeyMap, currentConfig?: IStringKeyMap, resetConfigForm?: boolean) => {
if (configList.length > 0) {
return cloneDeep(configList).map((item) => {
// if (!configId) return item
if (resetConfigForm) return item
let defaultValue = item.default !== undefined
? item.default
: item.type === 'checkbox'
+3 -2
View File
@@ -202,6 +202,7 @@ import { T as $T } from '@/i18n/index'
import $$db from '@/utils/db'
import GalleryToolbar from './components/gallery/GalleryToolbar.vue'
import { IRPCActionType } from '~/universal/types/enum'
import { getRawData } from '@/utils/common'
const images = ref<ImgInfo[]>([])
const dialogVisible = ref(false)
const imgInfo = reactive({
@@ -367,7 +368,7 @@ function handleClose () {
}
async function copy (item: ImgInfo) {
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, item)
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, getRawData(item))
const obj = {
title: $T('COPY_LINK_SUCCEED'),
body: copyLink
@@ -498,7 +499,7 @@ async function multiCopy () {
if (selectedList[key]) {
const item = await $$db.getById<ImgInfo>(key)
if (item) {
const txt = await ipcRenderer.invoke(PASTE_TEXT, item)
const txt = await ipcRenderer.invoke(PASTE_TEXT, getRawData(item))
copyString.push(txt)
selectedList[key] = false
}
+6 -3
View File
@@ -48,7 +48,7 @@ import { ElForm } from 'element-plus'
import { Reading } from '@element-plus/icons-vue'
import { IConfig } from 'picgo'
import { T as $T } from '@/i18n/index'
import { enforceNumber } from '~/universal/utils/common'
import { enforceNumber, isLinux } from '~/universal/utils/common'
import { onBeforeMount, reactive, ref } from 'vue'
import { getConfig } from '@/utils/dataSender'
import ButtonAreaSettings from './components/settings/buttonArea/ButtonAreaSettings.vue'
@@ -56,6 +56,7 @@ import SwitchAreaSettings from './components/settings/switchArea/SwitchAreaSetti
import CustomAreaSettings from './components/settings/customArea/CustomAreaSettings.vue'
import SelectAreaSettings from './components/settings/selectArea/SelectAreaSettings.vue'
import { openURL } from '@/utils/common'
import { IStartupMode } from '#/types/enum'
const form = reactive<ISettingForm>({
showUpdateTip: false,
@@ -80,7 +81,8 @@ const form = reactive<ISettingForm>({
port: 36677,
host: '127.0.0.1',
enable: true
}
},
startupMode: IStartupMode.HIDE
})
const proxy = ref('')
@@ -101,7 +103,7 @@ async function initData () {
form.uploadNotification = settings.uploadNotification || false
form.miniWindowOnTop = settings.miniWindowOnTop || false
form.logLevel = initLogLevel(settings.logLevel || [])
form.autoCopyUrl = settings.autoCopy === undefined ? true : settings.autoCopy
form.autoCopyUrl = settings.autoCopyUrl === undefined ? true : settings.autoCopyUrl
form.checkBetaUpdate = settings.checkBetaUpdate === undefined ? true : settings.checkBetaUpdate
form.useBuiltinClipboard = settings.useBuiltinClipboard === undefined ? false : settings.useBuiltinClipboard
form.language = settings.language ?? 'zh-CN'
@@ -113,6 +115,7 @@ async function initData () {
form.server = settings.server
form.logFileSizeLimit = enforceNumber(settings.logFileSizeLimit) || 10
form.showDockIcon = settings.showDockIcon === undefined ? true : settings.showDockIcon
form.startupMode = settings.startupMode || (isLinux ? IStartupMode.SHOW_MINI_WINDOW : IStartupMode.HIDE)
}
}
+1 -1
View File
@@ -485,7 +485,7 @@ function handleSearchResult (item: INPMSearchResultObject) {
return {
name,
fullName: item.package.name,
author: item.package.author.name,
author: item.package.maintainers[0]?.username || '',
description: item.package.description,
logo: `https://cdn.jsdelivr.net/npm/${item.package.name}/logo.png`,
config: {},
+2 -1
View File
@@ -70,6 +70,7 @@ import { IResult } from '@picgo/store/dist/types'
import { PASTE_TEXT, OPEN_WINDOW } from '#/events/constants'
import { IWindowList } from '#/types/enum'
import { sendToMain } from '@/utils/dataSender'
import { getRawData } from '@/utils/common'
const files = ref<IResult<ImgInfo>[]>([])
const notification = reactive({
@@ -92,8 +93,8 @@ async function getData () {
async function copyTheLink (item: ImgInfo) {
notification.body = item.imgUrl!
await ipcRenderer.invoke(PASTE_TEXT, getRawData(item))
const myNotification = new Notification(notification.title, notification)
ipcRenderer.invoke(PASTE_TEXT, item)
myNotification.onclick = () => {
return true
}
+6 -2
View File
@@ -1,5 +1,8 @@
<template>
<div id="config-list-view">
<div
id="config-list-view"
class="h-[425px]"
>
<div class="view-title">
{{ $T('SETTINGS') }}
</div>
@@ -239,9 +242,10 @@ export default {
.selected
border 1px solid #409EFF
.set-default-container
position absolute
position fixed
bottom 20px
width 100%
.set-default-btn
width 250px
transform translateX(-50%)
</style>
@@ -6,6 +6,12 @@
:placeholder="$T('SETTINGS_CHOOSE_LANGUAGE')"
@change="handleLanguageChange"
/>
<SelectFormItem
v-model="form.startupMode"
:list="startupModeList"
:label="$T('SETTINGS_STARTUP_MODE')"
@change="handleChangeStartupMode"
/>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
@@ -13,6 +19,8 @@ import { T as $T, i18nManager } from '@/i18n'
import { saveConfig, sendToMain } from '@/utils/dataSender'
import { GET_PICBEDS } from '~/universal/events/constants'
import SelectFormItem from '@/components/settings/SelectFormItem.vue'
import { IStartupMode } from '~/universal/types/enum'
import { isMacOS } from '~/universal/utils/common'
interface IProps {
settings: ISettingForm
@@ -26,6 +34,22 @@ const languageList = i18nManager.languageList.map(item => ({
value: item.value
}))
const startupModeList = [
{
label: $T('SETTINGS_STARTUP_MODE_MAIN_WINDOW'),
value: IStartupMode.SHOW_MAIN_WINDOW
},
{
label: $T('SETTINGS_STARTUP_MODE_MINI_WINDOW'),
value: IStartupMode.SHOW_MINI_WINDOW,
hide: isMacOS
},
{
label: $T('SETTINGS_STARTUP_MODE_HIDE'),
value: IStartupMode.HIDE
}
].filter(item => !item.hide)
function handleLanguageChange (val: string) {
i18nManager.setCurrentLanguage(val)
saveConfig({
@@ -34,6 +58,12 @@ function handleLanguageChange (val: string) {
sendToMain(GET_PICBEDS)
}
function handleChangeStartupMode (val: IStartupMode) {
saveConfig({
'settings.startupMode': val
})
}
</script>
<script lang="ts">
export default {
+6 -8
View File
@@ -43,16 +43,17 @@
</template>
<script lang="ts" setup>
import { IRPCActionType } from '~/universal/types/enum'
import { ref, onBeforeUnmount, onBeforeMount } from 'vue'
import { ref, onBeforeMount } from 'vue'
import { T as $T } from '@/i18n/index'
import { sendToMain, triggerRPC } from '@/utils/dataSender'
import { useRoute, useRouter } from 'vue-router'
import ConfigForm from '@/components/ConfigForm.vue'
// import mixin from '@/utils/ConfirmButtonMixin'
import {
ipcRenderer,
IpcRendererEvent
} from 'electron'
import { GET_PICBED_CONFIG } from '~/universal/events/constants'
import { useIPCOn } from '@/hooks/useIPC'
const type = ref('')
const config = ref<IPicGoPluginConfig[]>([])
const picBedName = ref('')
@@ -61,9 +62,10 @@ const $router = useRouter()
const $configForm = ref<InstanceType<typeof ConfigForm> | null>(null)
type.value = $route.params.type as string
useIPCOn(GET_PICBED_CONFIG, getPicBeds)
onBeforeMount(() => {
sendToMain('getPicBedConfig', $route.params.type)
ipcRenderer.on('getPicBedConfig', getPicBeds)
sendToMain(GET_PICBED_CONFIG, $route.params.type)
})
const handleConfirm = async () => {
@@ -85,10 +87,6 @@ function getPicBeds (event: IpcRendererEvent, _config: IPicGoPluginConfig[], nam
picBedName.value = name
}
onBeforeUnmount(() => {
ipcRenderer.removeListener('getPicBedConfig', getPicBeds)
})
</script>
<script lang="ts">
export default {
+1
View File
@@ -36,6 +36,7 @@ export const FORCE_UPDATE = 'FORCE_UPDATE'
export const OPEN_WINDOW = 'OPEN_WINDOW'
export const GET_PICBEDS = 'GET_PICBEDS'
export const RPC_ACTIONS = 'RPC_ACTIONS'
export const GET_PICBED_CONFIG = 'GET_PICBED_CONFIG'
// i18n
export const GET_CURRENT_LANGUAGE = 'GET_CURRENT_LANGUAGE'
export const GET_LANGUAGE_LIST = 'GET_LANGUAGE_LIST'
+6
View File
@@ -92,3 +92,9 @@ export enum IToolboxItemCheckStatus {
SUCCESS = 'success',
ERROR = 'error',
}
export enum IStartupMode {
SHOW_MAIN_WINDOW = 'SHOW_SETTING_WINDOW',
SHOW_MINI_WINDOW = 'SHOW_MINI_WINDOW',
HIDE = 'HIDE'
}
+14
View File
@@ -7,3 +7,17 @@ declare var notificationList: IAppNotification[]
declare module 'epipebomb' {
export default function epipebomb(stream: NodeJS.Process['stdout'], callback: () => void): void
}
// 扩展原生 IncomingMessage,添加 multer 字段
declare module 'http' {
interface IncomingMessage {
files?: {
path: string;
originalname: string;
mimetype: string;
size: number;
[key: string]: any;
}[];
body?: any;
}
}
+4
View File
@@ -116,6 +116,10 @@ interface ILocales {
SELECTED_SETTING_HINT: string
SETTINGS_ENCODE_OUTPUT_URL: string
SETTINGS_SHOW_DOCK_ICON: string
SETTINGS_STARTUP_MODE: string
SETTINGS_STARTUP_MODE_MAIN_WINDOW: string
SETTINGS_STARTUP_MODE_MINI_WINDOW: string
SETTINGS_STARTUP_MODE_HIDE: string
SHORTCUT_NAME: string
SHORTCUT_BIND: string
SHORTCUT_STATUS: string
+4 -3
View File
@@ -213,9 +213,10 @@ interface INPMSearchResultObject {
version: string
description: string
keywords: string[]
author: {
name: string
}
maintainers: Array<{
email: string
username: string
}>
links: {
npm: string
homepage: string
+1
View File
@@ -22,6 +22,7 @@ interface ISettingForm {
host: string
enable: boolean
}
startupMode: import('#/types/enum').IStartupMode
}
interface IShortKeyMap {
+4
View File
@@ -51,3 +51,7 @@ export const trimValues = (obj: IStringKeyMap) => {
})
return newObj
}
export const isMacOS = process.platform === 'darwin'
export const isWindows = process.platform === 'win32'
export const isLinux = process.platform === 'linux'
+1
View File
@@ -1,4 +1,5 @@
export const CLIPBOARD_IMAGE_FOLDER = 'picgo-clipboard-images'
export const FORM_IMAGE_FOLDER = 'picgo-form-images'
export const RELEASE_URL = 'https://api.github.com/repos/Molunerfinn/PicGo/releases'
export const RELEASE_URL_BACKUP = 'https://picgo-release.molunerfinn.com'
export const STABLE_RELEASE_URL = 'https://github.com/Molunerfinn/PicGo/releases/latest'
+44 -7
View File
@@ -2906,6 +2906,13 @@
resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/multer@^1.4.12":
version "1.4.12"
resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.12.tgz#da67bd0c809f3a63fe097c458c0d4af1fea50ab7"
integrity sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==
dependencies:
"@types/express" "*"
"@types/node@*", "@types/node@^14.6.2", "@types/node@^16.10.2":
version "16.11.18"
resolved "https://registry.npmjs.org/@types/node/-/node-16.11.18.tgz#39ed7c52943b0cee6d7299b717707bd51b1f90b9"
@@ -3950,6 +3957,11 @@ app-builder-lib@23.3.3:
tar "^6.1.11"
temp-file "^3.4.0"
append-field@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==
arch@^2.1.1:
version "2.2.0"
resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
@@ -4472,6 +4484,13 @@ builtins@^5.0.1:
dependencies:
semver "^7.0.0"
busboy@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
dependencies:
streamsearch "^1.1.0"
bytes@3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@@ -5019,7 +5038,7 @@ concat-map@0.0.1:
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
concat-stream@^1.6.2:
concat-stream@^1.5.2, concat-stream@^1.6.2:
version "1.6.2"
resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
@@ -9344,6 +9363,19 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
multer@^1.4.5-lts.1:
version "1.4.5-lts.1"
resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.5-lts.1.tgz#803e24ad1984f58edffbc79f56e305aec5cfd1ac"
integrity sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==
dependencies:
append-field "^1.0.0"
busboy "^1.0.0"
concat-stream "^1.5.2"
mkdirp "^0.5.4"
object-assign "^4.1.1"
type-is "^1.6.4"
xtend "^4.0.0"
multicast-dns@^7.2.5:
version "7.2.5"
resolved "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced"
@@ -9539,7 +9571,7 @@ number-is-nan@^1.0.0:
resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
object-assign@^4.0.1, object-assign@^4.1.0:
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
@@ -9986,10 +10018,10 @@ pend@~1.2.0:
resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
picgo@^1.5.6:
version "1.5.6"
resolved "https://registry.npmmirror.com/picgo/-/picgo-1.5.6.tgz#77e0422ed291ee8dd978b34aabb5cede61557e13"
integrity sha512-eJ+Jevv30TlIjkOO/rg1MNou8eYOeRADBZVUxuYnfXomuFVestm+IZoufHIUQlqAgf3bYprRnXRLImhs21JETQ==
picgo@^1.5.9:
version "1.5.9"
resolved "https://registry.yarnpkg.com/picgo/-/picgo-1.5.9.tgz#2ff46958c3f53203d7d13b870a1ae4be90aaa3e3"
integrity sha512-6jO53RdHBP9tl9w6fwm+WtlU6qeYMsZAH9HsXZDkyXqQYMRdQ7t2K4BXZo3DQJ76ebYD40fDHAaIW92k7m2A0w==
dependencies:
"@picgo/i18n" "^1.0.0"
"@picgo/store" "^2.0.2"
@@ -11580,6 +11612,11 @@ stream-browserify@3.0.0:
inherits "~2.0.4"
readable-stream "^3.5.0"
streamsearch@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
@@ -12210,7 +12247,7 @@ type-fest@^0.8.1:
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
type-is@~1.6.18:
type-is@^1.6.4, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==