Compare commits

...
Author SHA1 Message Date
PiEgg 09ee0947cd 🎉 Release: v2.3.1-beta.5 2022-08-14 23:04:01 +08:00
PiEgg 351fbdaa26 📦 Chore: update manually action 2022-08-14 23:01:50 +08:00
PiEgg c926414839 Feature: add dist upload to cos & update checkupdate logic 2022-08-14 20:46:22 +08:00
PiEgg dc85123bde ⬆️ Upgrade: update electron-builder version 2022-08-14 08:38:07 +08:00
PiEgg 83ab3c6db7 Feature: tray-window add open-setting-window button 2022-08-12 17:06:29 +08:00
PiEgg 87161b3ee0 📦 Chore: update macOS tray icon 2022-08-08 15:03:51 +08:00
PiEgg 4ebdc721e4 Feature: update tray icon in macOS 11 or 12
ISSUES CLOSED: #776
2022-08-07 22:34:26 +08:00
PiEgg dee40a6bcd 🚧 WIP: add new macos tray icon 2022-08-01 21:28:39 +08:00
PiEgg 09e4e82ca9 🐛 Fix: plugin config can't save
ISSUES CLOSED: #943
2022-07-31 18:24:13 +08:00
PiEgg 219b367f7c Feature: add logFileSizeLimit for log file
ISSUES CLOSED: #935, #945
2022-07-31 17:47:15 +08:00
PiEgg 3102d7b1ea 📝 Docs: update cos links 2022-07-17 11:52:14 +08:00
fb69bad2cf Feature: add server response headers for CORS (#939)
Co-authored-by: long <iamlongalong@gmail.com>
2022-07-16 10:36:00 +08:00
PiEgg 0a9e1692ee 📦 Chore: fix version error 2022-06-12 20:36:57 +08:00
PiEgg 1db84a2e14 🐛 Fix: build error 2022-06-12 20:25:03 +08:00
PiEgg e6b9d8853e 📦 Chore: fix github action build scripts 2022-06-12 20:23:02 +08:00
PiEgg c3b0f5b759 🎉 Release: v2.3.1-beta.4 2022-06-12 20:20:46 +08:00
PiEgg d3bb5caa83 🐛 Fix(db): fix some db bugs
#873,#806
2022-06-12 20:20:08 +08:00
PiEgg 8d861be161 🐛 Fix(gallery): can't copy gallery pics link
ISSUES CLOSED: #901
2022-06-12 12:30:28 +08:00
PiEgg a79efbfcc3 📝 Docs: update FAQ 2022-04-05 19:18:22 +08:00
PiEgg 746635ec3f 📝 Docs: update readme & FAQ 2022-04-05 11:22:50 +08:00
PiEgg db6c5b8751 📦 Chore: add issue template 2022-04-05 11:00:00 +08:00
PiEgg 5d0646995e 📝 Docs: fix electron_mirror link error
ISSUES CLOSED: #849
2022-04-04 19:55:02 +08:00
PiEgg b3c2ed9e13 🎉 Release: v2.3.1-beta.3 2022-04-04 19:24:17 +08:00
PiEgg af291e4f11 Feature: add tencent-cos options for url
ISSUES CLOSED: #862, #863, #865, #524, #845, #732
2022-04-04 19:22:30 +08:00
zhullybandPiEgg f1c8507927 Feature: add wayland support for linux 2022-03-14 23:57:37 +08:00
PiEgg 6bcda9ba28 📝 Docs: update readme
ISSUES CLOSED: #849, #850
2022-03-10 22:13:24 +08:00
PiEgg 1936ccfedc Feature: add i18n for en 2022-02-20 21:33:44 +08:00
PiEgg 7f6d58f992 🔨 Refactor: setting-page ui 2022-02-20 17:37:40 +08:00
PiEgg 27628da458 Feature: add upload-clipboard-image from electron' clipboard
ISSUES CLOSED: #822
2022-02-20 12:35:27 +08:00
PiEgg 6bcd019b31 🐛 Fix: fix mini-page can't upload image from dragging browser image
ISSUES CLOSED: #822
2022-02-20 12:33:51 +08:00
Wave-SYJandPiEgg c79a2869c1 🐛 Fix: mini window not always on top after reopen 2022-01-20 21:01:36 +08:00
PiEgg 1212774b3d 🚧 WIP: renderer process i18n 2022-01-19 23:21:17 +08:00
PiEgg be32ed0e52 🚧 WIP: renderer i18n 2022-01-18 23:10:49 +08:00
PiEgg cc73fe7bce 🚧 WIP: renderer process i18n 2022-01-18 16:06:33 +08:00
PiEgg 3a503151a4 🐛 Fix: notification freeze the main-process after uploading with clipboard
ISSUES CLOSED: #824
2022-01-16 20:22:23 +08:00
PiEgg 58f96db967 🚧 WIP: renderer i18n 2022-01-13 23:03:41 +08:00
PiEgg 6b6ae271e8 🐛 Fix: picgo.log path error
ISSUES CLOSED: #819
2022-01-12 14:57:09 +08:00
PiEgg 9d236ba6f4 🚧 WIP: renderer process i18n 2022-01-11 23:57:35 +08:00
PiEgg c19f741243 🚧 WIP: main process i18n 2022-01-11 21:50:29 +08:00
PiEgg c2991dde2f 🚧 WIP: add i18n ing 2022-01-10 10:20:56 +08:00
PiEgg 04701d4202 Feature: click cancel in rename-window will use origin filename now
ISSUES CLOSED: #791
2022-01-09 11:21:04 +08:00
PiEgg bcaf255a9c 📦 Chore: update fix-path
ISSUES CLOSED: #774
2022-01-09 10:11:14 +08:00
PiEgg 43d2a8e5c8 📦 Chore: types change 2022-01-08 15:44:25 +08:00
95 changed files with 2648 additions and 932 deletions
-34
View File
@@ -1,34 +0,0 @@
<!--
PicGo Issue 模板
请依照该模板来提交,否则将会被关闭。
**提问之前请注意你看过 FAQ、配置手册以及那些被关闭的 issues。否则同样的提问也会被关闭!**
-->
**声明:我已经仔细看过 [文档](https://picgo.github.io/PicGo-Doc/)、[FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md)、和搜索过已经关闭的 [issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed) 后依然没有找到答案,所以才发了一个新的 issue。**
## 问题类型
<!-- 你要提交的是 Bug Report 还是 Feature Request-->
## PicGo 的相关信息
<!-- PicGo 的版本、所在平台(Mac 或者 Windows 或者 Linux -->
## 问题重现
<!-- 如果是 Bug Report 请填写本项 -->
<!-- 请附上相关截图 -->
<!-- 请附上 PicGo 的相关报错日志(用文本的形式)否则无法判断原因-->
<!-- 报错日志可以在 PicGo 设置 -> 设置日志文件 -> 点击打开 后找到 -->
## 功能请求
<!-- 如果是 Feature Request 请填写本项 -->
<!-- 详细描述你所预想的功能或者是现有功能的改进。 -->
---
<!--
最后,喜欢 PicGo 的话不妨给它点个 star~
如果可以的话,请我喝杯咖啡?首页有赞助二维码,谢谢你的支持!
-->
+67
View File
@@ -0,0 +1,67 @@
name: "🐛 Bug Report"
description: 提交一个问题 / Report a bug
title: "[Bug]: "
labels: ["bug"]
assignees:
- molunerfinn
body:
- type: markdown
attributes:
value: |+
## PicGo Issue 模板
请依照该模板来提交,否则将会被关闭。
**提问之前请注意你看过 FAQ、文档以及那些被关闭的 issues。否则同样的提问也会被关闭!**
Please submit according to this template, otherwise it will be closed.
**Before asking a question, please note that you have read the FAQ, Doc, and those closed issues. Otherwise the same question will also be closed! **
- type: checkboxes
id: read
attributes:
label: 前置阅读 | Pre-reading
description: 我已经自行查找、阅读以下内容(阅读了请打勾) | I have searched and read the following on my own (Please tick after reading)
options:
- label: "[文档/Doc](https://picgo.github.io/PicGo-Doc/)"
required: true
- label: "[Issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed)"
required: true
- label: "[FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md)"
required: true
- type: input
id: version
attributes:
label: PicGo的版本 | PicGo Version
placeholder: 例如 v2.3.0-beta.1
validations:
required: true
- type: dropdown
id: platform
attributes:
label: 系统信息 | System Information
options:
- Windows
- Mac
- Mac(arm64)
- Linux
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: 问题重现 | Bug reproduce
description: 请复述Bug重现流程,必要时附图 | Please tell me the bug reproduction process, attach pictures if necessary
validations:
required: true
- type: textarea
id: log
attributes:
label: 相关日志 | Logs
description: 请附上 PicGo 的相关报错日志(用文本的形式)。报错日志可以在 PicGo 设置 -> 设置日志文件 -> 点击打开 后找到 | Please attach PicGo's relevant error log (in text form). The error log can be found in PicGo Settings -> Set Log File -> Click to Open
- type: markdown
attributes:
value: |
最后,喜欢 PicGo 的话不妨给它点个 star~
如果可以的话,请我喝杯咖啡?首页有赞助二维码,谢谢你的支持!
Finally, if you like PicGo, give it a star~
Buy me a cup of coffee if you can? There is a sponsorship QR code on the homepage, thank you for your support!
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
@@ -0,0 +1,62 @@
name: "✨ Feature Request"
description: 功能请求 / Feature request
title: "[Feature]: "
labels: ["feature request"]
assignees:
- molunerfinn
body:
- type: markdown
attributes:
value: |+
## PicGo Issue 模板
请依照该模板来提交,否则将会被关闭。
**提问之前请注意你看过 FAQ、文档以及那些被关闭的 issues。否则同样的提问也会被关闭!**
Please submit according to this template, otherwise it will be closed.
**Before asking a question, please note that you have read the FAQ, Doc, and those closed issues. Otherwise the same question will also be closed! **
- type: checkboxes
id: read
attributes:
label: 前置阅读 | Pre-reading
description: 我已经自行查找、阅读以下内容(阅读了请打勾) | I have searched and read the following on my own (Please tick after reading)
options:
- label: "[文档/Doc](https://picgo.github.io/PicGo-Doc/)"
required: true
- label: "[Issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed)"
required: true
- label: "[FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md)"
required: true
- type: input
id: version
attributes:
label: PicGo的版本 | PicGo Version
placeholder: 例如 v2.3.0-beta.1
validations:
required: true
- type: dropdown
id: platform
attributes:
label: 系统信息 | System Information
options:
- Windows
- Mac
- Mac(arm64)
- Linux
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: 功能请求 | Feature request
description: 详细描述你所预想的功能或者是现有功能的改进 | Describe in detail the features you envision or improvements to existing features
validations:
required: true
- type: markdown
attributes:
value: |
最后,喜欢 PicGo 的话不妨给它点个 star~
如果可以的话,请我喝杯咖啡?首页有赞助二维码,谢谢你的支持!
Finally, if you like PicGo, give it a star~
Buy me a cup of coffee if you can? There is a sponsorship QR code on the homepage, thank you for your support!
+4 -1
View File
@@ -35,7 +35,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
node-version: '16.x'
- name: Install system deps
if: matrix.os == 'ubuntu-latest'
@@ -51,5 +51,8 @@ jobs:
- name: Build & release app
run: |
yarn release
yarn upload-dist
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
PICGO_ENV_COS_SECRET_ID: ${{ secrets.PICGO_ENV_COS_SECRET_ID }}
PICGO_ENV_COS_SECRET_KEY: ${{ secrets.PICGO_ENV_COS_SECRET_KEY }}
+4 -1
View File
@@ -32,7 +32,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
node-version: '16.x'
- name: Install system deps
if: matrix.os == 'ubuntu-latest'
@@ -48,5 +48,8 @@ jobs:
- name: Build & release app
run: |
yarn release
yarn upload-dist
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
PICGO_ENV_COS_SECRET_ID: ${{ secrets.PICGO_ENV_COS_SECRET_ID }}
PICGO_ENV_COS_SECRET_KEY: ${{ secrets.PICGO_ENV_COS_SECRET_KEY }}
+2
View File
@@ -17,3 +17,5 @@ docs/dist/
.env.*.local
dist_electron/
test.js
.env
scripts/*.yml
+23 -25
View File
@@ -1,38 +1,36 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"name": "Electron: Main",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/src/main/index.dev.js",
"env": {
"DEBUG_ENV": "debug"
},
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceRoot}",
// this points to the electron task runner
"protocol": "inspector",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"runtimeArgs": [
"--nolazy"
],
"sourceMaps": true
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
},
"preLaunchTask": "electron-debug",
"args": ["--remote-debugging-port=9223", "./dist_electron"],
"outFiles": ["${workspaceFolder}/dist_electron/**/*.js"]
},
{
"name": "Attach",
"type": "node",
"name": "Electron: Renderer",
"type": "chrome",
"request": "attach",
"port": 5858,
"sourceMaps": true,
"restart": true,
"outFiles": [],
"localRoot": "${workspaceRoot}",
"protocol": "inspector",
"remoteRoot": null
"port": 9223,
"urlFilter": "http://localhost:*",
"timeout": 30000,
"webRoot": "${workspaceFolder}/src",
"sourceMapPathOverrides": {
"webpack:///./src/*": "${webRoot}/*"
}
}
],
"compounds": [
{
"name": "Electron: All",
"configurations": ["Electron: Main", "Electron: Renderer"]
}
]
}
+27
View File
@@ -0,0 +1,27 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "electron-debug",
"type": "process",
"command": "./node_modules/.bin/vue-cli-service",
"windows": {
"command": "./node_modules/.bin/vue-cli-service.cmd"
},
"isBackground": true,
"args": ["electron:serve", "--debug"],
"problemMatcher": {
"owner": "custom",
"pattern": {
"regexp": ""
},
"background": {
"beginsPattern": "Starting development server\\.\\.\\.",
"endsPattern": "Not launching electron as debug argument was passed\\."
}
}
}
]
}
+86
View File
@@ -1,3 +1,89 @@
## :tada: 2.3.1-beta.5 (2022-08-14)
### :sparkles: Features
* add dist upload to cos & update checkupdate logic ([c926414](https://github.com/Molunerfinn/PicGo/commit/c926414))
* add logFileSizeLimit for log file ([219b367](https://github.com/Molunerfinn/PicGo/commit/219b367)), closes [#935](https://github.com/Molunerfinn/PicGo/issues/935) [#945](https://github.com/Molunerfinn/PicGo/issues/945)
* add server response headers for CORS ([#939](https://github.com/Molunerfinn/PicGo/issues/939)) ([fb69bad](https://github.com/Molunerfinn/PicGo/commit/fb69bad))
* tray-window add open-setting-window button ([83ab3c6](https://github.com/Molunerfinn/PicGo/commit/83ab3c6))
* update tray icon in macOS 11 or 12 ([4ebdc72](https://github.com/Molunerfinn/PicGo/commit/4ebdc72)), closes [#776](https://github.com/Molunerfinn/PicGo/issues/776)
### :bug: Bug Fixes
* build error ([1db84a2](https://github.com/Molunerfinn/PicGo/commit/1db84a2))
* plugin config can't save ([09e4e82](https://github.com/Molunerfinn/PicGo/commit/09e4e82)), closes [#943](https://github.com/Molunerfinn/PicGo/issues/943)
### :package: Chore
* fix github action build scripts ([e6b9d88](https://github.com/Molunerfinn/PicGo/commit/e6b9d88))
* fix version error ([0a9e169](https://github.com/Molunerfinn/PicGo/commit/0a9e169))
* update macOS tray icon ([87161b3](https://github.com/Molunerfinn/PicGo/commit/87161b3))
* update manually action ([351fbda](https://github.com/Molunerfinn/PicGo/commit/351fbda))
### :pencil: Documentation
* update cos links ([3102d7b](https://github.com/Molunerfinn/PicGo/commit/3102d7b))
## :tada: 2.3.1-beta.4 (2022-06-12)
### :bug: Bug Fixes
* **db:** fix some db bugs ([d3bb5ca](https://github.com/Molunerfinn/PicGo/commit/d3bb5ca)), closes [#873](https://github.com/Molunerfinn/PicGo/issues/873) [#806](https://github.com/Molunerfinn/PicGo/issues/806)
* **gallery:** can't copy gallery pics link ([8d861be](https://github.com/Molunerfinn/PicGo/commit/8d861be)), closes [#901](https://github.com/Molunerfinn/PicGo/issues/901)
### :pencil: Documentation
* fix electron_mirror link error ([5d06469](https://github.com/Molunerfinn/PicGo/commit/5d06469)), closes [#849](https://github.com/Molunerfinn/PicGo/issues/849)
* update FAQ ([a79efbf](https://github.com/Molunerfinn/PicGo/commit/a79efbf))
* update readme & FAQ ([746635e](https://github.com/Molunerfinn/PicGo/commit/746635e))
### :package: Chore
* add issue template ([db6c5b8](https://github.com/Molunerfinn/PicGo/commit/db6c5b8))
## :tada: 2.3.1-beta.3 (2022-04-04)
### :sparkles: Features
* add i18n for en ([1936ccf](https://github.com/Molunerfinn/PicGo/commit/1936ccf))
* add tencent-cos options for url ([af291e4](https://github.com/Molunerfinn/PicGo/commit/af291e4)), closes [#862](https://github.com/Molunerfinn/PicGo/issues/862) [#863](https://github.com/Molunerfinn/PicGo/issues/863) [#865](https://github.com/Molunerfinn/PicGo/issues/865) [#524](https://github.com/Molunerfinn/PicGo/issues/524) [#845](https://github.com/Molunerfinn/PicGo/issues/845) [#732](https://github.com/Molunerfinn/PicGo/issues/732)
* add upload-clipboard-image from electron' clipboard ([27628da](https://github.com/Molunerfinn/PicGo/commit/27628da)), closes [#822](https://github.com/Molunerfinn/PicGo/issues/822)
* add wayland support for linux ([f1c8507](https://github.com/Molunerfinn/PicGo/commit/f1c8507))
* click cancel in rename-window will use origin filename now ([04701d4](https://github.com/Molunerfinn/PicGo/commit/04701d4)), closes [#791](https://github.com/Molunerfinn/PicGo/issues/791)
### :bug: Bug Fixes
* fix mini-page can't upload image from dragging browser image ([6bcd019](https://github.com/Molunerfinn/PicGo/commit/6bcd019)), closes [#822](https://github.com/Molunerfinn/PicGo/issues/822)
* mini window not always on top after reopen ([c79a286](https://github.com/Molunerfinn/PicGo/commit/c79a286))
* notification freeze the main-process after uploading with clipboard ([3a50315](https://github.com/Molunerfinn/PicGo/commit/3a50315)), closes [#824](https://github.com/Molunerfinn/PicGo/issues/824)
* picgo.log path error ([6b6ae27](https://github.com/Molunerfinn/PicGo/commit/6b6ae27)), closes [#819](https://github.com/Molunerfinn/PicGo/issues/819)
### :pencil: Documentation
* update readme ([6bcda9b](https://github.com/Molunerfinn/PicGo/commit/6bcda9b)), closes [#849](https://github.com/Molunerfinn/PicGo/issues/849) [#850](https://github.com/Molunerfinn/PicGo/issues/850)
### :package: Chore
* types change ([43d2a8e](https://github.com/Molunerfinn/PicGo/commit/43d2a8e))
* update fix-path ([bcaf255](https://github.com/Molunerfinn/PicGo/commit/bcaf255)), closes [#774](https://github.com/Molunerfinn/PicGo/issues/774)
## :tada: 2.3.1-beta.2 (2022-01-06)
+9
View File
@@ -61,3 +61,12 @@ PicGo 在 Mac 上是一个顶部栏应用,在 dock 栏是不会有图标的。
## 10. macOS版本安装完之后没有主界面
请找到PicGo在顶部栏的图标,然后右键(触摸板双指点按,或者鼠标右键),即可找到「打开详细窗口」的菜单。
## 11. 相册突然无法显示图片或者上传后相册不更新
这个原因可能是相册存储文件损坏导致的。可以找到 PicGo 配置文件所在路径下的 `picgo.db` ,将其删掉(删掉前建议备份一遍),再重启 PicGo 试试。
注意同时看看日志文件里有没有什么error,必要时可以提issue。
## 12. Gitee相关问题
如果在使用 Gitee 图床的时候遇到上传的问题,由于 PicGo 并没有官方提供 Gitee 上传服务,无法帮你解决,请去你所使用的 Gitee 插件仓库发相关的issue。
+6 -7
View File
@@ -6,7 +6,7 @@
<img src="https://img.shields.io/badge/code%20style-standard-green.svg?style=flat-square" alt="">
</a>
<a href="https://github.com/Molunerfinn/PicGo/actions">
<img src="https://github.com/Molunerfinn/PicGo/workflows/Build/badge.svg" alt="">
<img src="https://github.com/Molunerfinn/PicGo/actions/workflows/main.yml/badge.svg" alt="">
</a>
<a href="https://github.com/Molunerfinn/PicGo/releases">
<img src="https://img.shields.io/github/downloads/Molunerfinn/PicGo/total.svg?style=flat-square" alt="">
@@ -17,9 +17,6 @@
<a href="https://github.com/PicGo/bump-version">
<img src="https://img.shields.io/badge/picgo-convention-blue.svg?style=flat-square" alt="">
</a>
<a href="https://gitter.im/picgo-all/PicGo?utm_source=share-link&utm_medium=link&utm_campaign=share-link">
<img src="https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-66ae93.svg?style=flat-square" alt="">
</a>
</div>
## 应用概述
@@ -57,7 +54,9 @@ PicGo 本体支持如下图床:
## 下载安装
点击此处下载 [应用](https://github.com/Molunerfinn/PicGo/releases)。
点击此处下载 [应用](https://github.com/Molunerfinn/PicGo/releases)。从 2.3.1-beta.4 版本开始,在下载页提供 [腾讯云COS](https://cloud.tencent.com/product/cos) 下载链接,供国内用户快速下载使用。感谢 [腾讯云COS](https://cloud.tencent.com/product/cos) 提供的赞助支持!
还可以通过山东大学镜像站提供的镜像地址下载 [应用](https://mirrors.sdu.edu.cn/github-release/Molunerfinn_PicGo)。感谢山东大学镜像站提供的镜像服务!
### Windows
@@ -116,8 +115,8 @@ npm run electron:serve # 重新进入开发模式
**注意**:如果你的网络环境不太好,可能会出现 `electron-builder` 下载 `electron` 二进制文件失败的情况。这个时候需要在 `npm run electron:build` 之前指定一下 `electron` 的源为国内源:
```bash
export ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/"
# 在 Windows 上,则可以使用 set ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/ (无需引号)
export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/"
# 在 Windows 上,则可以使用 set ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ (无需引号)
npm run electron:build
```
+1
View File
@@ -27,5 +27,6 @@ install:
build_script:
#- yarn test
- yarn release
- yarn upload-dist
test: false
+16 -7
View File
@@ -1,6 +1,6 @@
{
"name": "picgo",
"version": "2.3.1-beta.2",
"version": "2.3.1-beta.5",
"private": true,
"scripts": {
"dev": "vue-cli-service electron:serve",
@@ -13,7 +13,8 @@
"postuninstall": "electron-builder install-app-deps",
"cz": "git-cz",
"bump": "bump-version",
"release": "vue-cli-service electron:build --publish always"
"release": "vue-cli-service electron:build --publish always",
"upload-dist": "node ./scripts/upload-dist-to-cos.js"
},
"main": "background.js",
"husky": {
@@ -35,32 +36,38 @@
]
},
"dependencies": {
"@picgo/store": "^1.0.3",
"@picgo/i18n": "^1.0.0",
"@picgo/store": "2.0.1",
"axios": "^0.19.0",
"compare-versions": "^4.1.3",
"core-js": "^3.3.2",
"element-ui": "^2.13.0",
"fix-path": "^2.1.0",
"fs-extra": "^10.0.0",
"js-yaml": "^4.1.0",
"keycode": "^2.2.0",
"lodash-id": "^0.14.0",
"lowdb": "^1.0.0",
"picgo": "^1.4.24",
"picgo": "^1.5.0-alpha.5",
"qrcode.vue": "^1.7.0",
"shell-path": "2.1.0",
"uuidv4": "^6.2.11",
"vue": "^2.6.10",
"vue-gallery": "^2.0.1",
"vue-lazyload": "^1.2.6",
"vue-router": "^3.1.3"
"vue-router": "^3.1.3",
"write-file-atomic": "^4.0.1"
},
"devDependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
"@picgo/bump-version": "^1.1.2",
"@types/fs-extra": "^9.0.13",
"@types/inquirer": "^6.5.0",
"@types/js-yaml": "^4.0.5",
"@types/lowdb": "^1.0.9",
"@types/node": "^16.10.2",
"@types/request-promise-native": "^1.0.17",
"@types/semver": "^7.3.8",
"@types/write-file-atomic": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"@vue/cli-plugin-babel": "^4.0.0",
@@ -72,6 +79,7 @@
"@vue/eslint-config-typescript": "^7.0.0",
"conventional-changelog": "^3.1.18",
"cz-customizable": "^6.2.0",
"dotenv": "^16.0.1",
"electron": "^16.0.6",
"electron-devtools-installer": "^3.2.0",
"eslint": "^7.32.0",
@@ -89,6 +97,7 @@
"vue-template-compiler": "^2.6.10"
},
"resolutions": {
"@types/node": "^16.10.2"
"@types/node": "^16.10.2",
"vue-cli-plugin-electron-builder/**/electron-builder": "23.3.3"
}
}
+30 -14
View File
@@ -1,18 +1,34 @@
#!/bin/sh
# require xclip(see http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212)
command -v xclip >/dev/null 2>&1 || { echo >&1 "no xclip"; exit 1; }
# write image in clipboard to file (see http://unix.stackexchange.com/questions/145131/copy-image-from-clipboard-to-file)
filePath=`xclip -selection clipboard -o 2>/dev/null | grep ^file:// | cut -c8-`
if [ ! -n "$filePath" ] ;then
if
xclip -selection clipboard -target image/png -o >/dev/null 2>&1
then
xclip -selection clipboard -target image/png -o >$1 2>/dev/null
echo $1
if [ "$XDG_SESSION_TYPE" = "x11" ]; then
# require xclip(see http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212)
command -v xclip >/dev/null 2>&1 || { echo >&1 "no xclip"; exit 1; }
# write image in clipboard to file (see http://unix.stackexchange.com/questions/145131/copy-image-from-clipboard-to-file)
filePath=`xclip -selection clipboard -o 2>/dev/null | grep ^file:// | cut -c8-`
if [ ! -n "$filePath" ] ;then
if
xclip -selection clipboard -target image/png -o >/dev/null 2>&1
then
xclip -selection clipboard -target image/png -o >$1 2>/dev/null
echo $1
else
echo "no image"
fi
else
echo "no image"
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
else
echo $filePath
fi
else
echo $filePath
fi
Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

+50
View File
@@ -0,0 +1,50 @@
// different platform has different format
// macos
const darwin = [{
appNameWithPrefix: 'PicGo-',
ext: '.dmg',
arch: '-arm64',
'version-file': 'latest-mac.yml'
}, {
appNameWithPrefix: 'PicGo-',
ext: '.dmg',
arch: '-x64',
'version-file': 'latest-mac.yml'
}]
const linux = [{
appNameWithPrefix: 'PicGo-',
ext: '.AppImage',
arch: '',
'version-file': 'latest-linux.yml'
}, {
appNameWithPrefix: 'picgo_',
ext: '.snap',
arch: '_amd64',
'version-file': 'latest-linux.yml'
}]
// windows
const win32 = [{
appNameWithPrefix: 'PicGo-Setup-',
ext: '.exe',
arch: '-ia32',
'version-file': 'latest.yml'
}, {
appNameWithPrefix: 'PicGo-Setup-',
ext: '.exe',
arch: '-x64',
'version-file': 'latest.yml'
}, {
appNameWithPrefix: 'PicGo-Setup-',
ext: '.exe',
arch: '', // 32 & 64
'version-file': 'latest.yml'
}]
module.exports = {
darwin,
linux,
win32
}
+23
View File
@@ -0,0 +1,23 @@
const pkg = require('../package.json')
const version = pkg.version
// TODO: use the same name format
const generateURL = (platform, ext, prefix = 'PicGo-') => {
return `https://picgo-1251750343.cos.ap-chengdu.myqcloud.com/${prefix}${version}${platform}${ext}`
}
const platformExtList = [
['-arm64', '.dmg', 'PicGo-'],
['-x64', '.dmg', 'PicGo-'],
['', '.AppImage', 'PicGo-'],
['-ia32', '.exe', 'PicGo-Setup-'],
['-x64', '.exe', 'PicGo-Setup-'],
['', '.exe', 'PicGo-Setup-'],
['_amd64', '.snap', 'picgo_']
]
const links = platformExtList.map(([arch, ext, prefix]) => {
const markdownLink = `[${prefix}${version}${arch}${ext}](${generateURL(arch, ext, prefix)})`
return markdownLink
})
console.log(links.join('\n'))
+103
View File
@@ -0,0 +1,103 @@
// upload dist bundled-app to cos
require('dotenv').config()
const crypto = require('crypto')
const fs = require('fs')
const mime = require('mime-types')
const pkg = require('../package.json')
const configList = require('./config')
const axios = require('axios').default
const path = require('path')
const distPath = path.join(__dirname, '../dist_electron')
const BUCKET = 'picgo-1251750343'
const AREA = 'ap-chengdu'
const VERSION = pkg.version
const FILE_PATH = `${VERSION}/`
const SECRET_ID = process.env.PICGO_ENV_COS_SECRET_ID
const SECRET_KEY = process.env.PICGO_ENV_COS_SECRET_KEY
// https://cloud.tencent.com/document/product/436/7778#signature
/**
* @param {string} fileName
* @returns
*/
const generateSignature = (fileName, folder = FILE_PATH) => {
const secretKey = SECRET_KEY
const area = AREA
const bucket = BUCKET
const path = folder
const today = Math.floor(new Date().getTime() / 1000)
const tomorrow = today + 86400
const signTime = `${today};${tomorrow}`
const signKey = crypto.createHmac('sha1', secretKey).update(signTime).digest('hex')
const httpString = `put\n/${path}${fileName}\n\nhost=${bucket}.cos.${area}.myqcloud.com\n`
const sha1edHttpString = crypto.createHash('sha1').update(httpString).digest('hex')
const stringToSign = `sha1\n${signTime}\n${sha1edHttpString}\n`
const signature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex')
return {
signature,
signTime
}
}
/**
*
* @param {string} fileName
* @param {Buffer} fileBuffer
* @param {{ signature: string, signTime: string }} signature
* @returns
*/
const getReqOptions = (fileName, fileBuffer, signature, folder = FILE_PATH) => {
return {
method: 'PUT',
url: `http://${BUCKET}.cos.${AREA}.myqcloud.com/${encodeURI(folder)}${encodeURI(fileName)}`,
headers: {
Host: `${BUCKET}.cos.${AREA}.myqcloud.com`,
Authorization: `q-sign-algorithm=sha1&q-ak=${SECRET_ID}&q-sign-time=${signature.signTime}&q-key-time=${signature.signTime}&q-header-list=host&q-url-param-list=&q-signature=${signature.signature}`,
contentType: mime.lookup(fileName),
useAgent: `PicGo;${pkg.version};null;null`
},
maxContentLength: Infinity,
maxBodyLength: Infinity,
data: fileBuffer,
resolveWithFullResponse: true
}
}
const uploadFile = async () => {
try {
const platform = process.platform
if (configList[platform]) {
let versionFileHasUploaded = false
for (const [index, config] of configList[platform].entries()) {
const fileName = `${config.appNameWithPrefix}${VERSION}${config.arch}${config.ext}`
const filePath = path.join(distPath, fileName)
const versionFilePath = path.join(distPath, config['version-file'])
let versionFileName = config['version-file']
if (VERSION.toLocaleLowerCase().includes('beta')) {
versionFileName = versionFileName.replace('.yml', '.beta.yml')
}
// upload dist file
const signature = generateSignature(fileName)
const reqOptions = getReqOptions(fileName, fs.readFileSync(filePath), signature)
console.log('[PicGo Dist] Uploading...', fileName, `${index + 1}/${configList[platform].length}`)
await axios.request(reqOptions)
// upload version file
if (!versionFileHasUploaded) {
const signature = generateSignature(versionFileName, '')
const reqOptions = getReqOptions(versionFileName, fs.readFileSync(versionFilePath), signature, '')
console.log('[PicGo Version File] Uploading...', versionFileName)
await axios.request(reqOptions)
versionFileHasUploaded = true
}
}
} else {
console.warn('platform not supported!', platform)
}
} catch (e) {
console.error(e)
}
}
uploadFile()
+7
View File
@@ -10,9 +10,14 @@ import mainMixin from './renderer/utils/mainMixin'
import bus from '@/utils/bus'
import { initTalkingData } from './renderer/utils/analytics'
import db from './renderer/utils/db'
import { T, i18n } from '#/i18n/index'
import { handleURLParams } from '@/utils/beforeOpen'
webFrame.setVisualZoomLevelLimits(1, 1)
// do here before vue init
handleURLParams()
Vue.config.productionTip = false
Vue.prototype.$builtInPicBed = [
'smms',
@@ -26,6 +31,8 @@ Vue.prototype.$builtInPicBed = [
Vue.prototype.$$db = db
Vue.prototype.$http = axios
Vue.prototype.$bus = bus
Vue.prototype.$T = T
Vue.prototype.$i18n = i18n
Vue.use(ElementUI)
Vue.use(VueLazyLoad)
@@ -177,7 +177,7 @@ class ShortKeyHandler {
keyList.forEach(item => {
globalShortcut.unregister(item.key)
shortKeyService.unregisterCommand(item.command)
picgo.unsetConfig('settings.shortKey', item.command)
db.unset('settings.shortKey', item.command)
})
}
}
+25 -14
View File
@@ -11,12 +11,14 @@ import uploader from 'apis/app/uploader'
import getPicBeds from '~/main/utils/getPicBeds'
import db, { GalleryDB } from '~/main/apis/core/datastore'
import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from 'apis/app/window/constants'
import { IWindowList } from '#/types/enum'
import picgo from '@core/picgo'
import pasteTemplate from '~/main/utils/pasteTemplate'
import pkg from 'root/package.json'
import { handleCopyUrl } from '~/main/utils/common'
import { privacyManager } from '~/main/utils/privacyManager'
import { T } from '#/i18n'
import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion'
let contextMenu: Menu | null
let menu: Menu | null
let tray: Tray | null
@@ -41,7 +43,7 @@ export function createContextMenu () {
})
contextMenu = Menu.buildFromTemplate([
{
label: '关于',
label: T('ABOUT'),
click () {
dialog.showMessageBox({
title: 'PicGo',
@@ -51,7 +53,7 @@ export function createContextMenu () {
}
},
{
label: '打开详细窗口',
label: T('OPEN_MAIN_WINDOW'),
click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
settingWindow!.show()
@@ -62,14 +64,14 @@ export function createContextMenu () {
}
},
{
label: '选择默认图床',
label: T('CHOOSE_DEFAULT_PICBED'),
type: 'submenu',
// @ts-ignore
submenu
},
// @ts-ignore
{
label: '打开更新助手',
label: T('OPEN_UPDATE_HELPER'),
type: 'checkbox',
checked: db.get('settings.showUpdateTip'),
click () {
@@ -78,13 +80,13 @@ export function createContextMenu () {
}
},
{
label: '隐私协议',
label: T('PRIVACY_AGREEMENT'),
click () {
privacyManager.show(false)
}
},
{
label: '重启应用',
label: T('RELOAD_APP'),
click () {
app.relaunch()
app.exit(0)
@@ -93,7 +95,7 @@ export function createContextMenu () {
// @ts-ignore
{
role: 'quit',
label: '退出'
label: T('QUIT')
}
])
} else if (process.platform === 'linux') {
@@ -106,7 +108,7 @@ export function createContextMenu () {
contextMenu = Menu.buildFromTemplate([
{
label: '打开详细窗口',
label: T('OPEN_MAIN_WINDOW'),
click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
settingWindow!.show()
@@ -118,7 +120,7 @@ export function createContextMenu () {
},
// @ts-ignore
{
label: '打开更新助手',
label: T('OPEN_UPDATE_HELPER'),
type: 'checkbox',
checked: db.get('settings.showUpdateTip'),
click () {
@@ -127,7 +129,7 @@ export function createContextMenu () {
}
},
{
label: '关于应用',
label: T('ABOUT'),
click () {
dialog.showMessageBox({
title: 'PicGo',
@@ -140,14 +142,23 @@ export function createContextMenu () {
// @ts-ignore
{
role: 'quit',
label: '退出'
label: T('QUIT')
}
])
}
}
const getTrayIcon = () => {
if (process.platform === 'darwin') {
const isMacOSGreaterThan11 = isMacOSVersionGreaterThanOrEqualTo('11')
return isMacOSGreaterThan11 ? `${__static}/menubar-newdarwin-v2.png` : `${__static}/menubar.png`
} else {
return `${__static}/menubar-nodarwin.png`
}
}
export function createTray () {
const menubarPic = process.platform === 'darwin' ? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png`
const menubarPic = getTrayIcon()
tray = new Tray(menubarPic)
// click事件在Mac和Windows上可以触发(在Ubuntu上无法触发,Unity不支持)
if (process.platform === 'darwin' || process.platform === 'win32') {
@@ -214,7 +225,7 @@ export function createTray () {
for (let i = 0; i < imgs.length; i++) {
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
const notification = new Notification({
title: '上传成功',
title: T('UPLOAD_SUCCEED'),
body: imgs[i].imgUrl!,
icon: files[i]
})
+23 -10
View File
@@ -3,38 +3,51 @@ import {
WebContents
} from 'electron'
import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from 'apis/app/window/constants'
import { IWindowList } from '#/types/enum'
import uploader from '.'
import pasteTemplate from '~/main/utils/pasteTemplate'
import db, { GalleryDB } from '~/main/apis/core/datastore'
import { handleCopyUrl } from '~/main/utils/common'
import { handleUrlEncode } from '#/utils/common'
export const uploadClipboardFiles = async (): Promise<string> => {
import { T } from '#/i18n/index'
// import dayjs from 'dayjs'
const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
const useBuiltinClipboard = !!db.get('settings.useBuiltinClipboard')
const win = windowManager.getAvailableWindow()
const img = await uploader.setWebContents(win!.webContents).upload()
if (useBuiltinClipboard) {
return await uploader.setWebContents(win!.webContents).uploadWithBuildInClipboard()
}
return await uploader.setWebContents(win!.webContents).upload()
}
export const uploadClipboardFiles = async (): Promise<string> => {
const img = await handleClipboardUploading()
if (img !== false) {
if (img.length > 0) {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
handleCopyUrl(pasteTemplate(pasteStyle, img[0], db.get('settings.customLink')))
const notification = new Notification({
title: '上传成功',
title: T('UPLOAD_SUCCEED'),
body: img[0].imgUrl!,
icon: img[0].imgUrl
})
notification.show()
setTimeout(() => {
notification.show()
}, 100)
await GalleryDB.getInstance().insert(img[0])
// trayWindow just be created in mac/windows, not in linux
trayWindow?.webContents?.send('clipboardFiles', [])
trayWindow?.webContents?.send('uploadFiles', img)
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return handleUrlEncode(img[0].imgUrl as string)
} else {
const notification = new Notification({
title: '上传不成功',
body: '你剪贴板最新的一条记录不是图片哦'
title: T('UPLOAD_FAILED'),
body: T('TIPS_UPLOAD_NOT_PICTURES')
})
notification.show()
return ''
@@ -54,7 +67,7 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
for (let i = 0; i < imgs.length; i++) {
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
const notification = new Notification({
title: '上传成功',
title: T('UPLOAD_SUCCEED'),
body: imgs[i].imgUrl!,
icon: files[i].path
})
@@ -68,7 +81,7 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
// trayWindow just be created in mac/windows, not in linux
windowManager.get(IWindowList.TRAY_WINDOW)?.webContents?.send('uploadFiles', imgs)
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return result
} else {
+49 -12
View File
@@ -2,18 +2,25 @@ import {
Notification,
BrowserWindow,
ipcMain,
WebContents
WebContents,
clipboard
} from 'electron'
import dayjs from 'dayjs'
import picgo from '@core/picgo'
import db from '~/main/apis/core/datastore'
import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from 'apis/app/window/constants'
import { IWindowList } from '#/types/enum'
import util from 'util'
import { IPicGo } from 'picgo/dist/src/types'
import { IPicGo } from 'picgo'
import { showNotification, calcDurationRange } from '~/main/utils/common'
import { TALKING_DATA_EVENT } from '~/universal/events/constants'
import { RENAME_FILE_NAME, TALKING_DATA_EVENT } from '~/universal/events/constants'
import logger from '@core/picgo/logger'
import { T } from '~/universal/i18n'
import fse from 'fs-extra'
import path from 'path'
import { privacyManager } from '~/main/utils/privacyManager'
import writeFile from 'write-file-atomic'
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
const waitForShow = (webcontent: WebContents) => {
return new Promise<void>((resolve) => {
@@ -26,13 +33,13 @@ const waitForShow = (webcontent: WebContents) => {
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
return new Promise((resolve) => {
const windowId = window.id
ipcMain.once(`rename${id}`, (evt: Event, newName: string) => {
ipcMain.once(`${RENAME_FILE_NAME}${id}`, (evt: Event, newName: string) => {
resolve(newName)
window.close()
})
window.on('close', () => {
resolve(null)
ipcMain.removeAllListeners(`rename${id}`)
ipcMain.removeAllListeners(`${RENAME_FILE_NAME}${id}`)
windowManager.deleteById(windowId)
})
})
@@ -60,19 +67,19 @@ class Uploader {
}
init () {
picgo.on('notification', message => {
picgo.on('notification', (message: Electron.NotificationConstructorOptions | undefined) => {
const notification = new Notification(message)
notification.show()
})
picgo.on('uploadProgress', progress => {
picgo.on('uploadProgress', (progress: any) => {
this.webContents?.send('uploadProgress', progress)
})
picgo.on('beforeTransform', () => {
if (db.get('settings.uploadNotification')) {
const notification = new Notification({
title: '上传进度',
body: '正在上传'
title: T('UPLOAD_PROGRESS'),
body: T('UPLOADING')
})
notification.show()
}
@@ -93,7 +100,7 @@ class Uploader {
if (rename) {
const window = windowManager.create(IWindowList.RENAME_WINDOW)!
await waitForShow(window.webContents)
window.webContents.send('rename', fileName, window.webContents.id)
window.webContents.send(RENAME_FILE_NAME, fileName, item.fileName, window.webContents.id)
name = await waitForRename(window, window.webContents.id)
}
item.fileName = name || fileName
@@ -108,8 +115,38 @@ class Uploader {
return this
}
/**
* use electron's clipboard image to upload
*/
async uploadWithBuildInClipboard (): Promise<ImgInfo[]|false> {
let filePath = ''
try {
const nativeImage = clipboard.readImage()
if (nativeImage.isEmpty()) {
return false
}
const buffer = nativeImage.toPNG()
const baseDir = picgo.baseDir
const fileName = `${dayjs().format('YYYYMMDDHHmmSSS')}.png`
filePath = path.join(baseDir, CLIPBOARD_IMAGE_FOLDER, fileName)
await writeFile(filePath, buffer)
return await this.upload([filePath])
} catch (e: any) {
logger.error(e)
return false
} finally {
if (filePath) {
fse.unlink(filePath)
}
}
}
async upload (img?: IUploadOption): Promise<ImgInfo[]|false> {
try {
const privacyCheckRes = await privacyManager.check()
if (!privacyCheckRes) {
throw Error(T('PRIVACY_TIPS'))
}
const startTime = Date.now()
const output = await picgo.upload(img)
if (Array.isArray(output) && output.some((item: ImgInfo) => item.imgUrl)) {
@@ -129,7 +166,7 @@ class Uploader {
logger.error(e)
setTimeout(() => {
showNotification({
title: '上传失败',
title: T('UPLOAD_FAILED'),
body: util.format(e.stack),
clickToCopy: true
})
-7
View File
@@ -1,10 +1,3 @@
export enum IWindowList {
SETTING_WINDOW = 'SETTING_WINDOW',
TRAY_WINDOW = 'TRAY_WINDOW',
MINI_WINDOW = 'MINI_WINDOW',
RENAME_WINDOW = 'RENAME_WINDOW'
}
const isDevelopment = process.env.NODE_ENV !== 'production'
export const TRAY_WINDOW_URL = isDevelopment
+15 -6
View File
@@ -1,19 +1,28 @@
import {
IWindowList,
SETTING_WINDOW_URL,
TRAY_WINDOW_URL,
MINI_WINDOW_URL,
RENAME_WINDOW_URL
} from './constants'
import { IWindowListItem } from '#/types/electron'
import { 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 { i18n } from '~/universal/i18n'
import { URLSearchParams } from 'url'
const windowList = new Map<IWindowList, IWindowListItem>()
const handleWindowParams = (windowURL: string) => {
const [baseURL, hash = ''] = windowURL.split('#')
const search = new URLSearchParams()
const lang = i18n.getLanguage()
search.append('lang', lang)
return `${baseURL}?${search.toString()}#${hash}`
}
windowList.set(IWindowList.TRAY_WINDOW, {
isValid: process.platform !== 'linux',
multiple: false,
@@ -36,7 +45,7 @@ windowList.set(IWindowList.TRAY_WINDOW, {
}
},
callback (window) {
window.loadURL(TRAY_WINDOW_URL)
window.loadURL(handleWindowParams(TRAY_WINDOW_URL))
window.on('blur', () => {
window.hide()
})
@@ -77,7 +86,7 @@ windowList.set(IWindowList.SETTING_WINDOW, {
return options
},
callback (window, windowManager) {
window.loadURL(SETTING_WINDOW_URL)
window.loadURL(handleWindowParams(SETTING_WINDOW_URL))
window.on('closed', () => {
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
if (process.platform === 'linux') {
@@ -119,7 +128,7 @@ windowList.set(IWindowList.MINI_WINDOW, {
return obj
},
callback (window) {
window.loadURL(MINI_WINDOW_URL)
window.loadURL(handleWindowParams(MINI_WINDOW_URL))
}
})
@@ -150,7 +159,7 @@ windowList.set(IWindowList.RENAME_WINDOW, {
return options
},
async callback (window, windowManager) {
window.loadURL(RENAME_WINDOW_URL)
window.loadURL(handleWindowParams(RENAME_WINDOW_URL))
const currentWindow = windowManager.getAvailableWindow()
if (currentWindow && currentWindow.isVisible()) {
// bounds: { x: 821, y: 75, width: 800, height: 450 }
+1 -4
View File
@@ -1,11 +1,8 @@
import {
BrowserWindow
} from 'electron'
import { IWindowManager, IWindowListItem } from '#/types/electron'
import windowList from './windowList'
import {
IWindowList
} from './constants'
import { IWindowList } from '#/types/enum'
class WindowManager implements IWindowManager {
private windowMap: Map<IWindowList | string, BrowserWindow> = new Map()
+13 -10
View File
@@ -1,8 +1,10 @@
import fs from 'fs-extra'
import writeFile from 'write-file-atomic'
import path from 'path'
import { app as APP } from 'electron'
import { getLogger } from '@core/utils/localLogger'
import dayjs from 'dayjs'
import { T } from '~/universal/i18n'
const STORE_PATH = APP.getPath('userData')
const configFilePath = path.join(STORE_PATH, 'data.json')
const configFileBackupPath = path.join(STORE_PATH, 'data.bak.json')
@@ -11,8 +13,8 @@ let _configFilePath = ''
let hasCheckPath = false
const errorMsg = {
broken: 'PicGo 配置文件损坏,已经恢复为默认配置',
brokenButBackup: 'PicGo 配置文件损坏,已经恢复为备份配置'
broken: T('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_DEFAULT'),
brokenButBackup: T('TIPS_PICGO_CONFIG_FILE_BROKEN_WITH_BACKUP')
}
/** ensure notification list */
@@ -36,7 +38,7 @@ function dbChecker () {
}
let configFile: string = '{}'
const optionsTpl = {
title: '注意',
title: T('TIPS_NOTICE'),
body: ''
}
// config save bak
@@ -49,9 +51,11 @@ function dbChecker () {
try {
configFile = fs.readFileSync(configFileBackupPath, { encoding: 'utf-8' })
JSON.parse(configFile)
fs.writeFileSync(configFilePath, configFile, { encoding: 'utf-8' })
writeFile.sync(configFilePath, configFile, { encoding: 'utf-8' })
const stats = fs.statSync(configFileBackupPath)
optionsTpl.body = `${errorMsg.brokenButBackup}\n备份文件版本:${dayjs(stats.mtime).format('YYYY-MM-DD HH:mm:ss')}`
optionsTpl.body = `${errorMsg.brokenButBackup}\n${T('TIPS_PICGO_BACKUP_FILE_VERSION', {
v: dayjs(stats.mtime).format('YYYY-MM-DD HH:mm:ss')
})}`
global.notificationList?.push(optionsTpl)
return
} catch (e) {
@@ -64,7 +68,7 @@ function dbChecker () {
global.notificationList?.push(optionsTpl)
return
}
fs.writeFileSync(configFileBackupPath, configFile, { encoding: 'utf-8' })
writeFile.sync(configFileBackupPath, configFile, { encoding: 'utf-8' })
}
}
@@ -94,18 +98,17 @@ function dbPathChecker (): string {
}
return _configFilePath
} catch (e) {
const picgoLogPath = path.join(defaultConfigPath, 'picgo.log')
const picgoLogPath = path.join(STORE_PATH, 'picgo-gui-local.log')
const logger = getLogger(picgoLogPath)
if (!hasCheckPath) {
const optionsTpl = {
title: '注意',
body: '自定义文件解析出错,请检查路径内容是否正确'
title: T('TIPS_NOTICE'),
body: T('TIPS_CUSTOM_CONFIG_FILE_PATH_ERROR')
}
global.notificationList?.push(optionsTpl)
hasCheckPath = true
}
logger('error', e)
console.error(e)
_configFilePath = defaultConfigPath
return _configFilePath
}
+26 -40
View File
@@ -1,10 +1,7 @@
import Datastore from 'lowdb'
// @ts-ignore
import LodashId from 'lodash-id'
import FileSync from 'lowdb/adapters/FileSync'
import fs from 'fs-extra'
import { dbPathChecker, dbPathDir, getGalleryDBPath } from './dbChecker'
import { DBStore } from '@picgo/store'
import { DBStore, JSONStore } from '@picgo/store'
import { T } from '~/universal/i18n'
const STORE_PATH = dbPathDir()
@@ -14,68 +11,55 @@ if (!fs.pathExistsSync(STORE_PATH)) {
const CONFIG_PATH: string = dbPathChecker()
const DB_PATH: string = getGalleryDBPath().dbPath
// TODO: use JSONStore with @picgo/store
class ConfigStore {
private db: Datastore.LowdbSync<Datastore.AdapterSync>
private db: JSONStore
constructor () {
const adapter = new FileSync(CONFIG_PATH)
this.db = new JSONStore(CONFIG_PATH)
this.db = Datastore(adapter)
this.db._.mixin(LodashId)
if (!this.db.has('picBed').value()) {
if (!this.db.has('picBed')) {
this.db.set('picBed', {
current: 'smms', // deprecated
uploader: 'smms',
smms: {
token: ''
}
}).write()
})
}
if (!this.db.has('settings.shortKey').value()) {
if (!this.db.has('settings.shortKey')) {
this.db.set('settings.shortKey[picgo:upload]', {
enable: true,
key: 'CommandOrControl+Shift+P',
name: 'upload',
label: '快捷上传'
}).write()
label: T('QUICK_UPLOAD')
})
}
this.read()
}
read () {
return this.db.read()
read (flush = false) {
// if flush -> true, read origin file again
this.db.read(flush)
return this.db
}
get (key = '') {
return this.read().get(key).value()
get (key = ''): any {
if (key === '') {
return this.db.read()
}
return this.db.get(key)
}
set (key: string, value: any) {
return this.read().set(key, value).write()
set (key: string, value: any): void {
return this.db.set(key, value)
}
has (key: string) {
return this.read().has(key).value()
}
insert (key: string, value: any): void {
// @ts-ignore
return this.read().get(key).insert(value).write()
return this.db.has(key)
}
unset (key: string, value: any): boolean {
return this.read().get(key).unset(value).value()
}
getById (key: string, id: string) {
// @ts-ignore
return this.read().get(key).getById(id).value()
}
removeById (key: string, id: string) {
// @ts-ignore
return this.read().get(key).removeById(id).write()
return this.db.unset(key, value)
}
getConfigPath () {
@@ -83,7 +67,9 @@ class ConfigStore {
}
}
export default new ConfigStore()
const db = new ConfigStore()
export default db
// v2.3.0 add gallery db
class GalleryDB {
+13 -5
View File
@@ -1,9 +1,7 @@
import PicGoCore from '~/universal/types/picgo'
import { dbChecker, dbPathChecker } from 'apis/core/datastore/dbChecker'
import pkg from 'root/package.json'
// eslint-disable-next-line
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
const PicGo = requireFunc('picgo') as typeof PicGoCore
import { PicGo } from 'picgo'
import db from 'apis/core/datastore'
const CONFIG_PATH = dbPathChecker()
@@ -18,4 +16,14 @@ picgo.saveConfig({
global.PICGO_GUI_VERSION = pkg.version
picgo.GUI_VERSION = global.PICGO_GUI_VERSION
export default picgo! as PicGoCore
const originPicGoSaveConfig = picgo.saveConfig.bind(picgo)
picgo.saveConfig = (config: IStringKeyMap) => {
originPicGoSaveConfig(config)
// flush electron's db
setTimeout(() => {
db.read(true)
}, 0)
}
export default picgo
+47 -13
View File
@@ -2,6 +2,32 @@ import fs from 'fs-extra'
import dayjs from 'dayjs'
import util from 'util'
const checkLogFileIsLarge = (logPath: string): {
isLarge: boolean
logFileSize?: number
logFileSizeLimit?: number
} => {
if (fs.existsSync(logPath)) {
const logFileSize = fs.statSync(logPath).size
const logFileSizeLimit = 10 * 1024 * 1024 // 10 MB default
return {
isLarge: logFileSize > logFileSizeLimit,
logFileSize,
logFileSizeLimit
}
}
return {
isLarge: false
}
}
const recreateLogFile = (logPath: string): void => {
if (fs.existsSync(logPath)) {
fs.unlinkSync(logPath)
fs.createFileSync(logPath)
}
}
/**
* for local log before picgo inited
*/
@@ -9,21 +35,29 @@ const getLogger = (logPath: string) => {
if (!fs.existsSync(logPath)) {
fs.ensureFileSync(logPath)
}
if (checkLogFileIsLarge(logPath).isLarge) {
recreateLogFile(logPath)
}
return (type: string, ...msg: any[]) => {
let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicGo ${type.toUpperCase()}] `
msg.forEach((item: ILogArgvTypeWithError) => {
if (typeof item === 'object' && type === 'error') {
log += `\n------Error Stack Begin------\n${util.format(item.stack)}\n-------Error Stack End------- `
} else {
if (typeof item === 'object') {
item = JSON.stringify(item)
try {
let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicGo ${type.toUpperCase()}] `
msg.forEach((item: ILogArgvTypeWithError) => {
if (typeof item === 'object' && type === 'error') {
log += `\n------Error Stack Begin------\n${util.format(item.stack)}\n-------Error Stack End------- `
} else {
if (typeof item === 'object') {
item = JSON.stringify(item)
}
log += `${item} `
}
log += `${item} `
}
})
log += '\n'
// A synchronized approach to avoid log msg sequence errors
fs.appendFileSync(logPath, log)
})
log += '\n'
console.log(log)
// A synchronized approach to avoid log msg sequence errors
fs.appendFileSync(logPath, log)
} catch (e) {
console.error(e)
}
}
}
+25 -3
View File
@@ -17,6 +17,7 @@ import {
SHOW_INPUT_BOX
} from '~/universal/events/constants'
import { DBStore } from '@picgo/store'
import { T } from '~/universal/i18n'
// Cross-process support may be required in the future
class GuiApi implements IGuiApi {
@@ -81,7 +82,7 @@ class GuiApi implements IGuiApi {
for (let i = 0; i < imgs.length; i++) {
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
const notification = new Notification({
title: '上传成功',
title: T('UPLOAD_SUCCEED'),
body: imgs[i].imgUrl as string,
icon: imgs[i].imgUrl
})
@@ -145,14 +146,35 @@ class GuiApi implements IGuiApi {
get galleryDB (): DBStore {
return new Proxy<DBStore>(GalleryDB.getInstance(), {
get (target, prop: keyof DBStore) {
if (prop === 'overwrite') {
return new Proxy(GalleryDB.getInstance().overwrite, {
apply (target, ctx, args) {
return new Promise((resolve) => {
const guiApi = GuiApi.getInstance()
guiApi.showMessageBox({
title: T('TIPS_WARNING'),
message: T('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'),
type: 'info',
buttons: ['Yes', 'No']
}).then(res => {
if (res.result === 0) {
resolve(Reflect.apply(target, ctx, args))
} else {
resolve(undefined)
}
})
})
}
})
}
if (prop === 'removeById') {
return new Proxy(GalleryDB.getInstance().removeById, {
apply (target, ctx, args) {
return new Promise((resolve) => {
const guiApi = GuiApi.getInstance()
guiApi.showMessageBox({
title: '警告',
message: '有插件正在试图删除一些相册图片,是否继续',
title: T('TIPS_WARNING'),
message: T('TIPS_PLUGIN_REMOVE_GALLERY_ITEM'),
type: 'info',
buttons: ['Yes', 'No']
}).then(res => {
+1 -1
View File
@@ -6,7 +6,7 @@ import {
import {
createMenu
} from 'apis/app/system'
import { IWindowList } from 'apis/app/window/constants'
import { IWindowList } from '#/types/enum'
import windowManager from 'apis/app/window/windowManager'
import {
UPLOAD_WITH_FILES,
+25 -14
View File
@@ -7,7 +7,7 @@ import {
BrowserWindow
} from 'electron'
import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from 'apis/app/window/constants'
import { IWindowList } from '#/types/enum'
import uploader from 'apis/app/uploader'
import pasteTemplate from '~/main/utils/pasteTemplate'
import db, { GalleryDB } from '~/main/apis/core/datastore'
@@ -27,7 +27,8 @@ import {
OPEN_URL,
RELOAD_APP,
SHOW_PLUGIN_PAGE_MENU,
SET_MINI_WINDOW_POS
SET_MINI_WINDOW_POS,
CHANGE_LANGUAGE
} from '#/events/constants'
import {
uploadClipboardFiles,
@@ -37,6 +38,7 @@ import picgoCoreIPC from './picgoCoreIPC'
import { handleCopyUrl } from '~/main/utils/common'
import { buildMainPageMenu, buildMiniPageMenu, buildPluginPageMenu, buildUploadPageMenu } from './remotes/menu'
import path from 'path'
import { i18n, T } from '~/universal/i18n'
const STORE_PATH = app.getPath('userData')
@@ -51,7 +53,7 @@ export default {
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
handleCopyUrl(pasteTemplate(pasteStyle, img[0], db.get('settings.customLink')))
const notification = new Notification({
title: '上传成功',
title: T('UPLOAD_SUCCEED'),
body: img[0].imgUrl!,
// icon: file[0]
icon: img[0].imgUrl
@@ -79,14 +81,14 @@ export default {
evt.sender.send('updateShortKeyResponse', result)
if (result) {
const notification = new Notification({
title: '操作成功',
body: '你的快捷键已经修改成功'
title: T('OPERATION_SUCCEED'),
body: T('TIPS_SHORTCUT_MODIFIED_SUCCEED')
})
notification.show()
} else {
const notification = new Notification({
title: '操作失败',
body: '快捷键冲突,请重新设置'
title: T('OPERATION_FAILED'),
body: T('TIPS_SHORTCUT_MODIFIED_CONFLICT')
})
notification.show()
}
@@ -96,14 +98,14 @@ export default {
const result = shortKeyHandler.bindOrUnbindShortKey(item, from)
if (result) {
const notification = new Notification({
title: '操作成功',
body: '你的快捷键已经修改成功'
title: T('OPERATION_SUCCEED'),
body: T('TIPS_SHORTCUT_MODIFIED_SUCCEED')
})
notification.show()
} else {
const notification = new Notification({
title: '操作失败',
body: '快捷键冲突,请重新设置'
title: T('OPERATION_FAILED'),
body: T('TIPS_SHORTCUT_MODIFIED_CONFLICT')
})
notification.show()
}
@@ -111,8 +113,8 @@ export default {
ipcMain.on('updateCustomLink', () => {
const notification = new Notification({
title: '操作成功',
body: '你的自定义链接格式已经修改成功'
title: T('OPERATION_SUCCEED'),
body: T('TIPS_CUSTOM_LINK_STYLE_MODIFIED_SUCCEED')
})
notification.show()
})
@@ -133,6 +135,11 @@ export default {
ipcMain.on('openMiniWindow', () => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
if (db.get('settings.miniWindowOntop')) {
miniWindow.setAlwaysOnTop(true)
}
miniWindow.show()
miniWindow.focus()
settingWindow.hide()
@@ -171,7 +178,7 @@ export default {
})
ipcMain.on(SHOW_MAIN_PAGE_MENU, () => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildMainPageMenu()
const menu = buildMainPageMenu(window)
menu.popup({
window
})
@@ -217,6 +224,10 @@ export default {
const window = BrowserWindow.getFocusedWindow()
window?.setBounds(pos)
})
ipcMain.on(CHANGE_LANGUAGE, (evt: IpcMainEvent, lang: string) => {
lang = lang || 'zh-CN'
i18n.setLanguage(lang)
})
},
dispose () {}
}
+62 -22
View File
@@ -7,14 +7,12 @@ import {
ipcMain,
clipboard
} from 'electron'
import PicGoCore from '~/universal/types/picgo'
import { IPasteStyle, IPicGoHelperType } from '#/types/enum'
import { IPasteStyle, IPicGoHelperType, IWindowList } from '#/types/enum'
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
import picgo from '@core/picgo'
import { handleStreamlinePluginName } from '~/universal/utils/common'
import { IGuiMenuItem } from 'picgo/dist/src/types'
import { handleStreamlinePluginName, simpleClone } from '~/universal/utils/common'
import { IGuiMenuItem, PicGo as PicGoCore } from 'picgo'
import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from 'apis/app/window/constants'
import { showNotification } from '~/main/utils/common'
import { dbPathChecker } from 'apis/core/datastore/dbChecker'
import {
@@ -27,16 +25,19 @@ import {
PICGO_GET_BY_ID_DB,
PICGO_REMOVE_BY_ID_DB,
PICGO_OPEN_FILE,
PASTE_TEXT
PASTE_TEXT,
OPEN_WINDOW,
DEFAULT_LOGO
} from '#/events/constants'
import { GalleryDB } from 'apis/core/datastore'
import { IObject, IFilter } from '@picgo/store/dist/types'
import pasteTemplate from '../utils/pasteTemplate'
import { T } from '~/universal/i18n'
// eslint-disable-next-line
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
// const PluginHandler = requireFunc('picgo/dist/lib/PluginHandler').default
// const PluginHandler = requireFunc('picgo/lib/PluginHandler').default
const STORE_PATH = path.dirname(dbPathChecker())
// const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
@@ -82,9 +83,11 @@ const getPluginList = (): IPicGoPlugin[] => {
const pluginPKG = requireFunc(path.join(pluginPath, 'package.json'))
const uploaderName = plugin.uploader || ''
const transformerName = plugin.transformer || ''
let menu: IGuiMenuItem[] = []
let menu: Omit<IGuiMenuItem, 'handle'>[] = []
if (plugin.guiMenu) {
menu = plugin.guiMenu(picgo)
menu = plugin.guiMenu(picgo).map(item => ({
label: item.label
}))
}
let gui = false
if (pluginPKG.keywords && pluginPKG.keywords.length > 0) {
@@ -127,8 +130,19 @@ const getPluginList = (): IPicGoPlugin[] => {
const handleGetPluginList = () => {
ipcMain.on('getPluginList', (event: IpcMainEvent) => {
const list = getPluginList()
event.sender.send('pluginList', list)
try {
const list = simpleClone(getPluginList())
// here can just send JS Object not function
// or will cause [Failed to serialize arguments] error
event.sender.send('pluginList', list)
} catch (e: any) {
event.sender.send('pluginList', [])
showNotification({
title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
body: e.message
})
picgo.log.error(e)
}
})
}
@@ -145,7 +159,7 @@ const handlePluginInstall = () => {
shortKeyHandler.registerPluginShortKey(res.body[0])
} else {
showNotification({
title: '插件安装失败',
title: T('PLUGIN_INSTALL_FAILED'),
body: res.body as string
})
}
@@ -163,7 +177,7 @@ const handlePluginUninstall = async (fullName: string) => {
shortKeyHandler.unregisterPluginShortKey(res.body[0])
} else {
showNotification({
title: '插件卸载失败',
title: T('PLUGIN_UNINSTALL_FAILED'),
body: res.body as string
})
}
@@ -179,7 +193,7 @@ const handlePluginUpdate = async (fullName: string) => {
window.webContents.send('updateSuccess', res.body[0])
} else {
showNotification({
title: '插件更新失败',
title: T('PLUGIN_UPDATE_FAILED'),
body: res.body as string
})
}
@@ -191,8 +205,8 @@ const handleNPMError = (): IDispose => {
const handler = (msg: string) => {
if (msg === 'NPM is not installed') {
dialog.showMessageBox({
title: '发生错误',
message: '请安装Node.js并重启PicGo再继续操作',
title: T('TIPS_ERROR'),
message: T('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'),
buttons: ['Yes']
}).then((res) => {
if (res.response === 0) {
@@ -209,7 +223,8 @@ const handleGetPicBedConfig = () => {
ipcMain.on('getPicBedConfig', (event: IpcMainEvent, type: string) => {
const name = picgo.helper.uploader.get(type)?.name || type
if (picgo.helper.uploader.get(type)?.config) {
const config = handleConfigWithFunction(picgo.helper.uploader.get(type)!.config(picgo))
const _config = picgo.helper.uploader.get(type)!.config!(picgo)
const config = handleConfigWithFunction(_config)
event.sender.send('getPicBedConfig', config, name)
} else {
event.sender.send('getPicBedConfig', [], name)
@@ -263,15 +278,23 @@ const handleImportLocalPlugin = () => {
if (filePaths.length > 0) {
const res = await picgo.pluginHandler.install(filePaths)
if (res.success) {
const list = getPluginList()
event.sender.send('pluginList', list)
try {
const list = simpleClone(getPluginList())
event.sender.send('pluginList', list)
} catch (e: any) {
event.sender.send('pluginList', [])
showNotification({
title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
body: e.message
})
}
showNotification({
title: '导入插件成功',
title: T('PLUGIN_IMPORT_SUCCEED'),
body: ''
})
} else {
showNotification({
title: '导入插件失败',
title: T('PLUGIN_IMPORT_FAILED'),
body: res.body as string
})
}
@@ -317,7 +340,7 @@ const handlePicGoGalleryDB = () => {
event.sender.send(PICGO_REMOVE_BY_ID_DB, res, callbackId)
})
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 customLink = picgo.getConfig<string>('settings.customLink')
const txt = pasteTemplate(pasteStyle, item, customLink)
@@ -335,6 +358,21 @@ const handleOpenFile = () => {
})
}
const handleOpenWindow = () => {
ipcMain.on(OPEN_WINDOW, (event: IpcMainEvent, windowName: IWindowList) => {
const window = windowManager.get(windowName)
if (window) {
window.show()
}
})
}
const handleDefaultLogo = () => {
ipcMain.on(DEFAULT_LOGO, (event: IpcMainEvent) => {
event.sender.send(DEFAULT_LOGO, path.join(__static, 'roundLogo.png'))
})
}
export default {
listen () {
handleGetPluginList()
@@ -347,6 +385,8 @@ export default {
handlePicGoGalleryDB()
handleImportLocalPlugin()
handleOpenFile()
handleOpenWindow()
handleDefaultLogo()
},
// TODO: separate to single file
handlePluginUninstall,
+32 -24
View File
@@ -1,5 +1,5 @@
import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from 'apis/app/window/constants'
import { IWindowList } from '#/types/enum'
import { Menu, BrowserWindow, app, dialog } from 'electron'
import getPicBeds from '~/main/utils/getPicBeds'
import picgo from '@core/picgo'
@@ -9,9 +9,10 @@ import {
import { privacyManager } from '~/main/utils/privacyManager'
import pkg from 'root/package.json'
import GuiApi from 'apis/gui'
import PicGoCore from '~/universal/types/picgo'
import { PICGO_CONFIG_PLUGIN, PICGO_HANDLE_PLUGIN_ING, PICGO_TOGGLE_PLUGIN } from '~/universal/events/constants'
import { PICGO_CONFIG_PLUGIN, PICGO_HANDLE_PLUGIN_ING, PICGO_TOGGLE_PLUGIN, SHOW_MAIN_PAGE_DONATION, SHOW_MAIN_PAGE_QRCODE } from '~/universal/events/constants'
import picgoCoreIPC from '~/main/events/picgoCoreIPC'
import { PicGo as PicGoCore } from 'picgo'
import { T } from '~/universal/i18n'
interface GuiMenuItem {
label: string
@@ -39,7 +40,7 @@ const buildMiniPageMenu = () => {
})
const template = [
{
label: '打开详细窗口',
label: T('OPEN_MAIN_WINDOW'),
click () {
windowManager.get(IWindowList.SETTING_WINDOW)!.show()
if (windowManager.has(IWindowList.MINI_WINDOW)) {
@@ -48,30 +49,30 @@ const buildMiniPageMenu = () => {
}
},
{
label: '选择默认图床',
label: T('CHOOSE_DEFAULT_PICBED'),
type: 'submenu',
submenu
},
{
label: '剪贴板图片上传',
label: T('UPLOAD_BY_CLIPBOARD'),
click () {
uploadClipboardFiles()
}
},
{
label: '隐藏窗口',
label: T('HIDE_WINDOW'),
click () {
BrowserWindow.getFocusedWindow()!.hide()
}
},
{
label: '隐私协议',
label: T('PRIVACY_AGREEMENT'),
click () {
privacyManager.show(false)
}
},
{
label: '重启应用',
label: T('RELOAD_APP'),
click () {
app.relaunch()
app.exit(0)
@@ -79,17 +80,17 @@ const buildMiniPageMenu = () => {
},
{
role: 'quit',
label: '退出'
label: T('QUIT')
}
]
// @ts-ignore
return Menu.buildFromTemplate(template)
}
const buildMainPageMenu = () => {
const buildMainPageMenu = (win: BrowserWindow) => {
const template = [
{
label: '关于',
label: T('ABOUT'),
click () {
dialog.showMessageBox({
title: 'PicGo',
@@ -99,20 +100,25 @@ const buildMainPageMenu = () => {
}
},
{
label: '赞助PicGo',
label: T('SPONSOR_PICGO'),
click () {
// TODO: show donation
win?.webContents?.send(SHOW_MAIN_PAGE_DONATION)
}
},
{
label: '生成图床配置二维码',
label: T('SHOW_PICBED_QRCODE'),
click () {
// TODO: qrcode
// _this.qrcodeVisible = true
win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE)
}
},
{
label: '隐私协议',
label: T('SHOW_DEVTOOLS'),
click () {
win?.webContents?.openDevTools()
}
},
{
label: T('PRIVACY_AGREEMENT'),
click () {
privacyManager.show(false)
}
@@ -169,7 +175,7 @@ const handleRestoreState = (item: string, name: string): void => {
const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
const menu = [{
label: '启用插件',
label: T('ENABLE_PLUGIN'),
enabled: !plugin.enabled,
click () {
picgo.saveConfig({
@@ -179,7 +185,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
window.webContents.send(PICGO_TOGGLE_PLUGIN, plugin.fullName, true)
}
}, {
label: '禁用插件',
label: T('DISABLE_PLUGIN'),
enabled: plugin.enabled,
click () {
picgo.saveConfig({
@@ -196,14 +202,14 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
}
}
}, {
label: '卸载插件',
label: T('UNINSTALL_PLUGIN'),
click () {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
picgoCoreIPC.handlePluginUninstall(plugin.fullName)
}
}, {
label: '更新插件',
label: T('UPDATE_PLUGIN'),
click () {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
@@ -213,7 +219,9 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
for (const i in plugin.config) {
if (plugin.config[i].config.length > 0) {
const obj = {
label: `配置${i} - ${plugin.config[i].fullName || plugin.config[i].name}`,
label: T('CONFIG_THING', {
c: `${i} - ${plugin.config[i].fullName || plugin.config[i].name}`
}),
click () {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const currentType = i
@@ -231,7 +239,7 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
const currentTransformer = picgo.getConfig<string>('picBed.transformer') || 'path'
const pluginTransformer = plugin.config.transformer.name
const obj = {
label: `${currentTransformer === pluginTransformer ? '禁用' : '启用'}transformer - ${plugin.config.transformer.name}`,
label: `${currentTransformer === pluginTransformer ? T('DISABLE') : T('ENABLE')}transformer - ${plugin.config.transformer.name}`,
click () {
const transformer = plugin.config.transformer.name
const currentTransformer = picgo.getConfig<string>('picBed.transformer') || 'path'
+5 -15
View File
@@ -1,27 +1,17 @@
import fse from 'fs-extra'
import path from 'path'
import dayjs from 'dayjs'
import util from 'util'
import { dbPathDir } from 'apis/core/datastore/dbChecker'
import { getLogger } from 'apis/core/utils/localLogger'
const STORE_PATH = dbPathDir()
const LOG_PATH = path.join(STORE_PATH, '/picgo.log')
const LOG_PATH = path.join(STORE_PATH, 'picgo-gui-local.log')
const logger = getLogger(LOG_PATH)
// since the error may occur in picgo-core
// so we can't use the log from picgo
export const loggerWriter = (error: Error) => {
let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicGo ERROR] startup error`
if (error?.stack) {
log += `\n------Error Stack Begin------\n${util.format(error.stack)}\n-------Error Stack End-------\n`
} else {
const msg = JSON.stringify(error)
log += `${msg}\n`
}
fse.appendFileSync(LOG_PATH, log)
}
const handleProcessError = (error: Error) => {
console.error(error)
loggerWriter(error)
logger('error', error)
}
process.on('uncaughtException', error => {
+18
View File
@@ -0,0 +1,18 @@
// TODO: so how to import pure esm module in electron main process????? help wanted
// just copy the fix-path because I can't import pure ESM module in electron main process
const shellPath = require('shell-path')
export default function fixPath () {
if (process.platform === 'win32') {
return
}
process.env.PATH = shellPath.sync() || [
'./node_modules/.bin',
'/.nodebrew/current/bin',
'/usr/local/bin',
process.env.PATH
].join(':')
}
+5 -8
View File
@@ -10,10 +10,9 @@ import {
} from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
import beforeOpen from '~/main/utils/beforeOpen'
import fixPath from 'fix-path'
import ipcList from '~/main/events/ipcList'
import busEventList from '~/main/events/busEventList'
import { IWindowList } from 'apis/app/window/constants'
import { IWindowList } from '#/types/enum'
import windowManager from 'apis/app/window/windowManager'
import {
updateShortKeyFromVersion212,
@@ -32,9 +31,10 @@ import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
import { getUploadFiles } from '~/main/utils/handleArgv'
import db, { GalleryDB } from '~/main/apis/core/datastore'
import bus from '@core/bus'
import { privacyManager } from '~/main/utils/privacyManager'
import logger from 'apis/core/picgo/logger'
import picgo from 'apis/core/picgo'
import fixPath from './fixPath'
import { initI18n } from '~/main/utils/handleI18n'
const isDevelopment = process.env.NODE_ENV !== 'production'
@@ -58,9 +58,10 @@ const handleStartUpFiles = (argv: string[], cwd: string) => {
class LifeCycle {
private async beforeReady () {
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
// fix the $PATH in macOS
// fix the $PATH in macOS & linux
fixPath()
beforeOpen()
initI18n()
ipcList.listen()
busEventList.listen()
updateShortKeyFromVersion212(db, db.get('settings.shortKey'))
@@ -79,10 +80,6 @@ class LifeCycle {
console.error('Vue Devtools failed to install:', e.toString())
}
}
const res = await privacyManager.init()
if (!res) {
return app.quit()
}
windowManager.create(IWindowList.TRAY_WINDOW)
windowManager.create(IWindowList.SETTING_WINDOW)
createTray()
+12 -5
View File
@@ -2,7 +2,8 @@ import { DBStore } from '@picgo/store'
import ConfigStore from '~/main/apis/core/datastore'
import path from 'path'
import fse from 'fs-extra'
import PicGoCore from '#/types/picgo'
import { PicGo as PicGoCore } from 'picgo'
import { T } from '~/universal/i18n'
// from v2.1.2
const updateShortKeyFromVersion212 = (db: typeof ConfigStore, shortKeyConfig: IShortKeyConfigs | IOldShortKeyConfigs) => {
// #557 极端情况可能会出现配置不存在,需要重新写入
@@ -11,7 +12,7 @@ const updateShortKeyFromVersion212 = (db: typeof ConfigStore, shortKeyConfig: IS
enable: true,
key: 'CommandOrControl+Shift+P',
name: 'upload',
label: '快捷上传'
label: T('QUICK_UPLOAD')
}
db.set('settings.shortKey[picgo:upload]', defaultShortKeyConfig)
return true
@@ -22,7 +23,7 @@ const updateShortKeyFromVersion212 = (db: typeof ConfigStore, shortKeyConfig: IS
enable: true,
key: shortKeyConfig.upload,
name: 'upload',
label: '快捷上传'
label: T('QUICK_UPLOAD')
}
// @ts-ignore
delete shortKeyConfig.upload
@@ -33,7 +34,12 @@ const updateShortKeyFromVersion212 = (db: typeof ConfigStore, shortKeyConfig: IS
}
const migrateGalleryFromVersion230 = async (configDB: typeof ConfigStore, galleryDB: DBStore, picgo: PicGoCore) => {
const originGallery: ImgInfo[] = configDB.get('uploaded')
const originGallery: ImgInfo[] = picgo.getConfig('uploaded')
// if hasMigrate, we don't need to migrate
const hasMigrate: boolean = configDB.get('__migrateUploaded')
if (hasMigrate) {
return
}
const configPath = configDB.getConfigPath()
const configBakPath = path.join(path.dirname(configPath), 'config.bak.json')
// migrate gallery from config to gallery db
@@ -43,7 +49,8 @@ const migrateGalleryFromVersion230 = async (configDB: typeof ConfigStore, galler
}
await galleryDB.insertMany(originGallery)
picgo.saveConfig({
uploaded: []
uploaded: [],
__migrateUploaded: true
})
}
}
+7 -1
View File
@@ -39,13 +39,19 @@ class Server {
}
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
if (request.method === 'OPTIONS') {
handleResponse({
response
})
return
}
if (request.method === 'POST') {
if (!routers.getHandler(request.url!)) {
logger.warn(`[PicGo Server] don't support [${request.url}] url`)
handleResponse({
response,
statusCode: 404,
header: {},
body: {
success: false
}
+2
View File
@@ -24,6 +24,7 @@ router.post('/upload', async ({
// upload with clipboard
logger.info('[PicGo Server] upload clipboard file')
const res = await uploadClipboardFiles()
logger.info('[PicGo Server] upload result:', res)
if (res) {
handleResponse({
response,
@@ -51,6 +52,7 @@ router.post('/upload', async ({
})
const win = windowManager.getAvailableWindow()
const res = await uploadChoosedFiles(win.webContents, pathList)
logger.info('[PicGo Server] upload result', res.join(' ; '))
if (res.length) {
handleResponse({
response,
+4 -1
View File
@@ -4,7 +4,10 @@ export const handleResponse = ({
response,
statusCode = 200,
header = {
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'access-control-allow-headers': '*',
'access-control-allow-methods': 'POST, GET, OPTIONS',
'access-control-allow-origin': '*'
},
body = {
success: false
+97
View File
@@ -0,0 +1,97 @@
// fork from https://github.com/sindresorhus/macos-version
// cause I can't change it to common-js module
import process from 'process'
import fs from 'fs'
import semver from 'semver'
export const isMacOS = process.platform === 'darwin'
let version: string | undefined
const clean = (version: string) => {
const { length } = version.split('.')
if (length === 1) {
return `${version}.0.0`
}
if (length === 2) {
return `${version}.0`
}
return version
}
const parseVersion = (plist: string) => {
const matches = /<key>ProductVersion<\/key>\s*<string>([\d.]+)<\/string>/.exec(plist)
if (!matches) {
return
}
return matches[1].replace('10.16', '11')
}
export function macOSVersion (): string {
if (!isMacOS) {
return ''
}
if (!version) {
const file = fs.readFileSync('/System/Library/CoreServices/SystemVersion.plist', 'utf8')
const matches = parseVersion(file)
if (!matches) {
return ''
}
version = clean(matches)
}
return version
}
if (process.env.NODE_ENV === 'test') {
macOSVersion._parseVersion = parseVersion
}
export function isMacOSVersion (semverRange: string) {
if (!isMacOS) {
return false
}
semverRange = semverRange.replace('10.16', '11')
return semver.satisfies(macOSVersion(), clean(semverRange))
}
export function isMacOSVersionGreaterThanOrEqualTo (version: string) {
if (!isMacOS) {
return false
}
version = version.replace('10.16', '11')
return semver.gte(macOSVersion(), clean(version))
}
export function assertMacOSVersion (semverRange: string) {
semverRange = semverRange.replace('10.16', '11')
if (!isMacOSVersion(semverRange)) {
throw new Error(`Requires macOS ${semverRange}`)
}
}
export function assertMacOSVersionGreaterThanOrEqualTo (version: string) {
version = version.replace('10.16', '11')
if (!isMacOSVersionGreaterThanOrEqualTo(version)) {
throw new Error(`Requires macOS ${version} or later`)
}
}
export function assertMacOS () {
if (!isMacOS) {
throw new Error('Requires macOS')
}
}
+5
View File
@@ -10,6 +10,11 @@ const getPicBeds = () => {
name: picgo.helper.uploader.get(item)!.name || item,
visible: visible ? visible.visible : true
}
}).sort((a) => {
if (a.type === 'tcyun') {
return -1
}
return 0
}) as IPicBedType[]
return picBeds
}
+1 -1
View File
@@ -1,6 +1,6 @@
import path from 'path'
import fs from 'fs-extra'
import Logger from 'picgo/dist/src/lib/Logger'
import { Logger } from 'picgo'
interface IResultFileObject {
path: string
}
+6
View File
@@ -0,0 +1,6 @@
import db from '~/main/apis/core/datastore'
import { i18n } from '#/i18n'
export const initI18n = () => {
const currentLanguage = db.get('settings.language') || 'zh-CN'
i18n.setLanguage(currentLanguage)
}
+4 -30
View File
@@ -1,13 +1,9 @@
import db from '~/main/apis/core/datastore'
import { ipcMain } from 'electron'
import { showMessageBox } from '~/main/utils/common'
import { SHOW_PRIVACY_MESSAGE } from '~/universal/events/constants'
import { T } from '~/universal/i18n'
class PrivacyManager {
async init () {
ipcMain.on(SHOW_PRIVACY_MESSAGE, () => {
this.show(false)
})
async check () {
if (db.get('settings.privacyEnsure') !== true) {
const res = await this.show(true)
// cancel
@@ -25,30 +21,8 @@ class PrivacyManager {
const res = await showMessageBox({
type: 'info',
buttons: showCancel ? ['Yes', 'No'] : ['Yes'],
title: '隐私协议',
message: `
本软件尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更优质的服务,本软件会按照本隐私权政策的规定使用和收集您的一些行为信息。您在同意本软件服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本软件服务使用协议不可分割的一部分,如果不同意将无法使用。本协议会定期更新。
1.适用范围
a)在您使用本软件时,本软件会记录的您对本软件的一些操作行为信息,包括但不限于您使用本软件进行文件上传的耗时、类型、数量等信息。
2.信息的使用
a)在获得您的使用数据之后,本软件会将其上传至数据分析服务器,以便分析数据后,提供给您更好的服务。
3.信息披露
a)本软件不会将您的信息披露给不受信任的第三方。
b)根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;
c)如您出现违反中国有关法律、法规或者相关规则的情况,需要向第三方披露;
4.信息安全
a)本软件不会收集您的个人信息、密钥信息等隐私信息,所收集的信息仅仅作为改善软件、优化体验、了解软件日活等用途。
`
title: T('PRIVACY_AGREEMENT'),
message: T('PRIVACY')
})
return res
}
+13 -17
View File
@@ -1,11 +1,12 @@
import { dialog, shell } from 'electron'
import db from '~/main/apis/core/datastore'
import axios from 'axios'
import pkg from 'root/package.json'
import { lt } from 'semver'
import { T } from '~/universal/i18n'
import { getLatestVersion } from '#/utils/getLatestVersion'
const version = pkg.version
const releaseUrl = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
const releaseUrlBackup = 'https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@latest/package.json'
// const releaseUrl = 'https://api.github.com/repos/Molunerfinn/PicGo/releases'
// const releaseUrlBackup = 'https://picgo-1251750343.cos.ap-chengdu.myqcloud.com'
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
const checkVersion = async () => {
@@ -15,25 +16,20 @@ const checkVersion = async () => {
showTip = true
}
if (showTip) {
let res: any
try {
res = await axios.get(releaseUrl).catch(async () => {
const result = await axios.get(releaseUrlBackup)
return result
})
} catch (err) {
console.log(err)
}
if (res.status === 200) {
const latest = res.data.version || res.data.name
const isCheckBetaUpdate = db.get('settings.checkBetaUpdate') !== false
const res: string = await getLatestVersion(isCheckBetaUpdate)
if (res !== '') {
const latest = res
const result = compareVersion2Update(version, latest)
if (result) {
dialog.showMessageBox({
type: 'info',
title: '发现新版本',
title: T('FIND_NEW_VERSION'),
buttons: ['Yes', 'No'],
message: `发现新版本${latest},更新了很多功能,是否去下载最新的版本?`,
checkboxLabel: '以后不再提醒',
message: T('TIPS_FIND_NEW_VERSION', {
v: latest
}),
checkboxLabel: T('NO_MORE_NOTICE'),
checkboxChecked: false
}).then(res => {
if (res.response === 0) { // if selected yes
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<div id="choose-pic-bed">
<span>选择 {{ label }} 作为你默认图床</span>
<span>{{ $T('CHOOSE_YOUR_DEFAULT_PICBED', { d: label }) }}</span>
<el-switch
v-model="value"
@change="choosePicBed"
+8 -8
View File
@@ -21,7 +21,7 @@
:placeholder="item.message || item.name"
></el-input>
<el-select
v-else-if="item.type === 'list'"
v-else-if="item.type === 'list' && item.choices"
v-model="ruleForm[item.name]"
:placeholder="item.message || item.name"
>
@@ -33,7 +33,7 @@
></el-option>
</el-select>
<el-select
v-else-if="item.type === 'checkbox'"
v-else-if="item.type === 'checkbox' && item.choices"
v-model="ruleForm[item.name]"
:placeholder="item.message || item.name"
multiple
@@ -74,8 +74,8 @@ export default class extends Vue {
@Prop() private config!: any[]
@Prop() readonly type!: 'uploader' | 'transformer' | 'plugin'
@Prop() readonly id!: string
configList = []
ruleForm = {}
configList: IPicGoPluginConfig[] = []
ruleForm: IStringKeyMap = {}
@Watch('config', {
deep: true,
immediate: true
@@ -114,20 +114,20 @@ export default class extends Vue {
}
}
async handleConfig (val: any) {
async handleConfig (val: IPicGoPluginConfig[]) {
this.ruleForm = Object.assign({}, {})
const config = await this.getConfig<IPicGoPluginConfig>(this.getConfigType())
if (val.length > 0) {
this.configList = cloneDeep(val).map((item: any) => {
this.configList = cloneDeep(val).map((item) => {
let defaultValue = item.default !== undefined
? item.default
: item.type === 'checkbox'
? []
: null
if (item.type === 'checkbox') {
const defaults = item.choices.filter((i: any) => {
const defaults = item.choices?.filter((i: any) => {
return i.checked
}).map((i: any) => i.value)
}).map((i: any) => i.value) || []
defaultValue = union(defaultValue, defaults)
}
if (config && config[item.name] !== undefined) {
+3 -3
View File
@@ -1,6 +1,6 @@
<template>
<el-dialog
:title="inputBoxOptions.title || '输入框'"
:title="inputBoxOptions.title || $T('INPUT')"
:visible.sync="showInputBoxVisible"
:modal-append-to-body="false"
>
@@ -8,8 +8,8 @@
v-model="inputBoxValue"
:placeholder="inputBoxOptions.placeholder"></el-input>
<span slot="footer">
<el-button @click="handleInputBoxCancel" round>取消</el-button>
<el-button type="primary" @click="handleInputBoxConfirm" round>确定</el-button>
<el-button @click="handleInputBoxCancel" round>{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="handleInputBoxConfirm" round>{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
</template>
+31 -18
View File
@@ -21,18 +21,18 @@
>
<el-menu-item index="upload">
<i class="el-icon-upload"></i>
<span slot="title">上传区</span>
<span slot="title">{{ $T('UPLOAD_AREA') }}</span>
</el-menu-item>
<el-menu-item index="gallery">
<i class="el-icon-picture"></i>
<span slot="title">相册</span>
<span slot="title">{{ $T('GALLERY') }}</span>
</el-menu-item>
<el-submenu
index="sub-menu"
>
<template slot="title">
<i class="el-icon-menu"></i>
<span>图床设置</span>
<span>{{ $T('PICBEDS_SETTINGS') }}</span>
</template>
<template
v-for="item in picBed"
@@ -49,11 +49,11 @@
</el-submenu>
<el-menu-item index="setting">
<i class="el-icon-setting"></i>
<span slot="title">PicGo设置</span>
<span slot="title">{{ $T('PICGO_SETTINGS') }}</span>
</el-menu-item>
<el-menu-item index="plugin">
<i class="el-icon-share"></i>
<span slot="title">插件设置</span>
<span slot="title">{{ $T('PLUGIN_SETTINGS') }}</span>
</el-menu-item>
</el-menu>
<i class="el-icon-info setting-window" @click="openDialog"></i>
@@ -66,29 +66,29 @@
:class="{ 'darwin': os === 'darwin' }">
<transition name="picgo-fade" mode="out-in">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
<router-view v-if="$route && $route.meta && $route.meta.keepAlive"></router-view>
</keep-alive>
</transition>
<transition name="picgo-fade" mode="out-in">
<router-view :key="$route.path" v-if="!$route.meta.keepAlive"></router-view>
<router-view :key="$route.path" v-if="!($route && $route.meta && $route.meta.keepAlive)"></router-view>
</transition>
</el-col>
</el-row>
<el-dialog
title="赞助PicGo"
:title="$T('SPONSOR_PICGO')"
:visible.sync="visible"
width="70%"
top="10vh"
>
PicGo是免费开源的软件如果你喜欢它对你有帮助不妨请我喝杯咖啡
{{ $T('PICGO_SPONSOR_TEXT') }}
<el-row class="support">
<el-col :span="12">
<img src="https://user-images.githubusercontent.com/12621342/34188165-e7cdf372-e56f-11e7-8732-1338c88b9bb7.jpg" alt="支付宝">
<div class="support-title">支付宝</div>
<img src="https://user-images.githubusercontent.com/12621342/34188165-e7cdf372-e56f-11e7-8732-1338c88b9bb7.jpg" :alt="$T('ALIPAY')">
<div class="support-title">{{ $T('ALIPAY') }}</div>
</el-col>
<el-col :span="12">
<img src="https://user-images.githubusercontent.com/12621342/34188201-212cda84-e570-11e7-9b7a-abb298699d85.jpg" alt="支付宝">
<div class="support-title">微信</div>
<img src="https://user-images.githubusercontent.com/12621342/34188201-212cda84-e570-11e7-9b7a-abb298699d85.jpg" :alt="$T('WECHATPAY')">
<div class="support-title">{{ $T('WECHATPAY') }}</div>
</el-col>
</el-row>
</el-dialog>
@@ -96,7 +96,7 @@
class="qrcode-dialog"
top="3vh"
width="60%"
title="图床配置二维码"
:title="$T('PICBED_QRCODE')"
:visible.sync="qrcodeVisible"
:modal-append-to-body="false"
lock-scroll
@@ -107,7 +107,7 @@
size="mini"
>
<el-form-item
label="选择图床"
:label="$T('CHOOSE_PICBED')"
>
<el-select
v-model="choosedPicBedForQRCode"
@@ -128,7 +128,7 @@
class="copy-picbed-config"
@click="handleCopyPicBedConfig"
>
复制图床配置
{{ $T('COPY_PICBED_CONFIG') }}
</el-button>
</el-form-item>
</el-form>
@@ -158,7 +158,9 @@ import InputBoxDialog from '@/components/InputBoxDialog.vue'
import {
MINIMIZE_WINDOW,
CLOSE_WINDOW,
SHOW_MAIN_PAGE_MENU
SHOW_MAIN_PAGE_MENU,
SHOW_MAIN_PAGE_QRCODE,
SHOW_MAIN_PAGE_DONATION
} from '~/universal/events/constants'
@Component({
name: 'main-page',
@@ -184,6 +186,12 @@ export default class extends Vue {
ipcRenderer.send('getPicBeds')
ipcRenderer.on('getPicBeds', this.getPicBeds)
this.handleGetPicPeds()
ipcRenderer.on(SHOW_MAIN_PAGE_QRCODE, () => {
this.qrcodeVisible = true
})
ipcRenderer.on(SHOW_MAIN_PAGE_DONATION, () => {
this.visible = true
})
}
@Watch('choosedPicBedForQRCode')
@@ -242,7 +250,7 @@ export default class extends Vue {
handleCopyPicBedConfig () {
clipboard.writeText(this.picBedConfigString)
this.$message.success('图床配置复制成功')
this.$message.success(this.$T('COPY_PICBED_CONFIG_SUCCEED'))
}
getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
@@ -262,6 +270,11 @@ export default class extends Vue {
</script>
<style lang='stylus'>
$darwinBg = transparentify(#172426, #000, 0.7)
.setting-list-scroll
height 425px
overflow-y auto
overflow-x hidden
margin-right 0!important
.picgo-fade
&-enter,
&-leave,
+44 -40
View File
@@ -1,7 +1,7 @@
<template>
<div id="gallery-view">
<div class="view-title">
相册 - {{ filterList.length }} <i class="el-icon-caret-bottom" @click="toggleHandleBar" :class="{'active': handleBarActive}"></i>
{{ $T('GALLERY') }} - {{ filterList.length }} <i class="el-icon-caret-bottom" @click="toggleHandleBar" :class="{'active': handleBarActive}"></i>
</div>
<transition name="el-zoom-in-top">
<el-row v-show="handleBarActive">
@@ -14,7 +14,7 @@
collapse-tags
size="mini"
style="width: 100%"
placeholder="请选择显示的图床">
:placeholder="$T('CHOOSE_SHOWED_PICBED')">
<el-option
v-for="item in picBed"
:key="item.type"
@@ -29,7 +29,7 @@
size="mini"
style="width: 100%"
@change="handlePasteStyleChange"
placeholder="请选择粘贴的格式">
:placeholder="$T('CHOOSE_PASTE_FORMAT')">
<el-option
v-for="(value, key) in pasteStyleMap"
:key="key"
@@ -42,7 +42,7 @@
<el-row class="handle-bar" :gutter="16">
<el-col :span="12">
<el-input
placeholder="搜索"
:placeholder="$T('SEARCH')"
size="mini"
v-model="searchText">
<i slot="suffix" class="el-input__icon el-icon-close" v-if="searchText" @click="cleanSearch" style="cursor: pointer"></i>
@@ -50,17 +50,17 @@
</el-col>
<el-col :span="4">
<div class="item-base copy round" :class="{ active: isMultiple(choosedList)}" @click="multiCopy">
复制
{{ $T('COPY') }}
</div>
</el-col>
<el-col :span="4">
<div class="item-base delete round" :class="{ active: isMultiple(choosedList)}" @click="multiRemove">
删除
{{ $T('DELETE') }}
</div>
</el-col>
<el-col :span="4">
<div class="item-base all-pick round" :class="{ active: filterList.length > 0}" @click="toggleSelectAll">
{{ isAllSelected ? '取消' : '全选' }}
{{ isAllSelected ? $T('CANCEL') : $T('SELECT_ALL') }}
</div>
</el-col>
</el-row>
@@ -87,7 +87,7 @@
<i class="el-icon-document" @click="copy(item)"></i>
<i class="el-icon-edit-outline" @click="openDialog(item)"></i>
<i class="el-icon-delete" @click="remove(item.id)"></i>
<el-checkbox v-model="choosedList[item.id]" class="pull-right" @change="(val) => handleChooseImage(val, index)"></el-checkbox>
<el-checkbox v-model="choosedList[item.id ? item.id : '']" class="pull-right" @change="(val) => handleChooseImage(val, index)"></el-checkbox>
</div>
</el-col>
</el-row>
@@ -95,14 +95,14 @@
</el-row>
<el-dialog
:visible.sync="dialogVisible"
title="修改图片URL"
:title="$T('CHANGE_IMAGE_URL')"
width="500px"
:modal-append-to-body="false"
>
<el-input v-model="imgInfo.imgUrl"></el-input>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmModify"> </el-button>
<el-button @click="dialogVisible = false">{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="confirmModify">{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
</div>
@@ -285,7 +285,7 @@ export default class extends Vue {
async copy (item: ImgInfo) {
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, item)
const obj = {
title: '复制链接成功',
title: this.$T('COPY_LINK_SUCCEED'),
body: copyLink,
icon: item.url || item.imgUrl
}
@@ -295,28 +295,30 @@ export default class extends Vue {
}
}
remove (id: string) {
this.$confirm('此操作将把该图片移出相册, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const file = await this.$$db.getById(id)
await this.$$db.removeById(id)
ipcRenderer.send('removeFiles', [file])
const obj = {
title: '操作结果',
body: '删除成功'
}
const myNotification = new Notification(obj.title, obj)
myNotification.onclick = () => {
remove (id?: string) {
if (id) {
this.$confirm(this.$T('TIPS_REMOVE_LINK'), this.$T('TIPS_NOTICE'), {
confirmButtonText: this.$T('CONFIRM'),
cancelButtonText: this.$T('CANCEL'),
type: 'warning'
}).then(async () => {
const file = await this.$$db.getById(id)
await this.$$db.removeById(id)
ipcRenderer.send('removeFiles', [file])
const obj = {
title: this.$T('OPERATION_SUCCEED'),
body: ''
}
const myNotification = new Notification(obj.title, obj)
myNotification.onclick = () => {
return true
}
this.updateGallery()
}).catch((e) => {
console.log(e)
return true
}
this.updateGallery()
}).catch((e) => {
console.log(e)
return true
})
})
}
}
openDialog (item: ImgInfo) {
@@ -330,7 +332,7 @@ export default class extends Vue {
imgUrl: this.imgInfo.imgUrl
})
const obj = {
title: '修改图片URL成功',
title: this.$T('CHANGE_IMAGE_URL_SUCCEED'),
body: this.imgInfo.imgUrl,
icon: this.imgInfo.imgUrl
}
@@ -370,9 +372,11 @@ export default class extends Vue {
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
const multiRemoveNumber = Object.values(this.choosedList).filter(item => item).length
if (multiRemoveNumber) {
this.$confirm(`将在相册中移除刚才选中的 ${multiRemoveNumber} 张图片,是否继续?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$T('TIPS_WILL_REMOVE_CHOOSED_IMAGES', {
m: multiRemoveNumber
}), this.$T('TIPS_NOTICE'), {
confirmButtonText: this.$T('CONFIRM'),
cancelButtonText: this.$T('CANCEL'),
type: 'warning'
}).then(async () => {
const files: IResult<ImgInfo>[] = []
@@ -390,8 +394,8 @@ export default class extends Vue {
this.clearChoosedList()
this.choosedList = {} // 只有删除才能将这个置空
const obj = {
title: '操作结果',
body: '删除成功'
title: this.$T('OPERATION_SUCCEED'),
body: ''
}
ipcRenderer.send('removeFiles', files)
const myNotification = new Notification(obj.title, obj)
@@ -422,7 +426,7 @@ export default class extends Vue {
}
}
const obj = {
title: '批量复制链接成功',
title: this.$T('BATCH_COPY_LINK_SUCCEED'),
body: copyString.join('\n')
}
const myNotification = new Notification(obj.title, obj)
+32 -1
View File
@@ -23,6 +23,9 @@ import {
IpcRendererEvent
} from 'electron'
import { SHOW_MINI_PAGE_MENU, SET_MINI_WINDOW_POS } from '~/universal/events/constants'
import {
isUrl
} from '~/universal/utils/common'
@Component({
name: 'mini-page',
mixins: [mixin]
@@ -80,7 +83,35 @@ export default class extends Vue {
onDrop (e: DragEvent) {
this.dragover = false
this.ipcSendFiles(e.dataTransfer!.files)
const items = e.dataTransfer!.items
if (items.length === 2 && items[0].type === 'text/uri-list') {
this.handleURLDrag(items, e.dataTransfer!)
} else if (items[0].type === 'text/plain') {
const str = e.dataTransfer!.getData(items[0].type)
if (isUrl(str)) {
ipcRenderer.send('uploadChoosedFiles', [{ path: str }])
} else {
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
}
} else {
this.ipcSendFiles(e.dataTransfer!.files)
}
}
handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer) {
// text/html
// Use this data to get a more precise URL
const urlString = dataTransfer.getData(items[1].type)
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
if (urlMatch) {
ipcRenderer.send('uploadChoosedFiles', [
{
path: urlMatch[1]
}
])
} else {
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
}
}
openUploadWindow () {
+213 -137
View File
@@ -1,135 +1,169 @@
<template>
<div id="picgo-setting">
<div class="view-title">
PicGo设置 - <i class="el-icon-document" @click="goConfigPage"></i>
{{ $T('PICGO_SETTINGS') }} - <i class="el-icon-document" @click="goConfigPage"></i>
</div>
<el-row class="setting-list">
<el-col :span="16" :offset="4">
<el-col :span="20" :offset="2">
<el-row>
<el-form
label-width="160px"
label-position="right"
label-position="left"
label-width="10"
size="small"
>
<el-form-item
label="打开配置文件"
:label="$T('SETTINGS_CHOOSE_LANGUAGE')"
>
<el-button type="primary" round size="mini" @click="openFile('data.json')">点击打开</el-button>
<!-- <el-button type="primary" round size="mini" @click="openFile('data.json')">{{ $T('SETTINGS_CLICK_TO_OPEN') }}</el-button> -->
<el-select
v-model="currentLanguage"
size="mini"
style="width: 100%"
@change="handleLanguageChange"
:placeholder="$T('SETTINGS_CHOOSE_LANGUAGE')">
<el-option
v-for="item in languageList"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item
label="设置日志文件"
:label="$T('SETTINGS_OPEN_CONFIG_FILE')"
>
<el-button type="primary" round size="mini" @click="openLogSetting">点击设置</el-button>
<el-button type="primary" round size="mini" @click="openFile('data.json')">{{ $T('SETTINGS_CLICK_TO_OPEN') }}</el-button>
</el-form-item>
<el-form-item
label="修改快捷键"
:label="$T('SETTINGS_SET_LOG_FILE')"
>
<el-button type="primary" round size="mini" @click="goShortCutPage">点击设置</el-button>
<el-button type="primary" round size="mini" @click="openLogSetting">{{ $T('SETTINGS_CLICK_TO_SET') }}</el-button>
</el-form-item>
<el-form-item
label="自定义链接格式"
:label="$T('SETTINGS_SET_SHORTCUT')"
>
<el-button type="primary" round size="mini" @click="customLinkVisible = true">点击设置</el-button>
<el-button type="primary" round size="mini" @click="goShortCutPage">{{ $T('SETTINGS_CLICK_TO_SET') }}</el-button>
</el-form-item>
<el-form-item
label="设置代理和镜像地址"
:label="$T('SETTINGS_CUSTOM_LINK_FORMAT')"
>
<el-button type="primary" round size="mini" @click="proxyVisible = true">点击设置</el-button>
<el-button type="primary" round size="mini" @click="customLinkVisible = true">{{ $T('SETTINGS_CLICK_TO_SET') }}</el-button>
</el-form-item>
<el-form-item
label="设置Server"
:label="$T('SETTINGS_SET_PROXY_AND_MIRROR')"
>
<el-button type="primary" round size="mini" @click="serverVisible = true">点击设置</el-button>
<el-button type="primary" round size="mini" @click="proxyVisible = true">{{ $T('SETTINGS_CLICK_TO_SET') }}</el-button>
</el-form-item>
<el-form-item
label="检查更新"
:label="$T('SETTINGS_SET_SERVER')"
>
<el-button type="primary" round size="mini" @click="checkUpdate">点击检查</el-button>
<el-button type="primary" round size="mini" @click="serverVisible = true">{{ $T('SETTINGS_CLICK_TO_SET') }}</el-button>
</el-form-item>
<el-form-item
label="打开更新助手"
:label="$T('SETTINGS_CHECK_UPDATE')"
>
<el-button type="primary" round size="mini" @click="checkUpdate">{{ $T('SETTINGS_CLICK_TO_CHECK') }}</el-button>
</el-form-item>
<el-form-item
:label="$T('SETTINGS_OPEN_UPDATE_HELPER')"
>
<el-switch
v-model="form.updateHelper"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="updateHelperChange"
></el-switch>
</el-form-item>
<el-form-item
v-show="form.updateHelper"
label="接受Beta版本更新"
:label="$T('SETTINGS_ACCEPT_BETA_UPDATE')"
>
<el-switch
v-model="form.checkBetaUpdate"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="checkBetaUpdateChange"
></el-switch>
</el-form-item>
<el-form-item
label="开机自启"
:label="$T('SETTINGS_LAUNCH_ON_BOOT')"
>
<el-switch
v-model="form.autoStart"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleAutoStartChange"
></el-switch>
</el-form-item>
<el-form-item
label="上传前重命名"
:label="$T('SETTINGS_RENAME_BEFORE_UPLOAD')"
>
<el-switch
v-model="form.rename"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleRename"
></el-switch>
</el-form-item>
<el-form-item
label="时间戳重命名"
:label="$T('SETTINGS_TIMESTAMP_RENAME')"
>
<el-switch
v-model="form.autoRename"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleAutoRename"
></el-switch>
</el-form-item>
<el-form-item
label="开启上传提示"
:label="$T('SETTINGS_OPEN_UPLOAD_TIPS')"
>
<el-switch
v-model="form.uploadNotification"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleUploadNotification"
></el-switch>
</el-form-item>
<el-form-item
v-if="os !== 'darwin'"
label="Mini窗口置顶"
:label="$T('SETTINGS_MINI_WINDOW_ON_TOP')"
>
<el-switch
v-model="form.miniWindowOntop"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleMiniWindowOntop"
></el-switch>
</el-form-item>
<el-form-item
label="上传后自动复制URL"
:label="$T('SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD')"
>
<el-switch
v-model="form.autoCopyUrl"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleAutoCopyUrl"
></el-switch>
</el-form-item>
<el-form-item
label="选择显示的图床"
>
<div class="el-form-item__custom-label" slot="label">
{{ $T('SETTINGS_USE_BUILTIN_CLIPBOARD_UPLOAD') }}
<el-tooltip class="item" effect="dark" :content="$T('BUILTIN_CLIPBOARD_TIPS')" placement="right">
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<el-switch
v-model="form.useBuiltinClipboard"
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="useBuiltinClipboardChange"
></el-switch>
</el-form-item>
<el-form-item
:style="{ marginRight: '-64px' }"
:label="$T('CHOOSE_SHOWED_PICBED')"
>
<el-checkbox-group
v-model="form.showPicBedList"
@@ -147,7 +181,7 @@
</el-col>
</el-row>
<el-dialog
title="自定义链接格式"
:title="$T('SETTINGS_CUSTOM_LINK_FORMAT')"
:visible.sync="customLinkVisible"
:modal-append-to-body="false"
>
@@ -162,10 +196,10 @@
prop="value"
>
<div class="custom-title">
用占位符 <b>$url</b> 来表示url的位置
{{ $T('SETTINGS_TIPS_PLACEHOLDER_URL') }}
</div>
<div class="custom-title">
用占位符 <b>$fileName</b> 来表示文件名的位置
{{ $T('SETTINGS_TIPS_PLACEHOLDER_FILENAME') }}
</div>
<el-input
class="align-center"
@@ -175,15 +209,15 @@
</el-form-item>
</el-form>
<div>
[$fileName]($url)
{{ $T('SETTINGS_TIPS_SUCH_AS') }}[$fileName]($url)
</div>
<span slot="footer">
<el-button @click="cancelCustomLink" round>取消</el-button>
<el-button type="primary" @click="confirmCustomLink" round>确定</el-button>
<el-button @click="cancelCustomLink" round>{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="confirmCustomLink" round>{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
<el-dialog
title="设置代理和镜像地址"
:title="$T('SETTINGS_SET_PROXY_AND_MIRROR')"
:visible.sync="proxyVisible"
:modal-append-to-body="false"
width="70%"
@@ -196,78 +230,80 @@
label-width="120px"
>
<el-form-item
label="上传代理"
:label="$T('SETTINGS_UPLOAD_PROXY')"
>
<el-input
v-model="proxy"
:autofocus="true"
placeholder="例如http://127.0.0.1:1080"
:placeholder="`${$T('SETTINGS_TIPS_SUCH_AS')}http://127.0.0.1:1080`"
></el-input>
</el-form-item>
<el-form-item
label="插件安装代理"
:label="$T('SETTINGS_PLUGIN_INSTALL_PROXY')"
>
<el-input
v-model="npmProxy"
:autofocus="true"
placeholder="例如http://127.0.0.1:1080"
:placeholder="`${$T('SETTINGS_TIPS_SUCH_AS')}http://127.0.0.1:1080`"
></el-input>
</el-form-item>
<el-form-item
label="插件镜像地址"
:label="$T('SETTINGS_PLUGIN_INSTALL_MIRROR')"
>
<el-input
v-model="npmRegistry"
:autofocus="true"
placeholder="例如https://registry.npm.taobao.org/"
:placeholder="`${$T('SETTINGS_TIPS_SUCH_AS')}https://registry.npm.taobao.org/`"
></el-input>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="cancelProxy" round>取消</el-button>
<el-button type="primary" @click="confirmProxy" round>确定</el-button>
<el-button @click="cancelProxy" round>{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="confirmProxy" round>{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
<el-dialog
title="检查更新"
:title="$T('SETTINGS_CHECK_UPDATE')"
:visible.sync="checkUpdateVisible"
:modal-append-to-body="false"
>
<div>
当前版本{{ version }}
{{ $T('SETTINGS_CURRENT_VERSION') }}: {{ version }}
</div>
<div>
最新版本{{ latestVersion ? latestVersion : '正在获取中...' }}
{{ $T('SETTINGS_NEWEST_VERSION') }}: {{ latestVersion ? latestVersion : `${$T('SETTINGS_GETING')}...` }}
</div>
<div v-if="needUpdate">
PicGo更新啦请点击确定打开下载页面
{{ $T('SETTINGS_TIPS_HAS_NEW_VERSION') }}
</div>
<span slot="footer">
<el-button @click="cancelCheckVersion" round>取消</el-button>
<el-button type="primary" @click="confirmCheckVersion" round>确定</el-button>
<el-button @click="cancelCheckVersion" round>{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="confirmCheckVersion" round>{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
<el-dialog
title="设置日志文件"
:title="$T('SETTINGS_SET_LOG_FILE')"
:visible.sync="logFileVisible"
:modal-append-to-body="false"
width="500px"
>
<el-form
label-position="right"
label-width="100px"
label-width="150px"
>
<el-form-item
label="日志文件"
:label="$T('SETTINGS_LOG_FILE')"
>
<el-button type="primary" round size="mini" @click="openFile('picgo.log')">点击打开</el-button>
<el-button type="primary" round size="mini" @click="openFile('picgo.log')">{{ $T('SETTINGS_CLICK_TO_OPEN') }}</el-button>
</el-form-item>
<el-form-item
label="日志记录等级"
:label="$T('SETTINGS_LOG_LEVEL')"
>
<el-select
v-model="form.logLevel"
multiple
collapse-tags
style="width: 100%;"
>
<el-option
v-for="(value, key) of logLevel"
@@ -278,59 +314,70 @@
></el-option>
</el-select>
</el-form-item>
<el-form-item
:label="`${$T('SETTINGS_LOG_FILE_SIZE')} (MB)`"
>
<el-input-number
style="width: 100%;"
v-model="form.logFileSizeLimit"
:placeholder="`${$T('SETTINGS_TIPS_SUCH_AS')}10`"
:controls="false"
:min="1"
></el-input-number>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="cancelLogLevelSetting" round>取消</el-button>
<el-button type="primary" @click="confirmLogLevelSetting" round>确定</el-button>
<el-button @click="cancelLogLevelSetting" round>{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="confirmLogLevelSetting" round>{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
<el-dialog
class="server-dialog"
width="60%"
title="设置PicGo-Server"
:title="$T('SETTINGS_SET_PICGO_SERVER')"
:visible.sync="serverVisible"
:modal-append-to-body="false"
>
<div class="notice-text">
如果你不知道Server的作用请阅读文档或者不用修改配置
{{ $T('SETTINGS_TIPS_SERVER_NOTICE') }}
</div>
<el-form
label-position="right"
label-width="120px"
>
<el-form-item
label="是否开启Server"
:label="$T('SETTINGS_ENABLE_SERVER')"
>
<el-switch
v-model="server.enable"
active-text=""
inactive-text=""
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
></el-switch>
</el-form-item>
<template v-if="server.enable">
<el-form-item
label="设置监听地址"
:label="$T('SETTINGS_SET_SERVER_HOST')"
>
<el-input
type="input"
v-model="server.host"
placeholder="推荐默认地址:127.0.0.1"
:placeholder="$T('SETTINGS_TIP_PLACEHOLDER_HOST')"
></el-input>
</el-form-item>
<el-form-item
label="设置监听端口"
:label="$T('SETTINGS_SET_SERVER_PORT')"
>
<el-input
type="number"
v-model="server.port"
placeholder="推荐默认端口:36677"
:placeholder="$T('SETTINGS_TIP_PLACEHOLDER_PORT')"
></el-input>
</el-form-item>
</template>
</el-form>
<span slot="footer">
<el-button @click="cancelServerSetting" round>取消</el-button>
<el-button type="primary" @click="confirmServerSetting" round>确定</el-button>
<el-button @click="cancelServerSetting" round>{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="confirmServerSetting" round>{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
</div>
@@ -338,19 +385,20 @@
<script lang="ts">
import keyDetect from '@/utils/key-binding'
import pkg from 'root/package.json'
import { IConfig } from 'picgo/dist/src/types/index'
import { PICGO_OPEN_FILE, OPEN_URL } from '#/events/constants'
import { IConfig } from 'picgo'
import { PICGO_OPEN_FILE, OPEN_URL, CHANGE_LANGUAGE } from '#/events/constants'
import {
ipcRenderer
} from 'electron'
import { Component, Vue } from 'vue-property-decorator'
// import db from '#/datastore'
const releaseUrl = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
const releaseUrlBackup = 'https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@latest/package.json'
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
import { T, languageList } from '~/universal/i18n'
import { enforceNumber } from '~/universal/utils/common'
import { getLatestVersion } from '#/utils/getLatestVersion'
import { compare } from 'compare-versions'
import { STABLE_RELEASE_URL, BETA_RELEASE_URL } from '#/utils/static'
const customLinkRule = (rule: string, value: string, callback: (arg0?: Error) => void) => {
if (!/\$url/.test(value)) {
return callback(new Error('必须含有$url'))
return callback(new Error(T('TIPS_MUST_CONTAINS_URL')))
} else {
return callback()
}
@@ -370,9 +418,18 @@ export default class extends Vue {
miniWindowOntop: false,
logLevel: ['all'],
autoCopyUrl: true,
checkBetaUpdate: true
checkBetaUpdate: true,
useBuiltinClipboard: false,
language: 'zh-CN',
logFileSizeLimit: 10
}
languageList = languageList.map(item => ({
label: item,
value: item
}))
currentLanguage = 'zh-CN'
picBed: IPicBedType[] = []
logFileVisible = false
keyBindingVisible = false
@@ -398,12 +455,12 @@ export default class extends Vue {
}
logLevel = {
all: '全部-All',
success: '成功-Success',
error: '错误-Error',
info: '普通-Info',
warn: '提醒-Warn',
none: '不记录日志-None'
all: this.$T('SETTINGS_LOG_LEVEL_ALL'),
success: this.$T('SETTINGS_LOG_LEVEL_SUCCESS'),
error: this.$T('SETTINGS_LOG_LEVEL_ERROR'),
info: this.$T('SETTINGS_LOG_LEVEL_INFO'),
warn: this.$T('SETTINGS_LOG_LEVEL_WARN'),
none: this.$T('SETTINGS_LOG_LEVEL_NONE')
}
server = {
@@ -445,7 +502,9 @@ export default class extends Vue {
this.form.logLevel = this.initLogLevel(settings.logLevel || [])
this.form.autoCopyUrl = settings.autoCopy === undefined ? true : settings.autoCopy
this.form.checkBetaUpdate = settings.checkBetaUpdate === undefined ? true : settings.checkBetaUpdate
this.form.useBuiltinClipboard = settings.useBuiltinClipboard === undefined ? false : settings.useBuiltinClipboard
this.form.language = settings.language ?? 'zh-CN'
this.currentLanguage = settings.language ?? 'zh-CN'
this.customLink.value = settings.customLink || '$url'
this.shortKey.upload = settings.shortKey.upload
this.proxy = picBed.proxy || ''
@@ -456,6 +515,7 @@ export default class extends Vue {
host: '127.0.0.1',
enable: true
}
this.form.logFileSizeLimit = enforceNumber(settings.logFileSizeLimit) || 10
}
}
@@ -522,8 +582,8 @@ export default class extends Vue {
'settings.proxy': this.npmProxy,
'settings.registry': this.npmRegistry
})
const successNotification = new Notification('设置代理', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_SET_PROXY_AND_MIRROR'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
@@ -538,6 +598,10 @@ export default class extends Vue {
this.saveConfig('settings.checkBetaUpdate', val)
}
useBuiltinClipboardChange (val: boolean) {
this.saveConfig('settings.useBuiltinClipboard', val)
}
handleShowPicBedListChange (val: string[]) {
const list = this.picBed.map(item => {
if (!val.includes(item.name)) {
@@ -570,39 +634,23 @@ export default class extends Vue {
})
}
compareVersion2Update (current: string, latest: string) {
const currentVersion = current.split('.').map(item => parseInt(item))
const latestVersion = latest.split('.').map(item => parseInt(item))
for (let i = 0; i < 3; i++) {
if (currentVersion[i] < latestVersion[i]) {
return true
}
if (currentVersion[i] > latestVersion[i]) {
return false
}
}
return false
compareVersion2Update (current: string, latest: string): boolean {
return compare(current, latest, '<')
}
checkUpdate () {
async checkUpdate () {
this.checkUpdateVisible = true
this.$http.get(releaseUrl)
.then(res => {
this.latestVersion = res.data.name
}).catch(async () => {
this.$http.get(releaseUrlBackup)
.then(res => {
this.latestVersion = res.data.version
}).catch(() => {
this.latestVersion = '网络错误暂时无法获取'
})
})
const version = await getLatestVersion(this.form.checkBetaUpdate)
if (version) {
this.latestVersion = version
} else {
this.latestVersion = this.$T('TIPS_NETWORK_ERROR')
}
}
confirmCheckVersion () {
if (this.needUpdate) {
ipcRenderer.send(OPEN_URL, downloadUrl)
ipcRenderer.send(OPEN_URL, this.form.checkBetaUpdate ? BETA_RELEASE_URL : STABLE_RELEASE_URL)
}
this.checkUpdateVisible = false
}
@@ -619,13 +667,13 @@ export default class extends Vue {
handleMiniWindowOntop (val: boolean) {
this.saveConfig('settings.miniWindowOntop', val)
this.$message.info('需要重启生效')
this.$message.info(this.$T('TIPS_NEED_RELOAD'))
}
handleAutoCopyUrl (val: boolean) {
this.saveConfig('settings.autoCopy', val)
const successNotification = new Notification('设置自动复制链接', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
@@ -634,13 +682,14 @@ export default class extends Vue {
confirmLogLevelSetting () {
if (this.form.logLevel.length === 0) {
return this.$message.error('请选择日志记录等级')
return this.$message.error(this.$T('TIPS_PLEASE_CHOOSE_LOG_LEVEL'))
}
this.saveConfig({
'settings.logLevel': this.form.logLevel
'settings.logLevel': this.form.logLevel,
'settings.logFileSizeLimit': this.form.logFileSizeLimit
})
const successNotification = new Notification('设置日志', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_SET_LOG_FILE'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
@@ -651,6 +700,7 @@ export default class extends Vue {
async cancelLogLevelSetting () {
this.logFileVisible = false
let logLevel = await this.getConfig<string | string[]>('settings.logLevel')
const logFileSizeLimit = await this.getConfig<number>('settings.logFileSizeLimit') || 10
if (!Array.isArray(logLevel)) {
if (logLevel && logLevel.length > 0) {
logLevel = [logLevel]
@@ -659,6 +709,7 @@ export default class extends Vue {
}
}
this.form.logLevel = logLevel
this.form.logFileSizeLimit = logFileSizeLimit
}
confirmServerSetting () {
@@ -667,8 +718,8 @@ export default class extends Vue {
this.saveConfig({
'settings.server': this.server
})
const successNotification = new Notification('设置PicGo-Server', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_SET_PICGO_SERVER'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
@@ -707,6 +758,15 @@ export default class extends Vue {
return false
}
handleLanguageChange (val: string) {
this.$i18n.setLanguage(val)
this.forceUpdate()
ipcRenderer.send(CHANGE_LANGUAGE, val)
this.saveConfig({
'settings.language': val
})
}
goConfigPage () {
ipcRenderer.send(OPEN_URL, 'https://picgo.github.io/PicGo-Doc/zh/guide/config.html#picgo设置')
}
@@ -739,10 +799,28 @@ export default class extends Vue {
overflow-x hidden
.setting-list
.el-form
&-item
display: flex
justify-content space-between
padding-top 8px
padding-bottom 8px
border-bottom 1px solid darken(#eee, 50%)
margin-bottom 0
&:last-child
border-bottom none
&::after
display none
&::before
display none
label
line-height 32px
padding-bottom 0
color #eee
flex-basis: 50%
flex-shrink: 0
.el-form-item__custom-label
display flex
align-items center
.el-button-group
width 100%
.el-button
@@ -756,9 +834,7 @@ export default class extends Vue {
&.is-active
color #409EFF
.el-icon-question
font-size 20px
float right
margin-top 9px
margin-left 4px
color #eee
cursor pointer
transition .2s color ease-in-out
+33 -25
View File
@@ -1,7 +1,7 @@
<template>
<div id="plugin-view">
<div class="view-title">
插件设置 -
{{ $T('PLUGIN_SETTINGS') }} -
<el-tooltip :content="pluginListToolTip" placement="right">
<i class="el-icon-goods" @click="goAwesomeList"></i>
</el-tooltip>
@@ -12,7 +12,7 @@
<el-row class="handle-bar" :class="{ 'cut-width': pluginList.length > 6 }">
<el-input
v-model="searchText"
placeholder="搜索npm上的PicGo插件,或者点击上方按钮查看优秀插件列表"
:placeholder="$T('PLUGIN_SEARCH_PLACEHOLDER')"
size="small"
>
<i slot="suffix" class="el-input__icon el-icon-close" v-if="searchText" @click="cleanSearch" style="cursor: pointer"></i>
@@ -43,19 +43,19 @@
<template v-if="searchText">
<template v-if="!item.hasInstall">
<span class="config-button install" v-if="!item.ing" @click="installPlugin(item)">
安装
{{ $T('PLUGIN_INSTALL') }}
</span>
<span v-else-if="item.ing" class="config-button ing">
安装中
{{ $T('PLUGIN_INSTALLING') }}
</span>
</template>
<span v-else class="config-button ing">
已安装
{{ $T('PLUGIN_INSTALLED') }}
</span>
</template>
<template v-else>
<span v-if="item.ing" class="config-button ing">
进行中
{{ $T('PLUGIN_DOING_SOMETHING') }}
</span>
<template v-else>
<i
@@ -77,12 +77,14 @@
</el-col>
</el-row>
<el-row v-show="needReload" class="reload-mask" :class="{ 'cut-width': pluginList.length > 6 }">
<el-button type="primary" @click="reloadApp" size="mini" round>重启以生效</el-button>
<el-button type="primary" @click="reloadApp" size="mini" round>{{ $T('TIPS_NEED_RELOAD') }}</el-button>
</el-row>
<el-dialog
:visible.sync="dialogVisible"
:modal-append-to-body="false"
:title="`配置${configName}`"
:title="$T('CONFIG_THING', {
c: configName
})"
width="70%"
>
<config-form
@@ -93,8 +95,8 @@
>
</config-form>
<span slot="footer">
<el-button @click="dialogVisible = false" round>取消</el-button>
<el-button type="primary" @click="handleConfirmConfig" round>确定</el-button>
<el-button @click="dialogVisible = false" round>{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="handleConfirmConfig" round>{{ $T('CONFIRM') }}</el-button>
</span>
</el-dialog>
</div>
@@ -118,7 +120,8 @@ import {
PICGO_CONFIG_PLUGIN,
PICGO_HANDLE_PLUGIN_ING,
PICGO_TOGGLE_PLUGIN,
SHOW_PLUGIN_PAGE_MENU
SHOW_PLUGIN_PAGE_MENU,
DEFAULT_LOGO
} from '#/events/constants'
@Component({
@@ -138,11 +141,11 @@ export default class extends Vue {
pluginNameList: string[] = []
loading = true
needReload = false
pluginListToolTip = '插件列表'
importLocalPluginToolTip = '导入本地插件'
pluginListToolTip = this.$T('PLUGIN_LIST')
importLocalPluginToolTip = this.$T('PLUGIN_IMPORT_LOCAL')
id = ''
os = ''
defaultLogo: string = 'this.src="https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@dev/public/roundLogo.png"'
defaultLogo: string = ''
get npmSearchText () {
return this.searchText.match('picgo-plugin-')
? this.searchText
@@ -245,11 +248,19 @@ export default class extends Vue {
this.needReload = true
}
})
ipcRenderer.on(DEFAULT_LOGO, (evt: IpcRendererEvent, logoPath) => {
this.defaultLogo = `this.src="${logoPath.replace(/\\/g, '/')}"`
})
this.getPluginList()
this.getSearchResult = debounce(this.getSearchResult, 50)
this.getDefaultLogo()
this.needReload = await this.getConfig<boolean>('needReload') || false
}
getDefaultLogo () {
ipcRenderer.send(DEFAULT_LOGO)
}
async buildContextMenu (plugin: IPicGoPlugin) {
ipcRenderer.send(SHOW_PLUGIN_PAGE_MENU, plugin)
}
@@ -264,9 +275,9 @@ export default class extends Vue {
installPlugin (item: IPicGoPlugin) {
if (!item.gui) {
this.$confirm('该插件未对可视化界面进行优化, 是否继续安装?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$T('TIPS_PLUGIN_NOT_GUI_IMPLEMENT'), this.$T('TIPS_NOTICE'), {
confirmButtonText: this.$T('CONFIRM'),
cancelButtonText: this.$T('CANCEL'),
type: 'warning'
}).then(() => {
item.ing = true
@@ -309,8 +320,8 @@ export default class extends Vue {
needReload: true
})
this.needReload = true
const successNotification = new Notification('更新成功', {
body: '请点击此通知重启应用以生效'
const successNotification = new Notification(this.$T('PLUGIN_UPDATE_SUCCEED'), {
body: this.$T('TIPS_NEED_RELOAD')
})
successNotification.onclick = () => {
this.reloadApp()
@@ -342,8 +353,8 @@ export default class extends Vue {
})
break
}
const successNotification = new Notification('设置结果', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_RESULT'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
@@ -426,10 +437,6 @@ export default class extends Vue {
ipcRenderer.send(OPEN_URL, 'https://github.com/PicGo/Awesome-PicGo')
}
saveConfig (data: IObj) {
ipcRenderer.send('picgoSaveData', data)
}
handleImportLocalPlugin () {
ipcRenderer.send('importLocalPlugin')
this.loading = true
@@ -441,6 +448,7 @@ export default class extends Vue {
ipcRenderer.removeAllListeners('uninstallSuccess')
ipcRenderer.removeAllListeners('updateSuccess')
ipcRenderer.removeAllListeners('hideLoading')
ipcRenderer.removeAllListeners(DEFAULT_LOGO)
}
}
</script>
+11 -7
View File
@@ -4,7 +4,7 @@
@submit.native.prevent
>
<el-form-item
label="文件改名"
:label="$T('FILE_RENAME')"
>
<el-input
v-model="fileName"
@@ -15,13 +15,14 @@
</el-form>
<el-row>
<div class="pull-right">
<el-button @click="cancel" round size="mini">取消</el-button>
<el-button type="primary" @click="confirmName" round size="mini">确定</el-button>
<el-button @click="cancel" round size="mini">{{ $T('CANCEL') }}</el-button>
<el-button type="primary" @click="confirmName" round size="mini">{{ $T('CONFIRM') }}</el-button>
</div>
</el-row>
</div>
</template>
<script lang="ts">
import { RENAME_FILE_NAME } from '#/events/constants'
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/mixin'
import {
@@ -34,20 +35,23 @@ import {
})
export default class extends Vue {
fileName: string = ''
originName: string = ''
id: string | null = null
created () {
ipcRenderer.on('rename', (event: IpcRendererEvent, name: string, id: string) => {
this.fileName = name
ipcRenderer.on(RENAME_FILE_NAME, (event: IpcRendererEvent, newName: string, originName: string, id: string) => {
this.fileName = newName
this.originName = originName
this.id = id
})
}
confirmName () {
ipcRenderer.send(`rename${this.id}`, this.fileName)
ipcRenderer.send(`${RENAME_FILE_NAME}${this.id}`, this.fileName)
}
cancel () {
ipcRenderer.send(`rename${this.id}`, null)
// if cancel, use origin file name
ipcRenderer.send(`${RENAME_FILE_NAME}${this.id}`, this.originName)
}
beforeDestroy () {
+24 -15
View File
@@ -1,16 +1,19 @@
<template>
<div id="shortcut-page">
<div class="view-title">
快捷键设置
{{ $T('SETTINGS_SET_SHORTCUT') }}
</div>
<el-row>
<el-col :span="20" :offset="2">
<el-table
class="shortcut-page-table-border"
:data="list"
size="mini"
header-cell-class-name="shortcut-page-table-border"
cell-class-name="shortcut-page-table-border"
>
<el-table-column
label="快捷键名称"
:label="$T('SHORTCUT_NAME')"
>
<template slot-scope="scope">
{{ scope.row.label ? scope.row.label : scope.row.name }}
@@ -18,24 +21,24 @@
</el-table-column>
<el-table-column
width="160px"
label="快捷键绑定"
:label="$T('SHORTCUT_BIND')"
prop="key"
>
</el-table-column>
<el-table-column
label="状态"
:label="$T('SHORTCUT_STATUS')"
>
<template slot-scope="scope">
<el-tag
size="mini"
:type="scope.row.enable ? 'success' : 'danger'"
>
{{ scope.row.enable ? '已启用' : '已禁用' }}
{{ scope.row.enable ? $T('SHORTCUT_ENABLED') : $T('SHORTCUT_DISABLED') }}
</el-tag>
</template>
</el-table-column>
<el-table-column
label="来源"
:label="$T('SHORTCUT_SOURCE')"
width="100px"
>
<template slot-scope="scope">
@@ -43,7 +46,7 @@
</template>
</el-table-column>
<el-table-column
label="操作"
:label="$T('SHORTCUT_HANDLE')"
>
<template slot-scope="scope">
<el-button
@@ -53,14 +56,14 @@
disabled: scope.row.enable
}"
type="text">
{{ scope.row.enable ? '禁用' : '启用' }}
{{ scope.row.enable ? $T('SHORTCUT_DISABLE') : $T('SHORTCUT_ENABLE') }}
</el-button>
<el-button
class="edit"
size="mini"
@click="openKeyBindingDialog(scope.row, scope.$index)"
type="text">
编辑
{{ $T('SHORTCUT_EDIT') }}
</el-button>
</template>
</el-table-column>
@@ -68,7 +71,7 @@
</el-col>
</el-row>
<el-dialog
title="修改上传快捷键"
:title="$T('SHORTCUT_CHANGE_UPLOAD')"
:visible.sync="keyBindingVisible"
:modal-append-to-body="false"
>
@@ -76,9 +79,7 @@
label-position="top"
label-width="80px"
>
<el-form-item
label="快捷上传"
>
<el-form-item>
<el-input
class="align-center"
@keydown.native.prevent="keyDetect($event)"
@@ -88,8 +89,12 @@
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="cancelKeyBinding" round>取消</el-button>
<el-button type="primary" @click="confirmKeyBinding" round>确定</el-button>
<el-button @click="cancelKeyBinding" round>
{{ $T('CANCEL') }}
</el-button>
<el-button type="primary" @click="confirmKeyBinding" round>
{{ $T('CONFIRM') }}
</el-button>
</span>
</el-dialog>
</div>
@@ -175,6 +180,8 @@ export default class extends Vue {
</script>
<style lang='stylus'>
#shortcut-page
.shortcut-page-table-border
border-color darken(#eee, 50%)
.el-dialog__body
padding 10px 20px
.el-form-item
@@ -187,6 +194,8 @@ export default class extends Vue {
.el-table
background-color: transparent
color #ddd
&::before
background-color darken(#eee, 50%)
thead
color #bbb
th,tr
+33 -16
View File
@@ -1,9 +1,9 @@
<template>
<div id="tray-page">
<!-- <div class="header-arrow"></div> -->
<div class="open-main-window" @click="openSettingWindow">{{ $T('OPEN_MAIN_WINDOW') }}</div>
<div class="content">
<div class="wait-upload-img" v-if="clipboardFiles.length > 0">
<div class="list-title">等待上传</div>
<div class="list-title">{{ $T('WAIT_TO_UPLOAD') }}</div>
<div v-for="(item, index) in clipboardFiles" :key="index" class="img-list">
<div
class="upload-img__container"
@@ -14,7 +14,7 @@
</div>
</div>
<div class="uploaded-img">
<div class="list-title">已上传</div>
<div class="list-title">{{ $T('ALREADY_UPLOAD') }}</div>
<div v-for="item in files" :key="item.imgUrl" class="img-list">
<div class="upload-img__container" @click="copyTheLink(item)">
<img :src="item.imgUrl" class="upload-img">
@@ -30,7 +30,8 @@ import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/mixin'
import { ipcRenderer } from 'electron'
import { IResult } from '@picgo/store/dist/types'
import { PASTE_TEXT } from '#/events/constants'
import { PASTE_TEXT, OPEN_WINDOW } from '#/events/constants'
import { IWindowList } from '#/types/enum'
@Component({
name: 'tray-page',
@@ -39,7 +40,7 @@ import { PASTE_TEXT } from '#/events/constants'
export default class extends Vue {
files: IResult<ImgInfo>[] = []
notification = {
title: '复制链接成功',
title: this.$T('COPY_LINK_SUCCEED'),
body: '',
icon: ''
}
@@ -50,6 +51,10 @@ export default class extends Vue {
return this.files.slice().reverse()
}
openSettingWindow () {
this.sendToMain(OPEN_WINDOW, IWindowList.SETTING_WINDOW)
}
async getData () {
this.files = (await this.$$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
}
@@ -124,6 +129,18 @@ body::-webkit-scrollbar
width 0px
#tray-page
background-color transparent
.open-main-window
background #000
height 20px
line-height 20px
text-align center
color #858585
font-size 12px
cursor pointer
transition all .2s ease-in-out
&:hover
color: #fff;
background #49B1F5
.list-title
text-align center
color #858585
@@ -138,19 +155,19 @@ body::-webkit-scrollbar
bottom 0
left 18px
background #858585
.header-arrow
position absolute
top 12px
left 50%
margin-left -10px
width: 0;
height: 0;
border-left: 10px solid transparent
border-right: 10px solid transparent
border-bottom: 10px solid rgba(255,255,255, 1)
// .header-arrow
// position absolute
// top 12px
// left 50%
// margin-left -10px
// width: 0;
// height: 0;
// border-left: 10px solid transparent
// border-right: 10px solid transparent
// border-bottom: 10px solid rgba(255,255,255, 1)
.content
position absolute
top 0px
top 20px
width 100%
.img-list
padding 8px 8px
+11 -11
View File
@@ -3,7 +3,7 @@
<el-row :gutter="16">
<el-col :span="20" :offset="2">
<div class="view-title">
图片上传 - {{ picBedName }} <i class="el-icon-caret-bottom" @click="handleChangePicBed"></i>
{{ $T('PICTURE_UPLOAD') }} - {{ picBedName }} <i class="el-icon-caret-bottom" @click="handleChangePicBed"></i>
</div>
<div
id="upload-area"
@@ -15,7 +15,7 @@
<div id="upload-dragger" @click="openUplodWindow">
<i class="el-icon-upload"></i>
<div class="upload-dragger__text">
将文件拖到此处 <span>点击上传</span>
{{ $T('DRAG_FILE_TO_HERE') }} <span>{{ $T('CLICK_TO_UPLOAD') }}</span>
</div>
<input type="file" id="file-uploader" @change="onChange" multiple>
</div>
@@ -30,7 +30,7 @@
<div class="paste-style">
<div class="el-col-16">
<div class="paste-style__text">
链接格式
{{ $T('LINK_FORMAT') }}
</div>
<el-radio-group v-model="pasteStyle" size="mini"
@change="handlePasteStyleChange"
@@ -41,14 +41,14 @@
<el-radio-button label="HTML"></el-radio-button>
<el-radio-button label="URL"></el-radio-button>
<el-radio-button label="UBB"></el-radio-button>
<el-radio-button label="Custom" title="自定义"></el-radio-button>
<el-radio-button label="Custom" :title="$T('CUSTOM')"></el-radio-button>
</el-radio-group>
</div>
<div class="el-col-8">
<div class="paste-style__text">
快捷上传
{{ $T('QUICK_UPLOAD') }}
</div>
<el-button type="primary" round size="mini" @click="uploadClipboardFiles" class="quick-upload" style="width: 50%">剪贴板图片</el-button>
<el-button type="primary" round size="mini" @click="uploadClipboardFiles" class="quick-upload" style="width: 50%">{{ $T('CLIPBOARD_PICTURE') }}</el-button>
<el-button type="primary" round size="mini" @click="uploadURLFiles" class="quick-upload" style="width: 46%; margin-left: 6px">URL</el-button>
</div>
</div>
@@ -131,7 +131,7 @@ export default class extends Vue {
if (isUrl(str)) {
ipcRenderer.send('uploadChoosedFiles', [{ path: str }])
} else {
this.$message.error('请拖入合法的图片文件或者图片URL地址')
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
}
} else {
this.ipcSendFiles(e.dataTransfer!.files)
@@ -150,7 +150,7 @@ export default class extends Vue {
}
])
} else {
this.$message.error('请拖入合法的图片文件或者图片URL地址')
this.$message.error(this.$T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
}
}
@@ -193,8 +193,8 @@ export default class extends Vue {
const str = await navigator.clipboard.readText()
this.$bus.$emit(SHOW_INPUT_BOX, {
value: isUrl(str) ? str : '',
title: '请输入URL',
placeholder: 'http://或者https://开头'
title: this.$T('TIPS_INPUT_URL'),
placeholder: this.$T('TIPS_HTTP_PREFIX')
})
}
@@ -205,7 +205,7 @@ export default class extends Vue {
path: val
}])
} else {
this.$message.error('请输入合法的URL')
this.$message.error(this.$T('TIPS_INPUT_VALID_URL'))
}
}
+2 -1
View File
@@ -72,6 +72,7 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/ConfirmButtonMixin'
import { trimValues } from '@/utils/common'
@Component({
name: 'aliyun',
mixins: [mixin]
@@ -99,7 +100,7 @@ export default class extends Vue {
this.$refs.aliyun.validate((valid) => {
if (valid) {
this.saveConfig({
'picBed.aliyun': this.form
'picBed.aliyun': trimValues(this.form)
})
const successNotification = new window.Notification('设置结果', {
body: '设置成功'
+2 -1
View File
@@ -59,6 +59,7 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/ConfirmButtonMixin'
import { trimValues } from '@/utils/common'
@Component({
name: 'github',
mixins: [mixin]
@@ -84,7 +85,7 @@ export default class extends Vue {
this.$refs.github.validate((valid) => {
if (valid) {
this.saveConfig({
'picBed.github': this.form
'picBed.github': trimValues(this.form)
})
const successNotification = new Notification('设置结果', {
body: '设置成功'
+2 -1
View File
@@ -39,6 +39,7 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/ConfirmButtonMixin'
import { trimValues } from '@/utils/common'
@Component({
name: 'imgur',
mixins: [mixin]
@@ -61,7 +62,7 @@ export default class extends Vue {
this.$refs.imgur.validate((valid) => {
if (valid) {
this.saveConfig({
'picBed.imgur': this.form
'picBed.imgur': trimValues(this.form)
})
const successNotification = new Notification('设置结果', {
body: '设置成功'
+11 -10
View File
@@ -3,7 +3,7 @@
<el-row :gutter="16" class="setting-list">
<el-col :span="16" :offset="4">
<div class="view-title">
{{ picBedName }}设置
{{ picBedName }}{{ $T('SETTINGS') }}
</div>
<config-form
v-if="config.length > 0"
@@ -14,14 +14,14 @@
>
<el-form-item>
<el-button-group>
<el-button type="primary" @click="handleConfirm" round>确定</el-button>
<el-button type="success" @click="setDefaultPicBed(type)" round :disabled="defaultPicBed === type">设为默认图床</el-button>
<el-button type="primary" @click="handleConfirm" round>{{ $T('CONFIRM') }}</el-button>
<el-button type="success" @click="setDefaultPicBed(type)" round :disabled="defaultPicBed === type">{{ $T('SETTINGS_SET_DEFAULT_PICBED') }}</el-button>
</el-button-group>
</el-form-item>
</config-form>
<div v-else class="single">
<div class="notice">暂无配置项</div>
<el-button type="success" @click="setDefaultPicBed(type)" round :disabled="defaultPicBed === type" size="mini">设为默认图床</el-button>
<div class="notice">{{ $T('SETTINGS_NOT_CONFIG_OPTIONS') }}</div>
<el-button type="success" @click="setDefaultPicBed(type)" round :disabled="defaultPicBed === type" size="mini">{{ $T('SETTINGS_SET_DEFAULT_PICBED') }}</el-button>
</div>
</el-col>
</el-row>
@@ -35,6 +35,7 @@ import {
ipcRenderer,
IpcRendererEvent
} from 'electron'
import { trimValues } from '@/utils/common'
@Component({
name: 'OtherPicBed',
@@ -58,10 +59,10 @@ export default class extends Vue {
const result = await this.$refs.configForm.validate()
if (result !== false) {
this.saveConfig({
[`picBed.${this.type}`]: result
[`picBed.${this.type}`]: trimValues(result)
})
const successNotification = new Notification('设置结果', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_RESULT'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
@@ -76,8 +77,8 @@ export default class extends Vue {
})
// @ts-ignore 来自mixin的数据
this.defaultPicBed = type
const successNotification = new Notification('设置默认图床', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_DEFAULT_PICBED'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
+2 -1
View File
@@ -74,6 +74,7 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/ConfirmButtonMixin'
import { trimValues } from '@/utils/common'
@Component({
name: 'qiniu',
mixins: [mixin]
@@ -101,7 +102,7 @@ export default class extends Vue {
this.$refs.qiniu.validate((valid) => {
if (valid) {
this.saveConfig({
'picBed.qiniu': this.form
'picBed.qiniu': trimValues(this.form)
})
const successNotification = new Notification('设置结果', {
body: '设置成功'
+3 -2
View File
@@ -17,7 +17,7 @@
:rules="{
required: true, message: 'Token不能为空', trigger: 'blur'
}">
<el-input v-model="form.token" type="password" placeholder="token" @keyup.native.enter="confirm('smmsForm')"></el-input>
<el-input v-model="form.token" type="password" placeholder="token" @keyup.native.enter="confirm"></el-input>
</el-form-item>
<el-form-item>
<el-button-group>
@@ -33,6 +33,7 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/ConfirmButtonMixin'
import { trimValues } from '@/utils/common'
@Component({
name: 'smms',
mixins: [mixin]
@@ -54,7 +55,7 @@ export default class extends Vue {
this.$refs.smms.validate((valid) => {
if (valid) {
this.saveConfig({
'picBed.smms': this.form
'picBed.smms': trimValues(this.form)
})
const successNotification = new window.Notification('设置结果', {
body: '设置成功'
+13 -5
View File
@@ -1,6 +1,6 @@
<template>
<div id="tcyun-view">
<el-row :gutter="16">
<el-row :gutter="16" class="setting-list-scroll">
<el-col :span="16" :offset="4">
<div class="view-title">
腾讯云COS设置
@@ -74,6 +74,11 @@
>
<el-input v-model="form.customUrl" @keyup.native.enter="confirm" placeholder="例如https://xxxx.com"></el-input>
</el-form-item>
<el-form-item
label="设定网址后缀"
>
<el-input v-model="form.options" @keyup.native.enter="confirm" placeholder="例如?imageMogr2"></el-input>
</el-form-item>
<el-form-item>
<el-button-group>
<el-button type="primary" @click="confirm" round>确定</el-button>
@@ -90,12 +95,14 @@ import { ipcRenderer } from 'electron'
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/ConfirmButtonMixin'
import { OPEN_URL } from '#/events/constants'
import { ITcyunConfig } from 'picgo/dist/types'
import { trimValues } from '@/utils/common'
@Component({
name: 'tcyun',
mixins: [mixin]
})
export default class extends Vue {
form: ITcYunConfig = {
form: ITcyunConfig = {
secretId: '',
secretKey: '',
bucket: '',
@@ -103,11 +110,12 @@ export default class extends Vue {
area: '',
path: '',
customUrl: '',
version: 'v4'
version: 'v5',
options: ''
}
async created () {
const config = await this.getConfig<ITcYunConfig>('picBed.tcyun')
const config = await this.getConfig<ITcyunConfig>('picBed.tcyun')
if (config) {
this.form = Object.assign({}, config)
}
@@ -118,7 +126,7 @@ export default class extends Vue {
this.$refs.tcyun.validate((valid) => {
if (valid) {
this.saveConfig({
'picBed.tcyun': this.form
'picBed.tcyun': trimValues(this.form)
})
const successNotification = new window.Notification('设置结果', {
body: '设置成功'
+6 -3
View File
@@ -67,21 +67,24 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import mixin from '@/utils/ConfirmButtonMixin'
import { IUpyunConfig } from 'picgo/dist/types'
import { trimValues } from '@/utils/common'
@Component({
name: 'upyun',
mixins: [mixin]
})
export default class extends Vue {
form: IUpYunConfig = {
form: IUpyunConfig = {
bucket: '',
operator: '',
password: '',
options: '',
url: '',
path: ''
}
async created () {
const config = await this.getConfig<IUpYunConfig>('picBed.upyun')
const config = await this.getConfig<IUpyunConfig>('picBed.upyun')
if (config) {
this.form = Object.assign({}, config)
}
@@ -92,7 +95,7 @@ export default class extends Vue {
this.$refs.tcyun.validate((valid) => {
if (valid) {
this.saveConfig({
'picBed.upyun': this.form
'picBed.upyun': trimValues(this.form)
})
const successNotification = new Notification('设置结果', {
body: '设置成功'
+3 -3
View File
@@ -1,5 +1,5 @@
import { Component, Vue } from 'vue-property-decorator'
import { IConfig } from 'picgo/dist/src/types'
import { IConfig } from 'picgo'
@Component
export default class extends Vue {
defaultPicBed = 'smms'
@@ -16,8 +16,8 @@ export default class extends Vue {
'picBed.uploader': type
})
this.defaultPicBed = type
const successNotification = new Notification('设置默认图床', {
body: '设置成功'
const successNotification = new Notification(this.$T('SETTINGS_DEFAULT_PICBED'), {
body: this.$T('TIPS_SET_SUCCEED')
})
successNotification.onclick = () => {
return true
+10
View File
@@ -0,0 +1,10 @@
import { i18n } from '~/universal/i18n'
export const handleURLParams = () => {
const url = new URL(location.href)
const search = new URLSearchParams(url.search)
if (search.has('lang')) {
const lang = search.get('lang') || 'zh-CN'
i18n.setLanguage(lang)
}
}
+8
View File
@@ -8,3 +8,11 @@ export const handleTalkingDataEvent = (data: ITalkingDataOptions) => {
console.log('talkingData', data)
}
}
export const trimValues = (obj: IStringKeyMap) => {
const newObj = {} as IStringKeyMap
Object.keys(obj).forEach(key => {
newObj[key] = typeof obj[key] === 'string' ? obj[key].trim() : obj[key]
})
return newObj
}
+15 -1
View File
@@ -1,9 +1,15 @@
import { Component, Vue } from 'vue-property-decorator'
import { ipcRenderer, IpcRendererEvent } from 'electron'
import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG } from '#/events/constants'
import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG, FORCE_UPDATE } from '#/events/constants'
import { uuid } from 'uuidv4'
@Component
export default class extends Vue {
created () {
this.$bus.$on(FORCE_UPDATE, () => {
this.$forceUpdate()
})
}
// support string key + value or object config
saveConfig (config: IObj | string, value?: any) {
if (typeof config === 'string') {
@@ -27,4 +33,12 @@ export default class extends Vue {
ipcRenderer.send(PICGO_GET_CONFIG, key, callbackId)
})
}
forceUpdate () {
this.$bus.$emit(FORCE_UPDATE)
}
sendToMain (channel: string, ...args: any[]) {
ipcRenderer.send(channel, ...args)
}
}
+7
View File
@@ -28,3 +28,10 @@ export const PICGO_HANDLE_PLUGIN_ING = 'PICGO_HANDLE_PLUGIN_ING'
export const PICGO_TOGGLE_PLUGIN = 'PICGO_TOGGLE_PLUGIN'
export const PASTE_TEXT = 'PASTE_TEXT'
export const SET_MINI_WINDOW_POS = 'SET_MINI_WINDOW_POS'
export const RENAME_FILE_NAME = 'RENAME_FILE_NAME'
export const SHOW_MAIN_PAGE_QRCODE = 'SHOW_MAIN_PAGE_QRCODE'
export const SHOW_MAIN_PAGE_DONATION = 'SHOW_MAIN_PAGE_DONATION'
export const FORCE_UPDATE = 'FORCE_UPDATE'
export const CHANGE_LANGUAGE = 'CHANGE_LANGUAGE'
export const OPEN_WINDOW = 'OPEN_WINDOW'
export const DEFAULT_LOGO = 'DEFAULT_LOGO'
+221
View File
@@ -0,0 +1,221 @@
import { ILocales } from './zh-CN'
/* eslint-disable no-template-curly-in-string */
export const EN: ILocales = {
ABOUT: 'About',
OPEN_MAIN_WINDOW: 'Open Main Window',
CHOOSE_DEFAULT_PICBED: 'Choose Default Picbed',
OPEN_UPDATE_HELPER: 'Open Update Helper',
PRIVACY_AGREEMENT: 'Privacy Agreement',
RELOAD_APP: 'Reload App',
UPLOAD_FAILED: 'Upload Failed',
UPLOAD_SUCCEED: 'Upload Succeed',
UPLOAD_PROGRESS: 'Upload Progress',
OPERATION_FAILED: 'Operation Failed',
OPERATION_SUCCEED: 'Operation Succeed',
UPLOADING: 'Uploading',
QUICK_UPLOAD: 'Quick Upload',
UPLOAD_BY_CLIPBOARD: 'Upload by Clipboard',
HIDE_WINDOW: 'Hide Window',
SPONSOR_PICGO: 'Sponsor PicGo',
SHOW_PICBED_QRCODE: 'Show Picbed Qrcode',
PICBED_QRCODE: 'Picbed Qrcode',
ENABLE: 'Enable',
DISABLE: 'Disable',
CONFIG_THING: 'Config ${c}',
FIND_NEW_VERSION: 'Find New Version',
SHOW_DEVTOOLS: 'Show Devtools',
NO_MORE_NOTICE: 'No More Notice',
// ---renderer i18n---
CHOOSE_YOUR_DEFAULT_PICBED: 'Choose ${d} as your default picbed:',
UPLOAD_AREA: 'Upload Area',
GALLERY: 'Gallery',
PICBEDS_SETTINGS: 'Picbeds Settings',
PICGO_SETTINGS: 'PicGo Settings',
PLUGIN_SETTINGS: 'Plugins Settings',
PICGO_SPONSOR_TEXT: 'PicGo is free software, if you like it, please don\'t forget to buy me a coffee?',
ALIPAY: 'Alipay',
WECHATPAY: 'Wechat Pay',
CHOOSE_PICBED: 'Choose Picbed',
COPY_PICBED_CONFIG: 'Copy Picbed Config',
COPY_PICBED_CONFIG_SUCCEED: 'Copy Picbed Config Succeed',
INPUT: 'Input',
CANCEL: 'Cancel',
CONFIRM: 'Confirm',
CHOOSE_SHOWED_PICBED: 'Choose Showed Picbed',
CHOOSE_PASTE_FORMAT: 'Choose Paste Format',
SEARCH: 'Search',
COPY: 'Copy',
DELETE: 'Delete',
SELECT_ALL: 'Select All',
CHANGE_IMAGE_URL: 'Change Image URL',
CHANGE_IMAGE_URL_SUCCEED: 'Change Image URL Succeed',
COPY_LINK_SUCCEED: 'Copy Link Succeed',
BATCH_COPY_LINK_SUCCEED: 'Batch Copy Link Succeed',
FILE_RENAME: 'File Rename',
// settings
SETTINGS: 'Settings',
SETTINGS_OPEN_CONFIG_FILE: 'Open Config File',
SETTINGS_CLICK_TO_OPEN: 'Click to Open',
SETTINGS_SET_LOG_FILE: 'Set Log File',
SETTINGS_CLICK_TO_SET: 'Click to Set',
SETTINGS_CLICK_TO_CHECK: 'Click to Check',
SETTINGS_SET_SHORTCUT: 'Set Shortcut',
SETTINGS_CUSTOM_LINK_FORMAT: 'Custom Link Format',
SETTINGS_SET_PROXY_AND_MIRROR: 'Set Proxy and Mirror',
SETTINGS_SET_SERVER: 'Set Server',
SETTINGS_CHECK_UPDATE: 'Check Update',
SETTINGS_OPEN_UPDATE_HELPER: 'Open Update Helper',
SETTINGS_OPEN: 'Open',
SETTINGS_CLOSE: 'Close',
SETTINGS_ACCEPT_BETA_UPDATE: 'Accept Beta Update',
SETTINGS_LAUNCH_ON_BOOT: 'Launch On Boot',
SETTINGS_RENAME_BEFORE_UPLOAD: 'Rename Before Upload',
SETTINGS_TIMESTAMP_RENAME: 'Timestamp Rename',
SETTINGS_OPEN_UPLOAD_TIPS: 'Open Upload Tips',
SETTINGS_MINI_WINDOW_ON_TOP: 'Mini Window On Top',
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_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',
SETTINGS_CURRENT_VERSION: 'Current Version',
SETTINGS_NEWEST_VERSION: 'Newest Version',
SETTINGS_GETING: 'Getting...',
SETTINGS_TIPS_HAS_NEW_VERSION: 'PicGo has a new version, please click confirm to open download page',
SETTINGS_LOG_FILE: 'Log File',
SETTINGS_LOG_LEVEL: 'Log Level',
SETTINGS_LOG_FILE_SIZE: 'Log File Size',
SETTINGS_SET_PICGO_SERVER: 'Set PicGo Server',
SETTINGS_TIPS_SERVER_NOTICE: 'If you don\'t know what is the server\'s function, please read the document, or don\'t modify the configuration.',
SETTINGS_ENABLE_SERVER: 'Enable Server',
SETTINGS_SET_SERVER_HOST: 'Set Server Host',
SETTINGS_SET_SERVER_PORT: 'Set Server Port',
SETTINGS_TIP_PLACEHOLDER_HOST: 'Default:127.0.0.1',
SETTINGS_TIP_PLACEHOLDER_PORT: 'Default:36677',
SETTINGS_LOG_LEVEL_ALL: 'All',
SETTINGS_LOG_LEVEL_SUCCESS: 'Success',
SETTINGS_LOG_LEVEL_ERROR: 'Error',
SETTINGS_LOG_LEVEL_INFO: 'Info',
SETTINGS_LOG_LEVEL_WARN: 'Warn',
SETTINGS_LOG_LEVEL_NONE: 'None',
SETTINGS_RESULT: 'Result',
SETTINGS_DEFAULT_PICBED: 'Default Picbed',
SETTINGS_SET_DEFAULT_PICBED: 'Set Default Picbed',
SETTINGS_NOT_CONFIG_OPTIONS: 'Not Config Options',
SETTINGS_USE_BUILTIN_CLIPBOARD_UPLOAD: 'Use Builtin Clipboard to Upload',
SETTINGS_CHOOSE_LANGUAGE: 'Choose Language',
BUILTIN_CLIPBOARD_TIPS: 'Use builtin clipboard function to upload instead of using scripts',
// shortcut page
SHORTCUT_NAME: 'Shortcut Name',
SHORTCUT_BIND: 'Shortcut Binding',
SHORTCUT_STATUS: 'Status',
SHORTCUT_ENABLED: 'Enabled',
SHORTCUT_DISABLED: 'Disabled',
SHORTCUT_SOURCE: 'Source',
SHORTCUT_HANDLE: 'Handle',
SHORTCUT_ENABLE: 'Enable',
SHORTCUT_DISABLE: 'Disable',
SHORTCUT_EDIT: 'Edit',
SHORTCUT_CHANGE_UPLOAD: 'Change Upload Shortcut',
// tray page
WAIT_TO_UPLOAD: 'Wait to Upload',
ALREADY_UPLOAD: 'Already Upload',
// uload page
PICTURE_UPLOAD: 'Picture Upload',
DRAG_FILE_TO_HERE: 'Drag file to here, or',
CLICK_TO_UPLOAD: 'click to upload',
LINK_FORMAT: 'Link Format',
CUSTOM: 'Custom',
CLIPBOARD_PICTURE: 'Clipboard',
TIPS_DRAG_VALID_PICTURE_OR_URL: 'Drag valid picture or url to here',
TIPS_INPUT_URL: 'Input URL',
TIPS_HTTP_PREFIX: 'http:// or https://',
TIPS_INPUT_VALID_URL: 'Input valid URL',
// plugins
PLUGIN_SEARCH_PLACEHOLDER: 'Search picgo plugins on npm, or click the button to view the awesome plugins list',
PLUGIN_INSTALL: 'Install',
PLUGIN_INSTALLING: 'Installing...',
PLUGIN_INSTALLED: 'Installed',
PLUGIN_DOING_SOMETHING: 'Doing...',
PLUGIN_LIST: 'Plugin List',
PLUGIN_IMPORT_LOCAL: 'Import Local Plugins',
// tips
TIPS_REMOVE_LINK: 'This operation will remove the picture from the album, continue?',
TIPS_WILL_REMOVE_CHOOSED_IMAGES: 'This operation will remove the picture from the album, continue?',
TIPS_MUST_CONTAINS_URL: 'Must contains $url',
TIPS_NETWORK_ERROR: 'Network Error',
TIPS_NEED_RELOAD: 'Need Reload App',
TIPS_PLEASE_CHOOSE_LOG_LEVEL: 'Please choose log level',
TIPS_SET_SUCCEED: 'Set successfully',
TIPS_PLUGIN_NOT_GUI_IMPLEMENT: 'This plugin is not optimized for the GUI, continue?',
TIPS_CLICK_NOTIFICATION_TO_RELOAD: 'Click notification to reload app',
TIPS_GET_PLUGIN_LIST_FAILED: 'Get plugin list failed',
// ---renderer i18n end---
// plugins
PLUGIN_INSTALL_SUCCEED: 'Plugin install succeed',
PLUGIN_INSTALL_FAILED: 'Plugin install failed',
PLUGIN_UNINSTALL_SUCCEED: 'Plugin uninstall succeed',
PLUGIN_UNINSTALL_FAILED: 'Plugin uninstall failed',
PLUGIN_UPDATE_SUCCEED: 'Plugin update succeed',
PLUGIN_UPDATE_FAILED: 'Plugin update failed',
PLUGIN_IMPORT_SUCCEED: 'Plugin import succeed',
PLUGIN_IMPORT_FAILED: 'Plugin import failed',
ENABLE_PLUGIN: 'Enable Plugin',
DISABLE_PLUGIN: 'Disable Plugin',
UNINSTALL_PLUGIN: 'Uninstall Plugin',
UPDATE_PLUGIN: 'Update Plugin',
// tips
TIPS_NOTICE: 'Tips',
TIPS_WARNING: 'Warning',
TIPS_ERROR: 'Error',
TIPS_INSTALL_NODE_AND_RELOAD_PICGO: 'Please install Node.js and restart PicGo to continue',
TIPS_PLUGIN_REMOVE_GALLERY_ITEM: 'Plugin is trying to remove some images from the album gallery, continue?',
TIPS_PLUGIN_OVERWRITE_GALLERY: 'Plugin is trying to overwrite the album gallery, continue?',
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_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',
TIPS_CUSTOM_LINK_STYLE_MODIFIED_SUCCEED: 'Custom link style modified successfully',
TIPS_FIND_NEW_VERSION: 'Find new version ${v}update many new features, do you want to download the latest version?',
// privcy
PRIVACY:
`
This software respects and protects the personal privacy of all users who use the service. In order to provide you with more accurate and better services, this software will use and collect some of your behavioral information in accordance with the provisions of this Privacy Policy. When you agree to the software service use agreement, you are deemed to have agreed to the entire content of this privacy policy. This privacy policy is an integral part of the software service use agreement, and it will not be used if you do not agree. This Agreement will be updated periodically.
1. Scope of application
a) When you use this software, this software will record some information about your operation behavior of this software, including but not limited to the time-consuming, type, quantity and other information of your use of this software to upload files.
2. Use of Information
a) After obtaining your usage data, the software will upload it to the data analysis server so as to provide you with better services after analyzing the data.
3. Information disclosure
a) This software will not disclose your information to untrusted third parties.
b) In accordance with the relevant provisions of the law, or the requirements of administrative or judicial institutions, disclose to third parties or administrative or judicial institutions;
c) If you violate relevant Chinese laws, regulations or relevant rules, you need to disclose it to a third party;
4. Information Security
a) This software does not collect your personal information, key information and other private information, and the collected information is only used for improving the software, optimizing the experience, and understanding the daily activities of the software.
`,
PRIVACY_TIPS: 'Please agree the privacy policy to upload',
// action
QUIT: 'Quit'
}
+23
View File
@@ -0,0 +1,23 @@
import { ZH_CN } from './zh-CN'
import { EN } from './en'
import { ObjectAdapter, I18n } from '@picgo/i18n'
const languageMap = {
'zh-CN': ZH_CN,
en: EN
}
const objectAdapter = new ObjectAdapter(languageMap)
const i18n = new I18n({
adapter: objectAdapter,
defaultLanguage: 'zh-CN'
})
const T = (key: ILocalesKey, args: IStringKeyMap = {}): string => {
return i18n.translate(key, args) || ''
}
const languageList = Object.keys(languageMap)
export { i18n, T, languageList }
+223
View File
@@ -0,0 +1,223 @@
/* eslint-disable no-template-curly-in-string */
export const ZH_CN = {
ABOUT: '关于',
OPEN_MAIN_WINDOW: '打开主窗口',
CHOOSE_DEFAULT_PICBED: '选择默认图床',
OPEN_UPDATE_HELPER: '打开更新助手',
PRIVACY_AGREEMENT: '隐私协议',
RELOAD_APP: '重启应用',
UPLOAD_SUCCEED: '上传成功',
UPLOAD_FAILED: '上传失败',
UPLOAD_PROGRESS: '上传进度',
OPERATION_SUCCEED: '操作成功',
OPERATION_FAILED: '操作失败',
UPLOADING: '正在上传',
QUICK_UPLOAD: '快捷上传',
UPLOAD_BY_CLIPBOARD: '剪贴板图片上传',
HIDE_WINDOW: '隐藏窗口',
SPONSOR_PICGO: '赞助 PicGo',
SHOW_PICBED_QRCODE: '生成图床配置二维码',
PICBED_QRCODE: '图床配置二维码',
ENABLE: '启用',
DISABLE: '禁用',
CONFIG_THING: '配置${c}',
FIND_NEW_VERSION: '发现新版本',
NO_MORE_NOTICE: '以后不再提醒',
SHOW_DEVTOOLS: '打开开发者工具',
// ---renderer i18n---
CHOOSE_YOUR_DEFAULT_PICBED: '选择 ${d} 作为你默认图床:',
UPLOAD_AREA: '上传区',
GALLERY: '相册',
PICBEDS_SETTINGS: '图床设置',
PICGO_SETTINGS: 'PicGo设置',
PLUGIN_SETTINGS: '插件设置',
PICGO_SPONSOR_TEXT: 'PicGo是免费开源的软件,如果你喜欢它,对你有帮助,不妨请我喝杯咖啡?',
ALIPAY: '支付宝',
WECHATPAY: '微信支付',
CHOOSE_PICBED: '选择图床',
COPY_PICBED_CONFIG: '复制图床配置',
COPY_PICBED_CONFIG_SUCCEED: '复制图床配置成功',
INPUT: '输入框',
CANCEL: '取消',
CONFIRM: '确定',
CHOOSE_SHOWED_PICBED: '请选择显示的图床',
CHOOSE_PASTE_FORMAT: '请选择粘贴的格式',
SEARCH: '搜索',
COPY: '复制',
DELETE: '删除',
SELECT_ALL: '全选',
CHANGE_IMAGE_URL: '修改图片URL',
CHANGE_IMAGE_URL_SUCCEED: '修改图片URL成功',
COPY_LINK_SUCCEED: '复制链接成功',
BATCH_COPY_LINK_SUCCEED: '批量复制链接成功',
FILE_RENAME: '文件改名',
// settings
SETTINGS: '设置',
SETTINGS_OPEN_CONFIG_FILE: '打开配置文件',
SETTINGS_CLICK_TO_OPEN: '点击打开',
SETTINGS_SET_LOG_FILE: '设置日志文件',
SETTINGS_CLICK_TO_SET: '点击设置',
SETTINGS_CLICK_TO_CHECK: '点击检查',
SETTINGS_SET_SHORTCUT: '设置快捷键',
SETTINGS_CUSTOM_LINK_FORMAT: '自定义链接格式',
SETTINGS_SET_PROXY_AND_MIRROR: '设置代理和镜像地址',
SETTINGS_SET_SERVER: '设置Server',
SETTINGS_CHECK_UPDATE: '检查更新',
SETTINGS_OPEN_UPDATE_HELPER: '打开更新助手',
SETTINGS_OPEN: '开',
SETTINGS_CLOSE: '关',
SETTINGS_ACCEPT_BETA_UPDATE: '接受Beta版本更新',
SETTINGS_LAUNCH_ON_BOOT: '开机自启',
SETTINGS_RENAME_BEFORE_UPLOAD: '上传前重命名',
SETTINGS_TIMESTAMP_RENAME: '时间戳重命名',
SETTINGS_OPEN_UPLOAD_TIPS: '开启上传提示',
SETTINGS_MINI_WINDOW_ON_TOP: 'Mini窗口置顶',
SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD: '上传后自动复制URL',
SETTINGS_TIPS_PLACEHOLDER_URL: '用占位符 $url 来表示url的位置',
SETTINGS_TIPS_PLACEHOLDER_FILENAME: '用占位符 $fileName 来表示文件名的位置',
SETTINGS_TIPS_SUCH_AS: '如',
SETTINGS_UPLOAD_PROXY: '上传代理',
SETTINGS_PLUGIN_INSTALL_PROXY: '插件安装代理',
SETTINGS_PLUGIN_INSTALL_MIRROR: '插件安装镜像',
SETTINGS_CURRENT_VERSION: '当前版本',
SETTINGS_NEWEST_VERSION: '最新版本',
SETTINGS_GETING: '正在获取中',
SETTINGS_TIPS_HAS_NEW_VERSION: 'PicGo更新啦,请点击确定打开下载页面',
SETTINGS_LOG_FILE: '日志文件',
SETTINGS_LOG_LEVEL: '日志记录等级',
SETTINGS_LOG_FILE_SIZE: '日志文件大小',
SETTINGS_SET_PICGO_SERVER: '设置PicGo-Server',
SETTINGS_TIPS_SERVER_NOTICE: '如果你不知道Server的作用,请阅读文档,或者不用修改配置。',
SETTINGS_ENABLE_SERVER: '是否开启Server',
SETTINGS_SET_SERVER_HOST: '设置监听地址',
SETTINGS_SET_SERVER_PORT: '设置监听端口',
SETTINGS_TIP_PLACEHOLDER_HOST: '推荐默认地址:127.0.0.1',
SETTINGS_TIP_PLACEHOLDER_PORT: '推荐默认端口:36677',
SETTINGS_LOG_LEVEL_ALL: '全部-All',
SETTINGS_LOG_LEVEL_SUCCESS: '成功-Success',
SETTINGS_LOG_LEVEL_ERROR: '错误-Error',
SETTINGS_LOG_LEVEL_INFO: '普通-Info',
SETTINGS_LOG_LEVEL_WARN: '提醒-Warn',
SETTINGS_LOG_LEVEL_NONE: '不记录日志-None',
SETTINGS_RESULT: '设置结果',
SETTINGS_DEFAULT_PICBED: '设置默认图床',
SETTINGS_SET_DEFAULT_PICBED: '设为默认图床',
SETTINGS_NOT_CONFIG_OPTIONS: '暂无配置项',
SETTINGS_USE_BUILTIN_CLIPBOARD_UPLOAD: '使用内置剪贴板上传',
SETTINGS_CHOOSE_LANGUAGE: '选择语言',
BUILTIN_CLIPBOARD_TIPS: '使用内置剪贴板函数而不是调用脚本获取剪贴板图片',
// shortcut page
SHORTCUT_NAME: '快捷键名称',
SHORTCUT_BIND: '快捷键绑定',
SHORTCUT_STATUS: '状态',
SHORTCUT_ENABLED: '已启用',
SHORTCUT_DISABLED: '已禁用',
SHORTCUT_SOURCE: '来源',
SHORTCUT_HANDLE: '操作',
SHORTCUT_ENABLE: '启用',
SHORTCUT_DISABLE: '禁用',
SHORTCUT_EDIT: '编辑',
SHORTCUT_CHANGE_UPLOAD: '修改上传快捷键',
// tray page
WAIT_TO_UPLOAD: '等待上传',
ALREADY_UPLOAD: '已上传',
// uload page
PICTURE_UPLOAD: '图片上传',
DRAG_FILE_TO_HERE: '将文件拖拽到此处,或',
CLICK_TO_UPLOAD: '点击上传',
LINK_FORMAT: '链接格式',
CUSTOM: '自定义',
CLIPBOARD_PICTURE: '剪贴板图片',
TIPS_DRAG_VALID_PICTURE_OR_URL: '请拖入合法的图片文件或者图片URL地址',
TIPS_INPUT_URL: '请输入URL',
TIPS_HTTP_PREFIX: 'http://或者https://开头',
TIPS_INPUT_VALID_URL: '请输入合法的URL',
// plugins
PLUGIN_SEARCH_PLACEHOLDER: '搜索npm上的PicGo插件,或者点击上方按钮查看优秀插件列表',
PLUGIN_INSTALL: '安装',
PLUGIN_INSTALLING: '安装中',
PLUGIN_INSTALLED: '已安装',
PLUGIN_DOING_SOMETHING: '进行中',
PLUGIN_LIST: '插件列表',
PLUGIN_IMPORT_LOCAL: '导入本地插件',
// tips
TIPS_REMOVE_LINK: '此操作将把该图片移出相册, 是否继续?',
TIPS_WILL_REMOVE_CHOOSED_IMAGES: '将在相册中移除刚才选中的 ${m} 张图片,是否继续?',
TIPS_MUST_CONTAINS_URL: '必须含有$url',
TIPS_NETWORK_ERROR: '网络错误暂时无法获取',
TIPS_NEED_RELOAD: '需要重启生效',
TIPS_PLEASE_CHOOSE_LOG_LEVEL: '请选择日志记录等级',
TIPS_SET_SUCCEED: '设置成功',
TIPS_PLUGIN_NOT_GUI_IMPLEMENT: '该插件未对可视化界面进行优化, 是否继续安装?',
TIPS_CLICK_NOTIFICATION_TO_RELOAD: '请点击此通知重启应用以生效',
TIPS_GET_PLUGIN_LIST_FAILED: '获取插件列表失败',
// ---renderer i18n end---
// plugins
PLUGIN_INSTALL_SUCCEED: '插件安装成功',
PLUGIN_INSTALL_FAILED: '插件安装失败',
PLUGIN_UNINSTALL_SUCCEED: '插件卸载成功',
PLUGIN_UNINSTALL_FAILED: '插件卸载失败',
PLUGIN_UPDATE_SUCCEED: '插件更新成功',
PLUGIN_UPDATE_FAILED: '插件更新失败',
PLUGIN_IMPORT_SUCCEED: '插件导入成功',
PLUGIN_IMPORT_FAILED: '插件导入失败',
ENABLE_PLUGIN: '启用插件',
DISABLE_PLUGIN: '禁用插件',
UNINSTALL_PLUGIN: '卸载插件',
UPDATE_PLUGIN: '更新插件',
// tips
TIPS_NOTICE: '注意',
TIPS_WARNING: '警告',
TIPS_ERROR: '发生错误',
TIPS_INSTALL_NODE_AND_RELOAD_PICGO: '请安装Node.js并重启PicGo再继续操作',
TIPS_PLUGIN_REMOVE_GALLERY_ITEM: '有插件正在试图删除一些相册图片,是否继续',
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_CUSTOM_CONFIG_FILE_PATH_ERROR: '自定义文件解析出错,请检查路径内容是否正确',
TIPS_SHORTCUT_MODIFIED_SUCCEED: '快捷键已经修改成功',
TIPS_SHORTCUT_MODIFIED_CONFLICT: '快捷键冲突,请重新设置',
TIPS_CUSTOM_LINK_STYLE_MODIFIED_SUCCEED: '自定义链接格式已经修改成功',
TIPS_FIND_NEW_VERSION: '发现新版本${v},更新了很多功能,是否去下载最新的版本?',
// privcy
PRIVACY:
`
本软件尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更优质的服务,本软件会按照本隐私权政策的规定使用和收集您的一些行为信息。您在同意本软件服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本软件服务使用协议不可分割的一部分,如果不同意将无法使用。本协议会定期更新。
1.适用范围
a)在您使用本软件时,本软件会记录的您对本软件的一些操作行为信息,包括但不限于您使用本软件进行文件上传的耗时、类型、数量等信息。
2.信息的使用
a)在获得您的使用数据之后,本软件会将其上传至数据分析服务器,以便分析数据后,提供给您更好的服务。
3.信息披露
a)本软件不会将您的信息披露给不受信任的第三方。
b)根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;
c)如您出现违反中国有关法律、法规或者相关规则的情况,需要向第三方披露;
4.信息安全
a)本软件不会收集您的个人信息、密钥信息等隐私信息,所收集的信息仅仅作为改善软件、优化体验、了解软件日活等用途。
`,
PRIVACY_TIPS: '请同意隐私协议,否则无法上传。',
// action
QUIT: '退出'
}
export type ILocalesKey = keyof typeof ZH_CN
export type ILocales = typeof ZH_CN
+3 -13
View File
@@ -1,9 +1,6 @@
import {
BrowserWindow
} from 'electron'
import {
IWindowList
} from 'apis/app/window/constants'
// https://stackoverflow.com/questions/45420448/how-to-import-external-type-into-global-d-ts-file
declare type BrowserWindow = import('electron').BrowserWindow
declare type IWindowList = import('./enum').IWindowList
declare interface IWindowListItem {
isValid: boolean
@@ -20,10 +17,3 @@ declare interface IWindowManager {
deleteById: (id: number) => void
getAvailableWindow: () => BrowserWindow
}
// https://stackoverflow.com/questions/35074713/extending-typescript-global-object-in-node-js/44387594#44387594
declare global {
var PICGO_GUI_VERSION: string
var PICGO_CORE_VERSION: string
var notificationList: IAppNotification[]
}
+7
View File
@@ -20,3 +20,10 @@ export enum IPasteStyle {
UBB = 'UBB',
CUSTOM = 'Custom'
}
export enum IWindowList {
SETTING_WINDOW = 'SETTING_WINDOW',
TRAY_WINDOW = 'TRAY_WINDOW',
MINI_WINDOW = 'MINI_WINDOW',
RENAME_WINDOW = 'RENAME_WINDOW'
}
+6
View File
@@ -19,7 +19,13 @@ declare module 'vue/types/vue' {
$builtInPicBed: string[]
$bus: Vue
$$db: IGalleryDB
$T: typeof import('#/i18n/index').T
$i18n: typeof import('#/i18n/index').i18n
saveConfig(data: IObj | string, value?: any): void
getConfig<T>(key?: string): Promise<T | undefined>
setDefaultPicBed(picBed: string): void
defaultPicBed: string
forceUpdate(): void
sendToMain(channel: string, ...args: any[]): void
}
}
+5
View File
@@ -0,0 +1,5 @@
// https://stackoverflow.com/questions/35074713/extending-typescript-global-object-in-node-js/44387594#44387594
declare var PICGO_GUI_VERSION: string
declare var PICGO_CORE_VERSION: string
declare var notificationList: IAppNotification[]
-2
View File
@@ -1,2 +0,0 @@
import PicGoCore from 'picgo'
export default PicGoCore
+5 -5
View File
@@ -2,8 +2,8 @@ declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
// third-party
declare module 'fix-path' {
function fixPath(): void
export default fixPath
}
// // third-party
// declare module 'fix-path' {
// function fixPath(): void
// export default fixPath
// }
+10 -2
View File
@@ -122,7 +122,7 @@ interface IBounds {
}
// PicGo Types
type ICtx = import('picgo')
type ICtx = import('picgo').PicGo
interface IPicGoPlugin {
name: string
fullName: string
@@ -151,6 +151,11 @@ interface IPicGoPluginConfig {
type: string
required: boolean
default?: any
alias?: string
choices?: {
name?: string
value?: any
}[]
[propName: string]: any
}
@@ -287,7 +292,8 @@ interface ITcYunConfig {
area: string,
path: string,
customUrl: string,
version: 'v4' | 'v5'
version: 'v4' | 'v5',
options: string
}
interface IUpYunConfig {
@@ -335,3 +341,5 @@ interface IMiniWindowPos {
}
type PromiseResType<T> = T extends Promise<infer R> ? R : T
type ILocalesKey = import('#/i18n/zh-CN').ILocalesKey
+3
View File
@@ -9,6 +9,9 @@ interface ISettingForm {
logLevel: string[]
autoCopyUrl: boolean
checkBetaUpdate: boolean
useBuiltinClipboard: boolean
language: string
logFileSizeLimit: number
}
interface IShortKeyMap {
+11
View File
@@ -30,3 +30,14 @@ export const handleStreamlinePluginName = (name: string) => {
return name.replace(/picgo-plugin-/, '')
}
}
/**
* for just simple clone an object
*/
export const simpleClone = (obj: any) => {
return JSON.parse(JSON.stringify(obj))
}
export const enforceNumber = (num: number | string) => {
return isNaN(Number(num)) ? 0 : Number(num)
}
+25
View File
@@ -0,0 +1,25 @@
import axios from 'axios'
import { RELEASE_URL, RELEASE_URL_BACKUP } from './static'
import yaml from 'js-yaml'
export const getLatestVersion = async (isCheckBetaUpdate: boolean = false) => {
let res: string = ''
try {
res = await axios.get(RELEASE_URL).then(r => {
const list = r.data as IStringKeyMap[]
if (isCheckBetaUpdate) {
const betaList = list.filter(item => item.name.includes('beta'))
return betaList[0].name
}
const normalList = list.filter(item => !item.name.includes('beta'))
return normalList[0].name
}).catch(async () => {
const result = await axios.get(isCheckBetaUpdate ? `${RELEASE_URL_BACKUP}/latest.beta.yml` : `${RELEASE_URL_BACKUP}/latest.yml`)
const r = yaml.load(result.data) as IStringKeyMap
return r.version
})
} catch (err) {
console.log(err)
}
return res
}
+5
View File
@@ -0,0 +1,5 @@
export const CLIPBOARD_IMAGE_FOLDER = 'picgo-clipboard-images'
export const RELEASE_URL = 'https://api.github.com/repos/Molunerfinn/PicGo/releases'
export const RELEASE_URL_BACKUP = 'https://picgo-1251750343.cos.ap-chengdu.myqcloud.com'
export const STABLE_RELEASE_URL = 'https://github.com/Molunerfinn/PicGo/releases/latest'
export const BETA_RELEASE_URL = 'https://github.com/Molunerfinn/PicGo/releases'
+5 -1
View File
@@ -32,6 +32,10 @@ const config = {
.set('#', resolve('src/universal'))
.set('apis', resolve('src/main/apis'))
.set('@core', resolve('src/main/apis/core'))
config.resolve.mainFields
.clear()
.add('main') // fix some modules will use browser target
.add('module')
},
builderOptions: {
productName: 'PicGo',
@@ -77,7 +81,7 @@ const config = {
win: {
icon: 'build/icons/icon.ico',
// eslint-disable-next-line no-template-curly-in-string
artifactName: 'PicGo Setup ${version}-${arch}.exe',
artifactName: 'PicGo-Setup-${version}-${arch}.exe',
target: [{
target: 'nsis',
arch: [
+510 -246
View File
File diff suppressed because it is too large Load Diff