mirror of
https://github.com/Molunerfinn/PicGo.git
synced 2024-04-21 10:31:33 +00:00
Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d3e779e0b | ||
|
|
20d3cf987c | ||
|
|
ae692632a5 | ||
|
|
019efd354c | ||
|
|
7030f7a764 | ||
|
|
96a63ea11a | ||
|
|
f1eb7f4d70 | ||
|
|
6ddd660d89 | ||
|
|
c70c3aff78 | ||
|
|
76964ff1a5 | ||
|
|
12cecc27e7 | ||
|
|
bdf523a060 | ||
|
|
49e5f343f4 | ||
|
|
1657542144 | ||
|
|
8e5e9ec59a | ||
|
|
06b67e50b9 | ||
|
|
cf895deb8d | ||
|
|
ab762ef465 | ||
|
|
92022a6e34 | ||
|
|
a312d06b62 | ||
|
|
a1b70b4cb1 | ||
|
|
2d9e9c0a00 | ||
|
|
a657c51bb5 | ||
|
|
321e33967c | ||
|
|
0a986c8933 | ||
|
|
69e1dc8128 | ||
|
|
b05139fc9a | ||
|
|
992ff35936 | ||
|
|
06d40ef7f6 | ||
|
|
f53639153e | ||
|
|
3fd6e4e4c8 |
+3
-1
@@ -15,7 +15,9 @@ module.exports = {
|
||||
'plugins': ['@typescript-eslint'],
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'off' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
"indent": "off",
|
||||
"@typescript-eslint/indent": ["error", 2]
|
||||
},
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
|
||||
@@ -1,3 +1,63 @@
|
||||
# :tada: 2.3.0-beta.8 (2021-08-13)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* settings bug ([20d3cf9](https://github.com/Molunerfinn/PicGo/commit/20d3cf9)), closes [#710](https://github.com/Molunerfinn/PicGo/issues/710)
|
||||
* upload clipboard images via http should return list ([ae69263](https://github.com/Molunerfinn/PicGo/commit/ae69263)), closes [#721](https://github.com/Molunerfinn/PicGo/issues/721)
|
||||
|
||||
|
||||
|
||||
# :tada: 2.3.0-beta.7 (2021-08-01)
|
||||
|
||||
|
||||
### :sparkles: Features
|
||||
|
||||
* add gallery db ([6ddd660](https://github.com/Molunerfinn/PicGo/commit/6ddd660))
|
||||
* add win32 support ([1657542](https://github.com/Molunerfinn/PicGo/commit/1657542)), closes [#632](https://github.com/Molunerfinn/PicGo/issues/632)
|
||||
* finish custom config path ([7030f7a](https://github.com/Molunerfinn/PicGo/commit/7030f7a)), closes [#255](https://github.com/Molunerfinn/PicGo/issues/255)
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* bug of gallery db for plugin ([96a63ea](https://github.com/Molunerfinn/PicGo/commit/96a63ea))
|
||||
* enable plugin should reload ([49e5f34](https://github.com/Molunerfinn/PicGo/commit/49e5f34)), closes [#659](https://github.com/Molunerfinn/PicGo/issues/659)
|
||||
* gallery db bug ([f1eb7f4](https://github.com/Molunerfinn/PicGo/commit/f1eb7f4))
|
||||
* multiple uploading in the same time will cause output conflict ([06b67e5](https://github.com/Molunerfinn/PicGo/commit/06b67e5)), closes [#666](https://github.com/Molunerfinn/PicGo/issues/666)
|
||||
* multiple uploading in the same time will cause rename failed ([12cecc2](https://github.com/Molunerfinn/PicGo/commit/12cecc2))
|
||||
* uploader error in linux ([ab762ef](https://github.com/Molunerfinn/PicGo/commit/ab762ef)), closes [#627](https://github.com/Molunerfinn/PicGo/issues/627)
|
||||
* use uploader first ([92022a6](https://github.com/Molunerfinn/PicGo/commit/92022a6))
|
||||
* windows ia32 && x64 build options ([bdf523a](https://github.com/Molunerfinn/PicGo/commit/bdf523a))
|
||||
|
||||
|
||||
|
||||
# :tada: 2.3.0-beta.6 (2021-04-24)
|
||||
|
||||
|
||||
### :sparkles: Features
|
||||
|
||||
* add baidu tongji for analytics ([f536391](https://github.com/Molunerfinn/PicGo/commit/f536391))
|
||||
* add logs for picgo-server ([2d9e9c0](https://github.com/Molunerfinn/PicGo/commit/2d9e9c0)), closes [#627](https://github.com/Molunerfinn/PicGo/issues/627)
|
||||
* add privacy policy ([992ff35](https://github.com/Molunerfinn/PicGo/commit/992ff35))
|
||||
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
||||
* add plugin install failed notice ([b05139f](https://github.com/Molunerfinn/PicGo/commit/b05139f))
|
||||
* default picBed using picBed.uploader instead of picBed.current ([0a986c8](https://github.com/Molunerfinn/PicGo/commit/0a986c8))
|
||||
* dev error with install vue-devtools ([a657c51](https://github.com/Molunerfinn/PicGo/commit/a657c51)), closes [#653](https://github.com/Molunerfinn/PicGo/issues/653) [#658](https://github.com/Molunerfinn/PicGo/issues/658)
|
||||
* disable plugin need reload app ([a1b70b4](https://github.com/Molunerfinn/PicGo/commit/a1b70b4))
|
||||
* fix analytics value ([06d40ef](https://github.com/Molunerfinn/PicGo/commit/06d40ef))
|
||||
* windows cli uploading bug ([321e339](https://github.com/Molunerfinn/PicGo/commit/321e339)), closes [#657](https://github.com/Molunerfinn/PicGo/issues/657)
|
||||
|
||||
|
||||
### :package: Chore
|
||||
|
||||
* add main process hot reload ([3fd6e4e](https://github.com/Molunerfinn/PicGo/commit/3fd6e4e))
|
||||
* fix eslint error notice in indent ([69e1dc8](https://github.com/Molunerfinn/PicGo/commit/69e1dc8))
|
||||
|
||||
|
||||
|
||||
# :tada: 2.3.0-beta.5 (2021-04-04)
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@ install:
|
||||
|
||||
build_script:
|
||||
#- yarn test
|
||||
- npm run release
|
||||
- yarn build --win --ia32
|
||||
- yarn release
|
||||
|
||||
test: off
|
||||
|
||||
+5
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "picgo",
|
||||
"version": "2.3.0-beta.5",
|
||||
"version": "2.3.0-beta.8",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service electron:serve",
|
||||
@@ -34,6 +34,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@picgo/store": "^1.0.3",
|
||||
"axios": "^0.19.0",
|
||||
"core-js": "^3.3.2",
|
||||
"element-ui": "^2.13.0",
|
||||
@@ -42,8 +43,9 @@
|
||||
"keycode": "^2.2.0",
|
||||
"lodash-id": "^0.14.0",
|
||||
"lowdb": "^1.0.0",
|
||||
"picgo": "^1.4.19",
|
||||
"picgo": "^1.4.24",
|
||||
"qrcode.vue": "^1.7.0",
|
||||
"uuidv4": "^6.2.11",
|
||||
"vue": "^2.6.10",
|
||||
"vue-gallery": "^2.0.1",
|
||||
"vue-lazyload": "^1.2.6",
|
||||
@@ -68,6 +70,7 @@
|
||||
"conventional-changelog": "^3.1.18",
|
||||
"cz-customizable": "^6.2.0",
|
||||
"electron": "^6.0.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"husky": "^3.1.0",
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
# grab the paths
|
||||
scriptPath=$(echo $0 | awk '{ print substr( $0, 1, length($0)-6 ) }')"windows10.ps1"
|
||||
imagePath=$(echo $1 | awk '{ print substr( $0, 1, length($0)-18 ) }')
|
||||
imageName=$(echo $1 | awk '{ print substr( $0, length($0)-17, length($0) ) }')
|
||||
|
||||
# run the powershell script
|
||||
res=$(powershell.exe -noprofile -noninteractive -nologo -sta -executionpolicy unrestricted -file $(wslpath -w $scriptPath) $(wslpath -w $imagePath)"\\"$imageName)
|
||||
|
||||
# note that there is a return symbol in powershell result
|
||||
noImage=$(echo "no image\r")
|
||||
|
||||
# check whether image exists
|
||||
if [ "$res" = "$noImage" ] ;then
|
||||
echo "no image"
|
||||
else
|
||||
echo $(wslpath -u $res)
|
||||
fi
|
||||
+5
-3
@@ -1,7 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import App from './renderer/App.vue'
|
||||
import router from './renderer/router'
|
||||
import db from '#/datastore/index'
|
||||
import ElementUI from 'element-ui'
|
||||
import { webFrame } from 'electron'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
@@ -9,6 +8,8 @@ import VueLazyLoad from 'vue-lazyload'
|
||||
import axios from 'axios'
|
||||
import mainMixin from './renderer/utils/mainMixin'
|
||||
import bus from '@/utils/bus'
|
||||
import { initTalkingData } from './renderer/utils/analytics'
|
||||
import db from './renderer/utils/db'
|
||||
|
||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
||||
webFrame.setLayoutZoomLevelLimits(0, 0)
|
||||
@@ -16,7 +17,6 @@ webFrame.setLayoutZoomLevelLimits(0, 0)
|
||||
Vue.config.productionTip = false
|
||||
Vue.prototype.$builtInPicBed = [
|
||||
'smms',
|
||||
'weibo',
|
||||
'imgur',
|
||||
'qiniu',
|
||||
'tcyun',
|
||||
@@ -24,7 +24,7 @@ Vue.prototype.$builtInPicBed = [
|
||||
'aliyun',
|
||||
'github'
|
||||
]
|
||||
Vue.prototype.$db = db
|
||||
Vue.prototype.$$db = db
|
||||
Vue.prototype.$http = axios
|
||||
Vue.prototype.$bus = bus
|
||||
|
||||
@@ -36,3 +36,5 @@ new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
|
||||
initTalkingData()
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
} from 'electron'
|
||||
import logger from '@core/picgo/logger'
|
||||
import GuiApi from '../../gui'
|
||||
import db from '#/datastore'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
|
||||
import shortKeyService from './shortKeyService'
|
||||
import picgo from '@core/picgo'
|
||||
@@ -130,8 +130,7 @@ class ShortKeyHandler {
|
||||
} else if (command.includes('picgo-plugin-')) {
|
||||
const handler = shortKeyService.getShortKeyHandler(command)
|
||||
if (handler) {
|
||||
const guiApi = new GuiApi()
|
||||
return handler(picgo, guiApi)
|
||||
return handler(picgo, GuiApi.getInstance())
|
||||
}
|
||||
} else {
|
||||
logger.warn(`can not find command: ${command}`)
|
||||
|
||||
@@ -9,13 +9,14 @@ import {
|
||||
} from 'electron'
|
||||
import uploader from 'apis/app/uploader'
|
||||
import getPicBeds from '~/main/utils/getPicBeds'
|
||||
import db from '#/datastore'
|
||||
import db, { GalleryDB } from '~/main/apis/core/datastore'
|
||||
import windowManager from 'apis/app/window/windowManager'
|
||||
import { IWindowList } from 'apis/app/window/constants'
|
||||
import picgo from '@core/picgo'
|
||||
import pasteTemplate from '#/utils/pasteTemplate'
|
||||
import pkg from 'root/package.json'
|
||||
import { handleCopyUrl } from '~/main/utils/common'
|
||||
import { privacyManager } from '~/main/utils/privacyManager'
|
||||
let contextMenu: Menu | null
|
||||
let menu: Menu | null
|
||||
let tray: Tray | null
|
||||
@@ -76,6 +77,12 @@ export function createContextMenu () {
|
||||
db.set('settings.showUpdateTip', !value)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '隐私协议',
|
||||
click () {
|
||||
privacyManager.show(false)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '重启应用',
|
||||
click () {
|
||||
@@ -194,6 +201,8 @@ export function createTray () {
|
||||
tray!.setImage(`${__static}/menubar.png`)
|
||||
})
|
||||
|
||||
// drop-files only be supported in macOS
|
||||
// so the tray window must be available
|
||||
tray.on('drop-files', async (event: Event, files: string[]) => {
|
||||
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||
@@ -203,7 +212,7 @@ export function createTray () {
|
||||
if (imgs !== false) {
|
||||
const pasteText: string[] = []
|
||||
for (let i = 0; i < imgs.length; i++) {
|
||||
pasteText.push(pasteTemplate(pasteStyle, imgs[i]))
|
||||
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
|
||||
const notification = new Notification({
|
||||
title: '上传成功',
|
||||
body: imgs[i].imgUrl!,
|
||||
@@ -212,7 +221,7 @@ export function createTray () {
|
||||
setTimeout(() => {
|
||||
notification.show()
|
||||
}, i * 100)
|
||||
db.insert('uploaded', imgs[i])
|
||||
await GalleryDB.getInstance().insert(imgs[i])
|
||||
}
|
||||
handleCopyUrl(pasteText.join('\n'))
|
||||
trayWindow.webContents.send('dragFiles', imgs)
|
||||
|
||||
@@ -6,7 +6,7 @@ import windowManager from 'apis/app/window/windowManager'
|
||||
import { IWindowList } from 'apis/app/window/constants'
|
||||
import uploader from '.'
|
||||
import pasteTemplate from '#/utils/pasteTemplate'
|
||||
import db from '#/datastore'
|
||||
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> => {
|
||||
@@ -14,18 +14,19 @@ export const uploadClipboardFiles = async (): Promise<string> => {
|
||||
let img = await uploader.setWebContents(win!.webContents).upload()
|
||||
if (img !== false) {
|
||||
if (img.length > 0) {
|
||||
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
|
||||
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||
handleCopyUrl(pasteTemplate(pasteStyle, img[0]))
|
||||
handleCopyUrl(pasteTemplate(pasteStyle, img[0], db.get('settings.customLink')))
|
||||
const notification = new Notification({
|
||||
title: '上传成功',
|
||||
body: img[0].imgUrl!,
|
||||
icon: img[0].imgUrl
|
||||
})
|
||||
notification.show()
|
||||
db.insert('uploaded', img[0])
|
||||
trayWindow.webContents.send('clipboardFiles', [])
|
||||
trayWindow.webContents.send('uploadFiles', img)
|
||||
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')
|
||||
}
|
||||
@@ -51,7 +52,7 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
|
||||
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||
const pasteText: string[] = []
|
||||
for (let i = 0; i < imgs.length; i++) {
|
||||
pasteText.push(pasteTemplate(pasteStyle, imgs[i]))
|
||||
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
|
||||
const notification = new Notification({
|
||||
title: '上传成功',
|
||||
body: imgs[i].imgUrl!,
|
||||
@@ -60,11 +61,12 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
|
||||
setTimeout(() => {
|
||||
notification.show()
|
||||
}, i * 100)
|
||||
db.insert('uploaded', imgs[i])
|
||||
await GalleryDB.getInstance().insert(imgs[i])
|
||||
result.push(handleUrlEncode(imgs[i].imgUrl!))
|
||||
}
|
||||
handleCopyUrl(pasteText.join('\n'))
|
||||
windowManager.get(IWindowList.TRAY_WINDOW)!.webContents.send('uploadFiles', imgs)
|
||||
// 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')
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ import {
|
||||
} from 'electron'
|
||||
import dayjs from 'dayjs'
|
||||
import picgo from '@core/picgo'
|
||||
import db from '#/datastore'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import windowManager from 'apis/app/window/windowManager'
|
||||
import { IWindowList } from 'apis/app/window/constants'
|
||||
import util from 'util'
|
||||
import { IPicGo } from 'picgo/dist/src/types'
|
||||
import { showNotification } from '~/main/utils/common'
|
||||
import { showNotification, calcDurationRange } from '~/main/utils/common'
|
||||
import { TALKING_DATA_EVENT } from '~/universal/events/constants'
|
||||
import logger from '@core/picgo/logger'
|
||||
|
||||
const waitForShow = (webcontent: WebContents) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
@@ -36,9 +38,23 @@ const waitForRename = (window: BrowserWindow, id: number): Promise<string|null>
|
||||
})
|
||||
}
|
||||
|
||||
const handleTalkingData = (webContents: WebContents, options: IAnalyticsData) => {
|
||||
const data: ITalkingDataOptions = {
|
||||
EventId: 'upload',
|
||||
Label: options.type,
|
||||
MapKv: {
|
||||
by: options.fromClipboard ? 'clipboard' : 'files', // 上传剪贴板图片还是选择的文文件
|
||||
count: options.count, // 上传的数量
|
||||
duration: calcDurationRange(options.duration || 0), // 上传耗时
|
||||
type: options.type
|
||||
}
|
||||
}
|
||||
webContents.send(TALKING_DATA_EVENT, data)
|
||||
}
|
||||
|
||||
class Uploader {
|
||||
private webContents: WebContents | null = null
|
||||
private uploading: boolean = false
|
||||
// private uploading: boolean = false
|
||||
constructor () {
|
||||
this.init()
|
||||
}
|
||||
@@ -70,7 +86,7 @@ class Uploader {
|
||||
let name: undefined | string | null
|
||||
let fileName: string | undefined
|
||||
if (autoRename) {
|
||||
fileName = dayjs().add(index, 'second').format('YYYYMMDDHHmmss') + item.extname
|
||||
fileName = dayjs().add(index, 'ms').format('YYYYMMDDHHmmSSS') + item.extname
|
||||
} else {
|
||||
fileName = item.fileName
|
||||
}
|
||||
@@ -92,46 +108,34 @@ class Uploader {
|
||||
return this
|
||||
}
|
||||
|
||||
upload (img?: IUploadOption): Promise<ImgInfo[]|false> {
|
||||
if (this.uploading) {
|
||||
showNotification({
|
||||
title: '上传失败',
|
||||
body: '前序上传还在继续,请稍后再试'
|
||||
})
|
||||
return Promise.resolve(false)
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
try {
|
||||
this.uploading = true
|
||||
picgo.upload(img)
|
||||
picgo.once('finished', ctx => {
|
||||
this.uploading = false
|
||||
if (ctx.output.every((item: ImgInfo) => item.imgUrl)) {
|
||||
resolve(ctx.output)
|
||||
} else {
|
||||
resolve(false)
|
||||
}
|
||||
picgo.removeAllListeners('failed')
|
||||
})
|
||||
picgo.once('failed', (e: Error) => {
|
||||
this.uploading = false
|
||||
setTimeout(() => {
|
||||
showNotification({
|
||||
title: '上传失败',
|
||||
body: util.format(e.stack),
|
||||
clickToCopy: true
|
||||
})
|
||||
}, 500)
|
||||
picgo.removeAllListeners('finished')
|
||||
resolve(false)
|
||||
})
|
||||
} catch (e) {
|
||||
this.uploading = false
|
||||
picgo.removeAllListeners('failed')
|
||||
picgo.removeAllListeners('finished')
|
||||
resolve([])
|
||||
async upload (img?: IUploadOption): Promise<ImgInfo[]|false> {
|
||||
try {
|
||||
const startTime = Date.now()
|
||||
const output = await picgo.upload(img)
|
||||
if (Array.isArray(output) && output.some((item: ImgInfo) => item.imgUrl)) {
|
||||
if (this.webContents) {
|
||||
handleTalkingData(this.webContents, {
|
||||
fromClipboard: !img,
|
||||
type: db.get('picBed.uploader') || db.get('picBed.current') || 'smms',
|
||||
count: img ? img.length : 1,
|
||||
duration: Date.now() - startTime
|
||||
} as IAnalyticsData)
|
||||
}
|
||||
return output.filter(item => item.imgUrl)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
setTimeout(() => {
|
||||
showNotification({
|
||||
title: '上传失败',
|
||||
body: util.format(e.stack),
|
||||
clickToCopy: true
|
||||
})
|
||||
}, 500)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import { IWindowListItem } from '#/types/electron'
|
||||
import bus from '@core/bus'
|
||||
import { CREATE_APP_MENU } from '@core/bus/constants'
|
||||
import db from '#/datastore'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
|
||||
import { app } from 'electron'
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { remote, app } from 'electron'
|
||||
import dayjs from 'dayjs'
|
||||
const APP = process.type === 'renderer' ? remote.app : app
|
||||
const STORE_PATH = APP.getPath('userData')
|
||||
const configFilePath = path.join(STORE_PATH, 'data.json')
|
||||
const configFileBackupPath = path.join(STORE_PATH, 'data.bak.json')
|
||||
export const defaultConfigPath = configFilePath
|
||||
let _configFilePath = ''
|
||||
let hasCheckPath = false
|
||||
|
||||
const errorMsg = {
|
||||
broken: 'PicGo 配置文件损坏,已经恢复为默认配置',
|
||||
brokenButBackup: 'PicGo 配置文件损坏,已经恢复为备份配置'
|
||||
}
|
||||
|
||||
function dbChecker () {
|
||||
if (process.type !== 'renderer') {
|
||||
if (!global.notificationList) global.notificationList = []
|
||||
// db save bak
|
||||
try {
|
||||
const { dbPath, dbBackupPath } = getGalleryDBPath()
|
||||
if (fs.existsSync(dbPath)) {
|
||||
fs.copyFileSync(dbPath, dbBackupPath)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
const configFilePath = dbPathChecker()
|
||||
if (!fs.existsSync(configFilePath)) {
|
||||
return
|
||||
}
|
||||
let configFile: string = '{}'
|
||||
let optionsTpl = {
|
||||
title: '注意',
|
||||
body: ''
|
||||
}
|
||||
// config save bak
|
||||
try {
|
||||
configFile = fs.readFileSync(configFilePath, { encoding: 'utf-8' })
|
||||
JSON.parse(configFile)
|
||||
} catch (e) {
|
||||
fs.unlinkSync(configFilePath)
|
||||
if (fs.existsSync(configFileBackupPath)) {
|
||||
try {
|
||||
configFile = fs.readFileSync(configFileBackupPath, { encoding: 'utf-8' })
|
||||
JSON.parse(configFile)
|
||||
fs.writeFileSync(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')}`
|
||||
global.notificationList.push(optionsTpl)
|
||||
return
|
||||
} catch (e) {
|
||||
optionsTpl.body = errorMsg.broken
|
||||
global.notificationList.push(optionsTpl)
|
||||
return
|
||||
}
|
||||
}
|
||||
optionsTpl.body = errorMsg.broken
|
||||
global.notificationList.push(optionsTpl)
|
||||
return
|
||||
}
|
||||
fs.writeFileSync(configFileBackupPath, configFile, { encoding: 'utf-8' })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config path
|
||||
*/
|
||||
function dbPathChecker (): string {
|
||||
if (_configFilePath) {
|
||||
return _configFilePath
|
||||
}
|
||||
// defaultConfigPath
|
||||
_configFilePath = defaultConfigPath
|
||||
// if defaultConfig path is not exit
|
||||
// do not parse the content of config
|
||||
if (!fs.existsSync(defaultConfigPath)) {
|
||||
return _configFilePath
|
||||
}
|
||||
try {
|
||||
const configString = fs.readFileSync(defaultConfigPath, { encoding: 'utf-8' })
|
||||
const config = JSON.parse(configString)
|
||||
const userConfigPath: string = config.configPath || ''
|
||||
if (userConfigPath) {
|
||||
if (fs.existsSync(userConfigPath) && userConfigPath.endsWith('.json')) {
|
||||
_configFilePath = userConfigPath
|
||||
return _configFilePath
|
||||
}
|
||||
}
|
||||
return _configFilePath
|
||||
} catch (e) {
|
||||
// TODO: local logger is needed
|
||||
if (!hasCheckPath) {
|
||||
let optionsTpl = {
|
||||
title: '注意',
|
||||
body: '自定义文件解析出错,请检查路径内容是否正确'
|
||||
}
|
||||
global.notificationList.push(optionsTpl)
|
||||
hasCheckPath = true
|
||||
}
|
||||
console.error(e)
|
||||
_configFilePath = defaultConfigPath
|
||||
return _configFilePath
|
||||
}
|
||||
}
|
||||
|
||||
function dbPathDir () {
|
||||
return path.dirname(dbPathChecker())
|
||||
}
|
||||
|
||||
function getGalleryDBPath (): {
|
||||
dbPath: string
|
||||
dbBackupPath: string
|
||||
} {
|
||||
const configPath = dbPathChecker()
|
||||
const dbPath = path.join(path.dirname(configPath), 'picgo.db')
|
||||
const dbBackupPath = path.join(path.dirname(dbPath), 'picgo.bak.db')
|
||||
return {
|
||||
dbPath,
|
||||
dbBackupPath
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
dbChecker,
|
||||
dbPathChecker,
|
||||
dbPathDir,
|
||||
getGalleryDBPath
|
||||
}
|
||||
@@ -2,33 +2,27 @@ import Datastore from 'lowdb'
|
||||
// @ts-ignore
|
||||
import LodashId from 'lodash-id'
|
||||
import FileSync from 'lowdb/adapters/FileSync'
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { remote, app } from 'electron'
|
||||
import { dbChecker } from './dbChecker'
|
||||
import { dbPathChecker, dbPathDir, getGalleryDBPath } from './dbChecker'
|
||||
import { DBStore } from '@picgo/store'
|
||||
|
||||
const APP = process.type === 'renderer' ? remote.app : app
|
||||
const STORE_PATH = APP.getPath('userData')
|
||||
const STORE_PATH = dbPathDir()
|
||||
|
||||
if (process.type !== 'renderer') {
|
||||
if (!fs.pathExistsSync(STORE_PATH)) {
|
||||
fs.mkdirpSync(STORE_PATH)
|
||||
}
|
||||
dbChecker()
|
||||
if (!fs.pathExistsSync(STORE_PATH)) {
|
||||
fs.mkdirpSync(STORE_PATH)
|
||||
}
|
||||
const CONFIG_PATH: string = dbPathChecker()
|
||||
const DB_PATH: string = getGalleryDBPath().dbPath
|
||||
|
||||
class DB {
|
||||
// TODO: use JSONStore with @picgo/store
|
||||
class ConfigStore {
|
||||
private db: Datastore.LowdbSync<Datastore.AdapterSync>
|
||||
constructor () {
|
||||
const adapter = new FileSync(path.join(STORE_PATH, '/data.json'))
|
||||
const adapter = new FileSync(CONFIG_PATH)
|
||||
|
||||
this.db = Datastore(adapter)
|
||||
this.db._.mixin(LodashId)
|
||||
|
||||
if (!this.db.has('uploaded').value()) {
|
||||
this.db.set('uploaded', []).write()
|
||||
}
|
||||
|
||||
if (!this.db.has('picBed').value()) {
|
||||
this.db.set('picBed', {
|
||||
current: 'smms', // deprecated
|
||||
@@ -75,6 +69,27 @@ class DB {
|
||||
// @ts-ignore
|
||||
return this.read().get(key).removeById(id).write()
|
||||
}
|
||||
getConfigPath () {
|
||||
return CONFIG_PATH
|
||||
}
|
||||
}
|
||||
|
||||
export default new DB()
|
||||
export default new ConfigStore()
|
||||
|
||||
// v2.3.0 add gallery db
|
||||
class GalleryDB {
|
||||
private static instance: DBStore
|
||||
private constructor () {
|
||||
console.log('init gallery db')
|
||||
}
|
||||
public static getInstance (): DBStore {
|
||||
if (!GalleryDB.instance) {
|
||||
GalleryDB.instance = new DBStore(DB_PATH, 'gallery')
|
||||
}
|
||||
return GalleryDB.instance
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
GalleryDB
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
import PicGoCore from '~/universal/types/picgo'
|
||||
import {
|
||||
app
|
||||
} from 'electron'
|
||||
import path from 'path'
|
||||
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
|
||||
const STORE_PATH = app.getPath('userData')
|
||||
|
||||
const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
|
||||
const CONFIG_PATH = dbPathChecker()
|
||||
|
||||
dbChecker()
|
||||
|
||||
const picgo = new PicGo(CONFIG_PATH)
|
||||
picgo.saveConfig({
|
||||
@@ -16,7 +15,7 @@ picgo.saveConfig({
|
||||
PICGO_ENV: 'GUI'
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
global.PICGO_GUI_VERSION = pkg.version
|
||||
picgo.GUI_VERSION = global.PICGO_GUI_VERSION
|
||||
|
||||
export default picgo! as PicGoCore
|
||||
|
||||
@@ -4,7 +4,9 @@ import {
|
||||
Notification,
|
||||
ipcMain
|
||||
} from 'electron'
|
||||
import db from '#/datastore'
|
||||
import path from 'path'
|
||||
import db, { GalleryDB } from 'apis/core/datastore'
|
||||
import { dbPathChecker, defaultConfigPath, getGalleryDBPath } from 'apis/core/datastore/dbChecker'
|
||||
import uploader from 'apis/app/uploader'
|
||||
import pasteTemplate from '#/utils/pasteTemplate'
|
||||
import { handleCopyUrl } from '~/main/utils/common'
|
||||
@@ -15,11 +17,23 @@ import {
|
||||
import {
|
||||
SHOW_INPUT_BOX
|
||||
} from '~/universal/events/constants'
|
||||
import { DBStore } from '@picgo/store'
|
||||
type PromiseResType<T> = T extends Promise<infer R> ? R : T
|
||||
|
||||
// Cross-process support may be required in the future
|
||||
class GuiApi implements IGuiApi {
|
||||
private static instance: GuiApi
|
||||
private windowId: number = -1
|
||||
private settingWindowId: number = -1
|
||||
private constructor () {
|
||||
console.log('init guiapi')
|
||||
}
|
||||
public static getInstance (): GuiApi {
|
||||
if (!GuiApi.instance) {
|
||||
GuiApi.instance = new GuiApi()
|
||||
}
|
||||
return GuiApi.instance
|
||||
}
|
||||
private async showSettingWindow () {
|
||||
this.settingWindowId = await getSettingWindowId()
|
||||
const settingWindow = BrowserWindow.fromId(this.settingWindowId)
|
||||
@@ -69,7 +83,7 @@ class GuiApi implements IGuiApi {
|
||||
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||
const pasteText: string[] = []
|
||||
for (let i = 0; i < imgs.length; i++) {
|
||||
pasteText.push(pasteTemplate(pasteStyle, imgs[i]))
|
||||
pasteText.push(pasteTemplate(pasteStyle, imgs[i], db.get('settings.customLink')))
|
||||
const notification = new Notification({
|
||||
title: '上传成功',
|
||||
body: imgs[i].imgUrl as string,
|
||||
@@ -78,7 +92,7 @@ class GuiApi implements IGuiApi {
|
||||
setTimeout(() => {
|
||||
notification.show()
|
||||
}, i * 100)
|
||||
db.insert('uploaded', imgs[i])
|
||||
await GalleryDB.getInstance().insert(imgs[i])
|
||||
}
|
||||
handleCopyUrl(pasteText.join('\n'))
|
||||
webContents.send('uploadFiles', imgs)
|
||||
@@ -118,6 +132,48 @@ class GuiApi implements IGuiApi {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* get picgo config/data path
|
||||
*/
|
||||
async getConfigPath () {
|
||||
const currentConfigPath = dbPathChecker()
|
||||
const galleryDBPath = getGalleryDBPath().dbPath
|
||||
return {
|
||||
defaultConfigPath,
|
||||
currentConfigPath,
|
||||
galleryDBPath
|
||||
}
|
||||
}
|
||||
|
||||
get galleryDB (): DBStore {
|
||||
return new Proxy<DBStore>(GalleryDB.getInstance(), {
|
||||
get (target, prop: keyof DBStore) {
|
||||
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: '有插件正在试图删除一些相册图片,是否继续',
|
||||
type: 'info',
|
||||
buttons: ['Yes', 'No']
|
||||
}).then(res => {
|
||||
if (res.result === 0) {
|
||||
resolve(Reflect.apply(target, ctx, args))
|
||||
} else {
|
||||
resolve(undefined)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
return Reflect.get(target, prop)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default GuiApi
|
||||
|
||||
@@ -8,12 +8,14 @@ import windowManager from 'apis/app/window/windowManager'
|
||||
import { IWindowList } from 'apis/app/window/constants'
|
||||
import uploader from 'apis/app/uploader'
|
||||
import pasteTemplate from '#/utils/pasteTemplate'
|
||||
import db from '#/datastore'
|
||||
import db, { GalleryDB } from '~/main/apis/core/datastore'
|
||||
import server from '~/main/server'
|
||||
import getPicBeds from '~/main/utils/getPicBeds'
|
||||
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
|
||||
import bus from '@core/bus'
|
||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
|
||||
import {
|
||||
TOGGLE_SHORTKEY_MODIFIED_MODE
|
||||
} from '#/events/constants'
|
||||
import {
|
||||
uploadClipboardFiles,
|
||||
uploadChoosedFiles
|
||||
@@ -30,7 +32,7 @@ export default {
|
||||
const img = await uploader.setWebContents(trayWindow.webContents).upload()
|
||||
if (img !== false) {
|
||||
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||
handleCopyUrl(pasteTemplate(pasteStyle, img[0]))
|
||||
handleCopyUrl(pasteTemplate(pasteStyle, img[0], db.get('settings.customLink')))
|
||||
const notification = new Notification({
|
||||
title: '上传成功',
|
||||
body: img[0].imgUrl!,
|
||||
@@ -38,7 +40,7 @@ export default {
|
||||
icon: img[0].imgUrl
|
||||
})
|
||||
notification.show()
|
||||
db.insert('uploaded', img[0])
|
||||
await GalleryDB.getInstance().insert(img[0])
|
||||
trayWindow.webContents.send('clipboardFiles', [])
|
||||
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
|
||||
|
||||
@@ -4,8 +4,7 @@ import {
|
||||
dialog,
|
||||
shell,
|
||||
IpcMainEvent,
|
||||
ipcMain,
|
||||
app
|
||||
ipcMain
|
||||
} from 'electron'
|
||||
import PicGoCore from '~/universal/types/picgo'
|
||||
import { IPicGoHelperType } from '#/types/enum'
|
||||
@@ -16,11 +15,26 @@ import { IGuiMenuItem } from 'picgo/dist/src/types'
|
||||
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 {
|
||||
PICGO_SAVE_CONFIG,
|
||||
PICGO_GET_CONFIG,
|
||||
PICGO_GET_DB,
|
||||
PICGO_INSERT_DB,
|
||||
PICGO_INSERT_MANY_DB,
|
||||
PICGO_UPDATE_BY_ID_DB,
|
||||
PICGO_GET_BY_ID_DB,
|
||||
PICGO_REMOVE_BY_ID_DB,
|
||||
PICGO_OPEN_FILE
|
||||
} from '#/events/constants'
|
||||
|
||||
import { GalleryDB } from 'apis/core/datastore'
|
||||
import { IObject, IFilter } from '@picgo/store/dist/types'
|
||||
|
||||
// eslint-disable-next-line
|
||||
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
||||
// const PluginHandler = requireFunc('picgo/dist/lib/PluginHandler').default
|
||||
const STORE_PATH = app.getPath('userData')
|
||||
const STORE_PATH = path.dirname(dbPathChecker())
|
||||
// const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
|
||||
|
||||
type PicGoNotice = {
|
||||
@@ -121,12 +135,21 @@ const handleGetPluginList = () => {
|
||||
}
|
||||
|
||||
const handlePluginInstall = () => {
|
||||
ipcMain.on('installPlugin', async (event: IpcMainEvent, msg: string) => {
|
||||
ipcMain.on('installPlugin', async (event: IpcMainEvent, fullName: string) => {
|
||||
const dispose = handleNPMError()
|
||||
const res = await picgo.pluginHandler.install([msg])
|
||||
const res = await picgo.pluginHandler.install([fullName])
|
||||
event.sender.send('installPlugin', {
|
||||
success: res.success,
|
||||
body: fullName,
|
||||
errMsg: res.success ? '' : res.body
|
||||
})
|
||||
if (res.success) {
|
||||
event.sender.send('installSuccess', res.body[0])
|
||||
shortKeyHandler.registerPluginShortKey(res.body[0])
|
||||
} else {
|
||||
showNotification({
|
||||
title: '插件安装失败',
|
||||
body: res.body as string
|
||||
})
|
||||
}
|
||||
event.sender.send('hideLoading')
|
||||
dispose()
|
||||
@@ -140,6 +163,11 @@ const handlePluginUninstall = () => {
|
||||
if (res.success) {
|
||||
event.sender.send('uninstallSuccess', res.body[0])
|
||||
shortKeyHandler.unregisterPluginShortKey(res.body[0])
|
||||
} else {
|
||||
showNotification({
|
||||
title: '插件卸载失败',
|
||||
body: res.body as string
|
||||
})
|
||||
}
|
||||
event.sender.send('hideLoading')
|
||||
dispose()
|
||||
@@ -152,6 +180,11 @@ const handlePluginUpdate = () => {
|
||||
const res = await picgo.pluginHandler.update([msg])
|
||||
if (res.success) {
|
||||
event.sender.send('updateSuccess', res.body[0])
|
||||
} else {
|
||||
showNotification({
|
||||
title: '插件更新失败',
|
||||
body: res.body as string
|
||||
})
|
||||
}
|
||||
event.sender.send('hideLoading')
|
||||
dispose()
|
||||
@@ -191,12 +224,11 @@ const handleGetPicBedConfig = () => {
|
||||
const handlePluginActions = () => {
|
||||
ipcMain.on('pluginActions', (event: IpcMainEvent, name: string, label: string) => {
|
||||
const plugin = picgo.pluginLoader.getPlugin(name)
|
||||
const guiApi = new GuiApi()
|
||||
if (plugin?.guiMenu?.(picgo)?.length) {
|
||||
const menu: GuiMenuItem[] = plugin.guiMenu(picgo)
|
||||
menu.forEach(item => {
|
||||
if (item.label === label) {
|
||||
item.handle(picgo, guiApi)
|
||||
item.handle(picgo, GuiApi.getInstance())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -205,19 +237,25 @@ const handlePluginActions = () => {
|
||||
|
||||
const handleRemoveFiles = () => {
|
||||
ipcMain.on('removeFiles', (event: IpcMainEvent, files: ImgInfo[]) => {
|
||||
const guiApi = new GuiApi()
|
||||
setTimeout(() => {
|
||||
picgo.emit('remove', files, guiApi)
|
||||
picgo.emit('remove', files, GuiApi.getInstance())
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
|
||||
const handlePicGoSaveData = () => {
|
||||
ipcMain.on('picgoSaveData', (event: IpcMainEvent, data: IObj) => {
|
||||
const handlePicGoSaveConfig = () => {
|
||||
ipcMain.on(PICGO_SAVE_CONFIG, (event: IpcMainEvent, data: IObj) => {
|
||||
picgo.saveConfig(data)
|
||||
})
|
||||
}
|
||||
|
||||
const handlePicGoGetConfig = () => {
|
||||
ipcMain.on(PICGO_GET_CONFIG, (event: IpcMainEvent, key: string | undefined, callbackId: string) => {
|
||||
const result = picgo.getConfig(key)
|
||||
event.sender.send(PICGO_GET_CONFIG, result, callbackId)
|
||||
})
|
||||
}
|
||||
|
||||
const handleImportLocalPlugin = () => {
|
||||
ipcMain.on('importLocalPlugin', (event: IpcMainEvent) => {
|
||||
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||
@@ -245,6 +283,51 @@ const handleImportLocalPlugin = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const handlePicGoGalleryDB = () => {
|
||||
ipcMain.on(PICGO_GET_DB, async (event: IpcMainEvent, filter: IFilter, callbackId: string) => {
|
||||
const dbStore = GalleryDB.getInstance()
|
||||
const res = await dbStore.get(filter)
|
||||
event.sender.send(PICGO_GET_DB, res, callbackId)
|
||||
})
|
||||
|
||||
ipcMain.on(PICGO_INSERT_DB, async (event: IpcMainEvent, value: IObject, callbackId: string) => {
|
||||
const dbStore = GalleryDB.getInstance()
|
||||
const res = await dbStore.insert(value)
|
||||
event.sender.send(PICGO_INSERT_DB, res, callbackId)
|
||||
})
|
||||
|
||||
ipcMain.on(PICGO_INSERT_MANY_DB, async (event: IpcMainEvent, value: IObject[], callbackId: string) => {
|
||||
const dbStore = GalleryDB.getInstance()
|
||||
const res = await dbStore.insertMany(value)
|
||||
event.sender.send(PICGO_INSERT_MANY_DB, res, callbackId)
|
||||
})
|
||||
|
||||
ipcMain.on(PICGO_UPDATE_BY_ID_DB, async (event: IpcMainEvent, id: string, value: IObject[], callbackId: string) => {
|
||||
const dbStore = GalleryDB.getInstance()
|
||||
const res = await dbStore.updateById(id, value)
|
||||
event.sender.send(PICGO_UPDATE_BY_ID_DB, res, callbackId)
|
||||
})
|
||||
|
||||
ipcMain.on(PICGO_GET_BY_ID_DB, async (event: IpcMainEvent, id: string, callbackId: string) => {
|
||||
const dbStore = GalleryDB.getInstance()
|
||||
const res = await dbStore.getById(id)
|
||||
event.sender.send(PICGO_GET_BY_ID_DB, res, callbackId)
|
||||
})
|
||||
|
||||
ipcMain.on(PICGO_REMOVE_BY_ID_DB, async (event: IpcMainEvent, id: string, callbackId: string) => {
|
||||
const dbStore = GalleryDB.getInstance()
|
||||
const res = await dbStore.removeById(id)
|
||||
event.sender.send(PICGO_REMOVE_BY_ID_DB, res, callbackId)
|
||||
})
|
||||
}
|
||||
|
||||
const handleOpenFile = () => {
|
||||
ipcMain.on(PICGO_OPEN_FILE, (event: IpcMainEvent, fileName: string) => {
|
||||
const abFilePath = path.join(STORE_PATH, fileName)
|
||||
shell.openItem(abFilePath)
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
listen () {
|
||||
handleGetPluginList()
|
||||
@@ -254,7 +337,10 @@ export default {
|
||||
handleGetPicBedConfig()
|
||||
handlePluginActions()
|
||||
handleRemoveFiles()
|
||||
handlePicGoSaveData()
|
||||
handlePicGoSaveConfig()
|
||||
handlePicGoGetConfig()
|
||||
handlePicGoGalleryDB()
|
||||
handleImportLocalPlugin()
|
||||
handleOpenFile()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import fse from 'fs-extra'
|
||||
import path from 'path'
|
||||
import dayjs from 'dayjs'
|
||||
import util from 'util'
|
||||
import { dbPathDir } from 'apis/core/datastore/dbChecker'
|
||||
const STORE_PATH = dbPathDir()
|
||||
const LOG_PATH = path.join(STORE_PATH, '/picgo.log')
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
process.on('uncaughtException', error => {
|
||||
handleProcessError(error)
|
||||
})
|
||||
|
||||
process.on('unhandledRejection', (error: any) => {
|
||||
handleProcessError(error)
|
||||
})
|
||||
+48
-31
@@ -1,14 +1,14 @@
|
||||
import './errorHandler'
|
||||
import {
|
||||
app,
|
||||
globalShortcut,
|
||||
protocol,
|
||||
dialog,
|
||||
Notification
|
||||
} from 'electron'
|
||||
import {
|
||||
createProtocol,
|
||||
installVueDevtools
|
||||
createProtocol
|
||||
} 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'
|
||||
@@ -16,7 +16,8 @@ import busEventList from '~/main/events/busEventList'
|
||||
import { IWindowList } from 'apis/app/window/constants'
|
||||
import windowManager from 'apis/app/window/windowManager'
|
||||
import {
|
||||
updateShortKeyFromVersion212
|
||||
updateShortKeyFromVersion212,
|
||||
migrateGalleryFromVersion230
|
||||
} from '~/main/migrate'
|
||||
import {
|
||||
uploadChoosedFiles,
|
||||
@@ -29,12 +30,33 @@ import server from '~/main/server/index'
|
||||
import updateChecker from '~/main/utils/updateChecker'
|
||||
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
|
||||
import { getUploadFiles } from '~/main/utils/handleArgv'
|
||||
import db from '#/datastore'
|
||||
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'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
const handleStartUpFiles = (argv: string[], cwd: string) => {
|
||||
const files = getUploadFiles(argv, cwd, logger)
|
||||
if (files === null || files.length > 0) { // 如果有文件列表作为参数,说明是命令行启动
|
||||
if (files === null) {
|
||||
logger.info('cli -> uploading file from clipboard')
|
||||
uploadClipboardFiles()
|
||||
} else {
|
||||
logger.info('cli -> uploading files from cli', ...files.map(item => item.path))
|
||||
const win = windowManager.getAvailableWindow()
|
||||
uploadChoosedFiles(win.webContents, files)
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class LifeCycle {
|
||||
private beforeReady () {
|
||||
private async beforeReady () {
|
||||
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
|
||||
// fix the $PATH in macOS
|
||||
fixPath()
|
||||
@@ -42,18 +64,24 @@ class LifeCycle {
|
||||
ipcList.listen()
|
||||
busEventList.listen()
|
||||
updateShortKeyFromVersion212(db, db.get('settings.shortKey'))
|
||||
await migrateGalleryFromVersion230(db, GalleryDB.getInstance(), picgo)
|
||||
}
|
||||
private onReady () {
|
||||
app.on('ready', async () => {
|
||||
const readyFunction = async () => {
|
||||
console.log('on ready')
|
||||
createProtocol('picgo')
|
||||
if (isDevelopment && !process.env.IS_TEST) {
|
||||
// Install Vue Devtools
|
||||
try {
|
||||
await installVueDevtools()
|
||||
await installExtension(VUEJS_DEVTOOLS)
|
||||
} catch (e) {
|
||||
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()
|
||||
@@ -65,15 +93,7 @@ class LifeCycle {
|
||||
})
|
||||
server.startup()
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
let files = getUploadFiles()
|
||||
if (files === null || files.length > 0) { // 如果有文件列表作为参数,说明是命令行启动
|
||||
if (files === null) {
|
||||
uploadClipboardFiles()
|
||||
} else {
|
||||
const win = windowManager.getAvailableWindow()
|
||||
uploadChoosedFiles(win.webContents, files)
|
||||
}
|
||||
}
|
||||
handleStartUpFiles(process.argv, process.cwd())
|
||||
}
|
||||
|
||||
if (global.notificationList?.length > 0) {
|
||||
@@ -83,19 +103,18 @@ class LifeCycle {
|
||||
notice.show()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!app.isReady()) {
|
||||
app.on('ready', readyFunction)
|
||||
} else {
|
||||
readyFunction()
|
||||
}
|
||||
}
|
||||
private onRunning () {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
let files = getUploadFiles(commandLine, workingDirectory)
|
||||
if (files === null || files.length > 0) { // 如果有文件列表作为参数,说明是命令行启动
|
||||
if (files === null) {
|
||||
uploadClipboardFiles()
|
||||
} else {
|
||||
const win = windowManager.getAvailableWindow()
|
||||
uploadChoosedFiles(win.webContents, files)
|
||||
}
|
||||
} else {
|
||||
logger.info('detect second instance')
|
||||
const result = handleStartUpFiles(commandLine, workingDirectory)
|
||||
if (!result) {
|
||||
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||
if (settingWindow.isMinimized()) {
|
||||
@@ -143,23 +162,21 @@ class LifeCycle {
|
||||
process.on('message', data => {
|
||||
if (data === 'graceful-exit') {
|
||||
app.quit()
|
||||
server.shutdown()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
process.on('SIGTERM', () => {
|
||||
app.quit()
|
||||
server.shutdown()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
launchApp () {
|
||||
async launchApp () {
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
this.beforeReady()
|
||||
await this.beforeReady()
|
||||
this.onReady()
|
||||
this.onRunning()
|
||||
this.onQuit()
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import DB from '#/datastore'
|
||||
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'
|
||||
// from v2.1.2
|
||||
const updateShortKeyFromVersion212 = (db: typeof DB, shortKeyConfig: IShortKeyConfigs | IOldShortKeyConfigs) => {
|
||||
const updateShortKeyFromVersion212 = (db: typeof ConfigStore, shortKeyConfig: IShortKeyConfigs | IOldShortKeyConfigs) => {
|
||||
// #557 极端情况可能会出现配置不存在,需要重新写入
|
||||
if (shortKeyConfig === undefined) {
|
||||
const defaultShortKeyConfig = {
|
||||
@@ -20,6 +24,7 @@ const updateShortKeyFromVersion212 = (db: typeof DB, shortKeyConfig: IShortKeyCo
|
||||
name: 'upload',
|
||||
label: '快捷上传'
|
||||
}
|
||||
// @ts-ignore
|
||||
delete shortKeyConfig.upload
|
||||
db.set('settings.shortKey', shortKeyConfig)
|
||||
return true
|
||||
@@ -27,6 +32,23 @@ const updateShortKeyFromVersion212 = (db: typeof DB, shortKeyConfig: IShortKeyCo
|
||||
return false
|
||||
}
|
||||
|
||||
const migrateGalleryFromVersion230 = async (configDB: typeof ConfigStore, galleryDB: DBStore, picgo: PicGoCore) => {
|
||||
const originGallery: ImgInfo[] = configDB.get('uploaded')
|
||||
const configPath = configDB.getConfigPath()
|
||||
const configBakPath = path.join(path.dirname(configPath), 'config.bak.json')
|
||||
// migrate gallery from config to gallery db
|
||||
if (originGallery && originGallery?.length > 0) {
|
||||
if (fse.existsSync(configBakPath)) {
|
||||
fse.copyFileSync(configPath, configBakPath)
|
||||
}
|
||||
await galleryDB.insertMany(originGallery)
|
||||
picgo.saveConfig({
|
||||
uploaded: []
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
updateShortKeyFromVersion212
|
||||
updateShortKeyFromVersion212,
|
||||
migrateGalleryFromVersion230
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class Server {
|
||||
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
|
||||
if (request.method === 'POST') {
|
||||
if (!routers.getHandler(request.url!)) {
|
||||
logger.warn(`[PicGo Server] don't support [${request.url}] url`)
|
||||
handleResponse({
|
||||
response,
|
||||
statusCode: 404,
|
||||
@@ -57,6 +58,7 @@ class Server {
|
||||
try {
|
||||
postObj = (body === '') ? {} : JSON.parse(body)
|
||||
} catch (err) {
|
||||
logger.error(`[PicGo Server]`, err)
|
||||
return handleResponse({
|
||||
response,
|
||||
body: {
|
||||
@@ -65,6 +67,7 @@ class Server {
|
||||
}
|
||||
})
|
||||
}
|
||||
logger.info(`[PicGo Server] get the request`, body)
|
||||
const handler = routers.getHandler(request.url!)
|
||||
handler!({
|
||||
...postObj,
|
||||
@@ -73,6 +76,7 @@ class Server {
|
||||
})
|
||||
}
|
||||
} else {
|
||||
logger.warn(`[PicGo Server] don't support [${request.method}] method`)
|
||||
response.statusCode = 404
|
||||
response.end()
|
||||
}
|
||||
@@ -99,6 +103,7 @@ class Server {
|
||||
})
|
||||
}
|
||||
startup () {
|
||||
console.log('startup', this.config.enable)
|
||||
if (this.config.enable) {
|
||||
this.listen(this.config.port)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import router from './router'
|
||||
import {
|
||||
uploadWithClipboardFiles,
|
||||
uploadWithFiles
|
||||
} from '@core/bus/apis'
|
||||
import {
|
||||
handleResponse
|
||||
} from './utils'
|
||||
import logger from '@core/picgo/logger'
|
||||
import windowManager from 'apis/app/window/windowManager'
|
||||
import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis'
|
||||
import path from 'path'
|
||||
import { dbPathDir } from 'apis/core/datastore/dbChecker'
|
||||
const STORE_PATH = dbPathDir()
|
||||
const LOG_PATH = path.join(STORE_PATH, 'picgo.log')
|
||||
|
||||
const errorMessage = `upload error. see ${LOG_PATH} for more detail.`
|
||||
|
||||
router.post('/upload', async ({
|
||||
response,
|
||||
@@ -18,39 +22,50 @@ router.post('/upload', async ({
|
||||
try {
|
||||
if (list.length === 0) {
|
||||
// upload with clipboard
|
||||
const res = await uploadWithClipboardFiles()
|
||||
if (res.success) {
|
||||
logger.info('[PicGo Server] upload clipboard file')
|
||||
const res = await uploadClipboardFiles()
|
||||
if (res) {
|
||||
handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: true,
|
||||
result: res.result
|
||||
result: [res]
|
||||
}
|
||||
})
|
||||
} else {
|
||||
handleResponse({
|
||||
response
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: errorMessage
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
logger.info('[PicGo Server] upload files in list')
|
||||
// upload with files
|
||||
const pathList = list.map(item => {
|
||||
return {
|
||||
path: item
|
||||
}
|
||||
})
|
||||
const res = await uploadWithFiles(pathList)
|
||||
if (res.success) {
|
||||
const win = windowManager.getAvailableWindow()
|
||||
const res = await uploadChoosedFiles(win.webContents, pathList)
|
||||
if (res.length) {
|
||||
handleResponse({
|
||||
response,
|
||||
body: {
|
||||
success: true,
|
||||
result: res.result
|
||||
result: res
|
||||
}
|
||||
})
|
||||
} else {
|
||||
handleResponse({
|
||||
response
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: errorMessage
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -60,7 +75,7 @@ router.post('/upload', async ({
|
||||
response,
|
||||
body: {
|
||||
success: false,
|
||||
message: err
|
||||
message: errorMessage
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import logger from '@core/picgo/logger'
|
||||
|
||||
export const handleResponse = ({
|
||||
response,
|
||||
statusCode = 200,
|
||||
@@ -13,6 +15,9 @@ export const handleResponse = ({
|
||||
header?: IObj,
|
||||
body?: any
|
||||
}) => {
|
||||
if (body?.success === false) {
|
||||
logger.warn('[PicGo Server] upload failed, see picgo.log for more detail ↑')
|
||||
}
|
||||
response.writeHead(statusCode, header)
|
||||
response.write(JSON.stringify(body))
|
||||
response.end()
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import { remote, app } from 'electron'
|
||||
import pkg from 'root/package.json'
|
||||
import { dbPathChecker } from 'apis/core/datastore/dbChecker'
|
||||
|
||||
const APP = process.type === 'renderer' ? remote.app : app
|
||||
const STORE_PATH = APP.getPath('userData')
|
||||
|
||||
function injectPicGoVersion () {
|
||||
global.PICGO_GUI_VERSION = pkg.version
|
||||
global.PICGO_CORE_VERSION = pkg.dependencies.picgo.replace('^', '')
|
||||
}
|
||||
const configPath = dbPathChecker()
|
||||
const CONFIG_DIR = path.dirname(configPath)
|
||||
|
||||
function beforeOpen () {
|
||||
injectPicGoVersion()
|
||||
if (process.platform === 'darwin') {
|
||||
resolveMacWorkFlow()
|
||||
}
|
||||
@@ -41,7 +34,7 @@ function resolveMacWorkFlow () {
|
||||
*/
|
||||
function resolveClipboardImageGenerator () {
|
||||
let clipboardFiles = getClipboardFiles()
|
||||
if (!fs.pathExistsSync(path.join(STORE_PATH, 'windows10.ps1'))) {
|
||||
if (!fs.pathExistsSync(path.join(CONFIG_DIR, 'windows10.ps1'))) {
|
||||
clipboardFiles.forEach(item => {
|
||||
fs.copyFileSync(item.origin, item.dest)
|
||||
})
|
||||
@@ -52,10 +45,15 @@ function resolveClipboardImageGenerator () {
|
||||
}
|
||||
|
||||
function diffFilesAndUpdate (filePath1: string, filePath2: string) {
|
||||
let file1 = fs.readFileSync(filePath1)
|
||||
let file2 = fs.readFileSync(filePath2)
|
||||
try {
|
||||
let file1 = fs.existsSync(filePath1) && fs.readFileSync(filePath1)
|
||||
let file2 = fs.existsSync(filePath1) && fs.readFileSync(filePath2)
|
||||
|
||||
if (!file1.equals(file2)) {
|
||||
if (!file1 || !file2 || !file1.equals(file2)) {
|
||||
fs.copyFileSync(filePath1, filePath2)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
fs.copyFileSync(filePath1, filePath2)
|
||||
}
|
||||
}
|
||||
@@ -65,13 +63,14 @@ function resolveClipboardImageGenerator () {
|
||||
'/linux.sh',
|
||||
'/mac.applescript',
|
||||
'/windows.ps1',
|
||||
'/windows10.ps1'
|
||||
'/windows10.ps1',
|
||||
'/wsl.sh'
|
||||
]
|
||||
|
||||
return files.map(item => {
|
||||
return {
|
||||
origin: path.join(__static, item),
|
||||
dest: path.join(STORE_PATH, item)
|
||||
dest: path.join(CONFIG_DIR, item)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import db from '#/datastore'
|
||||
import { clipboard, Notification } from 'electron'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import { clipboard, Notification, dialog } from 'electron'
|
||||
|
||||
export const handleCopyUrl = (str: string): void => {
|
||||
if (db.get('settings.autoCopy') !== false) {
|
||||
@@ -18,7 +18,8 @@ export const showNotification = (options: IPrivateShowNotificationOption = {
|
||||
}) => {
|
||||
const notification = new Notification({
|
||||
title: options.title,
|
||||
body: options.body
|
||||
body: options.body,
|
||||
icon: options.icon || undefined
|
||||
})
|
||||
const handleClick = () => {
|
||||
if (options.clickToCopy) {
|
||||
@@ -31,3 +32,40 @@ export const showNotification = (options: IPrivateShowNotificationOption = {
|
||||
})
|
||||
notification.show()
|
||||
}
|
||||
|
||||
export const showMessageBox = (options: any) => {
|
||||
return new Promise<IShowMessageBoxResult>(async (resolve, reject) => {
|
||||
dialog.showMessageBox(
|
||||
options
|
||||
).then((res) => {
|
||||
resolve({
|
||||
result: res.response,
|
||||
checkboxChecked: res.checkboxChecked
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const calcDurationRange = (duration: number) => {
|
||||
if (duration < 1000) {
|
||||
return 500
|
||||
} else if (duration < 1500) {
|
||||
return 1000
|
||||
} else if (duration < 3000) {
|
||||
return 2000
|
||||
} else if (duration < 5000) {
|
||||
return 3000
|
||||
} else if (duration < 7000) {
|
||||
return 5000
|
||||
} else if (duration < 10000) {
|
||||
return 8000
|
||||
} else if (duration < 12000) {
|
||||
return 10000
|
||||
} else if (duration < 20000) {
|
||||
return 15000
|
||||
} else if (duration < 30000) {
|
||||
return 20000
|
||||
}
|
||||
// max range
|
||||
return 100000
|
||||
}
|
||||
|
||||
@@ -1,35 +1,55 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
type ClipboardFileObject = {
|
||||
import Logger from 'picgo/dist/src/lib/Logger'
|
||||
interface IResultFileObject {
|
||||
path: string
|
||||
}
|
||||
type Result = ClipboardFileObject[]
|
||||
const getUploadFiles = (argv = process.argv, cwd = process.cwd()) => {
|
||||
let files = argv.slice(1)
|
||||
if (files.length > 0 && files[0] === 'upload') {
|
||||
if (files.length === 1) {
|
||||
type Result = IResultFileObject[]
|
||||
|
||||
interface IHandleArgvResult {
|
||||
success: boolean
|
||||
fileList?: string[]
|
||||
}
|
||||
|
||||
const handleArgv = (argv: string[]): IHandleArgvResult => {
|
||||
const uploadIndex = argv.indexOf('upload')
|
||||
if (uploadIndex !== -1) {
|
||||
const fileList = argv.slice(1 + uploadIndex)
|
||||
return {
|
||||
success: true,
|
||||
fileList
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: false
|
||||
}
|
||||
}
|
||||
|
||||
const getUploadFiles = (argv = process.argv, cwd = process.cwd(), logger: Logger) => {
|
||||
const { success, fileList } = handleArgv(argv)
|
||||
if (!success) {
|
||||
return []
|
||||
} else {
|
||||
if (fileList?.length === 0) {
|
||||
return null // for uploading images in clipboard
|
||||
} else if (files.length > 1) {
|
||||
files = argv.slice(1)
|
||||
let result: Result = []
|
||||
if (files.length > 0) {
|
||||
result = files.map(item => {
|
||||
if (path.isAbsolute(item)) {
|
||||
} else if ((fileList?.length || 0) > 0) {
|
||||
const result = fileList!.map(item => {
|
||||
if (path.isAbsolute(item)) {
|
||||
return {
|
||||
path: item
|
||||
}
|
||||
} else {
|
||||
let tempPath = path.join(cwd, item)
|
||||
if (fs.existsSync(tempPath)) {
|
||||
return {
|
||||
path: item
|
||||
path: tempPath
|
||||
}
|
||||
} else {
|
||||
let tempPath = path.join(cwd, item)
|
||||
if (fs.existsSync(tempPath)) {
|
||||
return {
|
||||
path: tempPath
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
logger.warn(`cli -> can't get file: ${tempPath}, invalid path`)
|
||||
return null
|
||||
}
|
||||
}).filter(item => item !== null) as Result
|
||||
}
|
||||
}
|
||||
}).filter(item => item !== null) as Result
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
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'
|
||||
|
||||
class PrivacyManager {
|
||||
async init () {
|
||||
ipcMain.on(SHOW_PRIVACY_MESSAGE, () => {
|
||||
this.show(false)
|
||||
})
|
||||
if (db.get('settings.privacyEnsure') !== true) {
|
||||
const res = await this.show(true)
|
||||
// cancel
|
||||
if (res.result === 1) {
|
||||
return false
|
||||
} else {
|
||||
db.set('settings.privacyEnsure', true)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async show (showCancel = true) {
|
||||
const res = await showMessageBox({
|
||||
type: 'info',
|
||||
buttons: showCancel ? ['Yes', 'No'] : ['Yes'],
|
||||
title: '隐私协议',
|
||||
message: `
|
||||
本软件尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更优质的服务,本软件会按照本隐私权政策的规定使用和收集您的一些行为信息。您在同意本软件服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本软件服务使用协议不可分割的一部分,如果不同意将无法使用。本协议会定期更新。
|
||||
|
||||
1.适用范围
|
||||
|
||||
a)在您使用本软件时,本软件会记录的您对本软件的一些操作行为信息,包括但不限于您使用本软件进行文件上传的耗时、类型、数量等信息。
|
||||
|
||||
2.信息的使用
|
||||
|
||||
a)在获得您的使用数据之后,本软件会将其上传至数据分析服务器,以便分析数据后,提供给您更好的服务。
|
||||
|
||||
3.信息披露
|
||||
|
||||
a)本软件不会将您的信息披露给不受信任的第三方。
|
||||
|
||||
b)根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;
|
||||
|
||||
c)如您出现违反中国有关法律、法规或者相关规则的情况,需要向第三方披露;
|
||||
|
||||
4.信息安全
|
||||
|
||||
a)本软件不会收集您的个人信息、密钥信息等隐私信息,所收集的信息仅仅作为改善软件、优化体验、了解软件日活等用途。
|
||||
`
|
||||
})
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
const privacyManager = new PrivacyManager()
|
||||
|
||||
export {
|
||||
privacyManager
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { dialog, shell } from 'electron'
|
||||
import db from '#/datastore'
|
||||
import db from '~/main/apis/core/datastore'
|
||||
import axios from 'axios'
|
||||
import pkg from 'root/package.json'
|
||||
import { lt } from 'semver'
|
||||
|
||||
@@ -8,31 +8,27 @@
|
||||
</el-switch>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'choose-pic-bed',
|
||||
props: {
|
||||
type: String,
|
||||
label: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
value: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.type === this.$db.get('picBed.current')) {
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from 'vue-property-decorator'
|
||||
@Component({
|
||||
name: 'choose-pic-bed'
|
||||
})
|
||||
export default class extends Vue {
|
||||
value = false
|
||||
@Prop() type!: string
|
||||
@Prop() label!: string
|
||||
async created () {
|
||||
const current = await this.getConfig<string>('picBed.current')
|
||||
if (this.type === current) {
|
||||
this.value = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
choosePicBed (val) {
|
||||
this.letPicGoSaveData({
|
||||
'picBed.current': this.type,
|
||||
'picBed.uploader': this.type
|
||||
})
|
||||
this.$emit('update:choosed', this.type)
|
||||
}
|
||||
}
|
||||
choosePicBed (val: string) {
|
||||
this.saveConfig({
|
||||
'picBed.current': this.type,
|
||||
'picBed.uploader': this.type
|
||||
})
|
||||
this.$emit('update:choosed', this.type)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -72,7 +72,7 @@ import { cloneDeep, union } from 'lodash'
|
||||
})
|
||||
export default class extends Vue {
|
||||
@Prop() private config!: any[]
|
||||
@Prop() readonly type!: string
|
||||
@Prop() readonly type!: 'uploader' | 'transformer' | 'plugin'
|
||||
@Prop() readonly id!: string
|
||||
configList = []
|
||||
ruleForm = {}
|
||||
@@ -81,9 +81,42 @@ export default class extends Vue {
|
||||
immediate: true
|
||||
})
|
||||
handleConfigChange (val: any) {
|
||||
this.handleConfig(val)
|
||||
}
|
||||
async validate () {
|
||||
return new Promise((resolve, reject) => {
|
||||
// @ts-ignore
|
||||
this.$refs.form.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
resolve(this.ruleForm)
|
||||
} else {
|
||||
resolve(false)
|
||||
return false
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getConfigType () {
|
||||
switch (this.type) {
|
||||
case 'plugin': {
|
||||
return this.id
|
||||
}
|
||||
case 'uploader': {
|
||||
return `picBed.${this.id}`
|
||||
}
|
||||
case 'transformer': {
|
||||
return `transformer.${this.id}`
|
||||
}
|
||||
default:
|
||||
return `unknown`
|
||||
}
|
||||
}
|
||||
|
||||
async handleConfig (val: any) {
|
||||
this.ruleForm = Object.assign({}, {})
|
||||
const config = this.$db.get(`picBed.${this.id}`)
|
||||
if (val.length > 0) {
|
||||
const config = await this.getConfig<IPicGoPluginConfig>(this.getConfigType())
|
||||
if (val.length > 0 && config) {
|
||||
this.configList = cloneDeep(val).map((item: any) => {
|
||||
let defaultValue = item.default !== undefined
|
||||
? item.default : item.type === 'checkbox'
|
||||
@@ -102,19 +135,6 @@ export default class extends Vue {
|
||||
})
|
||||
}
|
||||
}
|
||||
async validate () {
|
||||
return new Promise((resolve, reject) => {
|
||||
// @ts-ignore
|
||||
this.$refs.form.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
resolve(this.ruleForm)
|
||||
} else {
|
||||
resolve(false)
|
||||
return false
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
|
||||
@@ -91,35 +91,6 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
title="自定义链接格式"
|
||||
:visible.sync="customLinkVisible"
|
||||
>
|
||||
<el-form
|
||||
label-position="top"
|
||||
:model="customLink"
|
||||
ref="customLink"
|
||||
:rules="rules"
|
||||
>
|
||||
<el-form-item
|
||||
label="用占位符$url来表示url的位置"
|
||||
prop="value"
|
||||
>
|
||||
<el-input
|
||||
class="align-center"
|
||||
v-model="customLink.value"
|
||||
:autofocus="true"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div>
|
||||
如[]($url)
|
||||
</div>
|
||||
<span slot="footer">
|
||||
<el-button @click="cancelCustomLink">取消</el-button>
|
||||
<el-button type="primary" @click="confirmCustomLink">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
class="qrcode-dialog"
|
||||
top="3vh"
|
||||
@@ -183,9 +154,13 @@ import {
|
||||
IpcRendererEvent,
|
||||
clipboard
|
||||
} from 'electron'
|
||||
import db from '#/datastore'
|
||||
// import db from '#/datastore'
|
||||
import mixin from '@/utils/mixin'
|
||||
import InputBoxDialog from '@/components/InputBoxDialog.vue'
|
||||
import {
|
||||
SHOW_PRIVACY_MESSAGE
|
||||
} from '~/universal/events/constants'
|
||||
import { IConfig } from 'picgo/dist/src/types/index'
|
||||
const { Menu, dialog, BrowserWindow } = remote
|
||||
const customLinkRule = (rule: string, value: string, callback: (arg0?: Error) => void) => {
|
||||
if (!/\$url/.test(value)) {
|
||||
@@ -209,18 +184,7 @@ export default class extends Vue {
|
||||
visible = false
|
||||
keyBindingVisible = false
|
||||
customLinkVisible = false
|
||||
customLink = {
|
||||
value: db.get('customLink') || '$url'
|
||||
}
|
||||
rules = {
|
||||
value: [
|
||||
{ validator: customLinkRule, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
os = ''
|
||||
shortKey: IShortKeyMap = {
|
||||
upload: db.get('shortKey.upload')
|
||||
}
|
||||
picBed: IPicBedType[] = []
|
||||
qrcodeVisible = false
|
||||
picBedConfigString = ''
|
||||
@@ -235,8 +199,8 @@ export default class extends Vue {
|
||||
@Watch('choosedPicBedForQRCode')
|
||||
choosedPicBedForQRCodeChange (val: string[], oldVal: string[]) {
|
||||
if (val.length > 0) {
|
||||
this.$nextTick(() => {
|
||||
const picBedConfig = db.get('picBed')
|
||||
this.$nextTick(async () => {
|
||||
const picBedConfig = await this.getConfig('picBed')
|
||||
const config = pick(picBedConfig, ...this.choosedPicBedForQRCode)
|
||||
this.picBedConfigString = JSON.stringify(config)
|
||||
})
|
||||
@@ -301,6 +265,12 @@ export default class extends Vue {
|
||||
click () {
|
||||
_this.qrcodeVisible = true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '隐私协议',
|
||||
click () {
|
||||
ipcRenderer.send(SHOW_PRIVACY_MESSAGE)
|
||||
}
|
||||
}
|
||||
]
|
||||
this.menu = Menu.buildFromTemplate(template)
|
||||
@@ -309,29 +279,6 @@ export default class extends Vue {
|
||||
// this.menu!.popup(remote.getCurrentWindow())
|
||||
this.menu!.popup()
|
||||
}
|
||||
keyDetect (type: string, event: KeyboardEvent) {
|
||||
this.shortKey[type] = keyDetect(event).join('+')
|
||||
}
|
||||
cancelKeyBinding () {
|
||||
this.keyBindingVisible = false
|
||||
this.shortKey = db.get('shortKey')
|
||||
}
|
||||
cancelCustomLink () {
|
||||
this.customLinkVisible = false
|
||||
this.customLink.value = db.get('customLink') || '$url'
|
||||
}
|
||||
confirmCustomLink () {
|
||||
// @ts-ignore
|
||||
this.$refs.customLink.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
db.set('customLink', this.customLink.value)
|
||||
this.customLinkVisible = false
|
||||
ipcRenderer.send('updateCustomLink')
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
openMiniWindow () {
|
||||
ipcRenderer.send('openMiniWindow')
|
||||
}
|
||||
|
||||
@@ -71,12 +71,12 @@
|
||||
<el-col :span="20" :offset="2">
|
||||
<el-row :gutter="16">
|
||||
<gallerys
|
||||
:images="images"
|
||||
:images="filterList"
|
||||
:index="idx"
|
||||
@close="handleClose"
|
||||
:options="options"
|
||||
></gallerys>
|
||||
<el-col :span="6" v-for="(item, index) in images" :key="item.id" class="gallery-list__img">
|
||||
<el-col :span="6" v-for="(item, index) in filterList" :key="item.id" class="gallery-list__img">
|
||||
<div
|
||||
class="gallery-list__item"
|
||||
@click="zoomImage(index)"
|
||||
@@ -111,7 +111,9 @@
|
||||
// @ts-ignore
|
||||
import gallerys from 'vue-gallery'
|
||||
import pasteStyle from '#/utils/pasteTemplate'
|
||||
import { IPasteStyle } from '#/types/enum'
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||
import { IResult } from '@picgo/store/dist/types'
|
||||
import {
|
||||
ipcRenderer,
|
||||
clipboard,
|
||||
@@ -153,18 +155,23 @@ export default class extends Vue {
|
||||
picBed: IPicBedType[] = []
|
||||
@Watch('$route')
|
||||
handleRouteUpdate (to: any, from: any) {
|
||||
console.log(to, from)
|
||||
if (from.name === 'gallery') {
|
||||
this.clearChoosedList()
|
||||
}
|
||||
if (to.name === 'gallery') {
|
||||
this.updateGallery()
|
||||
}
|
||||
}
|
||||
created () {
|
||||
async created () {
|
||||
ipcRenderer.on('updateGallery', (event: IpcRendererEvent) => {
|
||||
this.$nextTick(() => {
|
||||
this.filterList = this.getGallery()
|
||||
this.$nextTick(async () => {
|
||||
this.updateGallery()
|
||||
})
|
||||
})
|
||||
ipcRenderer.send('getPicBeds')
|
||||
ipcRenderer.on('getPicBeds', this.getPicBeds)
|
||||
this.updateGallery()
|
||||
}
|
||||
mounted () {
|
||||
document.addEventListener('keydown', this.handleDetectShiftKey)
|
||||
@@ -178,9 +185,6 @@ export default class extends Vue {
|
||||
get filterList () {
|
||||
return this.getGallery()
|
||||
}
|
||||
set filterList (val) {
|
||||
this.images = val
|
||||
}
|
||||
get isAllSelected () {
|
||||
const values = Object.values(this.choosedList)
|
||||
if (values.length === 0) {
|
||||
@@ -194,37 +198,28 @@ export default class extends Vue {
|
||||
getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
|
||||
this.picBed = picBeds
|
||||
}
|
||||
getGallery () {
|
||||
if (this.choosedPicBed.length > 0) {
|
||||
let arr: ImgInfo[] = []
|
||||
this.choosedPicBed.forEach(item => {
|
||||
let obj: IObj = {
|
||||
type: item
|
||||
}
|
||||
if (this.searchText) {
|
||||
obj.fileName = this.searchText
|
||||
}
|
||||
// @ts-ignore
|
||||
arr = arr.concat(this.$db.read().get('uploaded').filter(obj => {
|
||||
return obj.fileName.indexOf(this.searchText) !== -1 && obj.type === item
|
||||
}).reverse().value())
|
||||
})
|
||||
this.images = arr
|
||||
getGallery (): ImgInfo[] {
|
||||
if (this.searchText || this.choosedPicBed.length > 0) {
|
||||
return this.images
|
||||
.filter(item => {
|
||||
let isInChoosedPicBed = true
|
||||
let isIncludesSearchText = true
|
||||
if (this.choosedPicBed.length > 0) {
|
||||
isInChoosedPicBed = this.choosedPicBed.some(type => type === item.type)
|
||||
}
|
||||
if (this.searchText) {
|
||||
isIncludesSearchText = item.fileName?.includes(this.searchText) || false
|
||||
}
|
||||
return isIncludesSearchText && isInChoosedPicBed
|
||||
})
|
||||
} else {
|
||||
if (this.searchText) {
|
||||
let data = this.$db.read().get('uploaded')
|
||||
// @ts-ignore
|
||||
.filter(item => {
|
||||
return item.fileName.indexOf(this.searchText) !== -1
|
||||
}).reverse().value()
|
||||
this.images = data
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this.images = this.$db.read().get('uploaded').slice().reverse().value()
|
||||
}
|
||||
return this.images
|
||||
}
|
||||
return this.images
|
||||
}
|
||||
async updateGallery () {
|
||||
this.images = (await this.$$db.get({ orderBy: 'desc' })).data
|
||||
}
|
||||
|
||||
@Watch('filterList')
|
||||
handleFilterListChange () {
|
||||
this.clearChoosedList()
|
||||
@@ -267,9 +262,10 @@ export default class extends Vue {
|
||||
this.idx = null
|
||||
this.changeZIndexForGallery(false)
|
||||
}
|
||||
copy (item: ImgInfo) {
|
||||
const style = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||
const copyLink = pasteStyle(style, item)
|
||||
async copy (item: ImgInfo) {
|
||||
const style = await this.getConfig<IPasteStyle>('settings.pasteStyle') || IPasteStyle.MARKDOWN
|
||||
const customLink = await this.getConfig<string>('settings.customLink')
|
||||
const copyLink = pasteStyle(style, item, customLink)
|
||||
const obj = {
|
||||
title: '复制链接成功',
|
||||
body: copyLink,
|
||||
@@ -286,9 +282,9 @@ export default class extends Vue {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const file = this.$db.getById('uploaded', id)
|
||||
this.$db.removeById('uploaded', id)
|
||||
}).then(async () => {
|
||||
const file = await this.$$db.getById(id)
|
||||
await this.$$db.removeById(id)
|
||||
ipcRenderer.send('removeFiles', [file])
|
||||
const obj = {
|
||||
title: '操作结果',
|
||||
@@ -298,7 +294,7 @@ export default class extends Vue {
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
this.getGallery()
|
||||
this.updateGallery()
|
||||
}).catch((e) => {
|
||||
console.log(e)
|
||||
return true
|
||||
@@ -309,12 +305,10 @@ export default class extends Vue {
|
||||
this.imgInfo.imgUrl = item.imgUrl as string
|
||||
this.dialogVisible = true
|
||||
}
|
||||
confirmModify () {
|
||||
this.$db.read().get('uploaded')
|
||||
// @ts-ignore
|
||||
.getById(this.imgInfo.id)
|
||||
.assign({ imgUrl: this.imgInfo.imgUrl })
|
||||
.write()
|
||||
async confirmModify () {
|
||||
await this.$$db.updateById(this.imgInfo.id, {
|
||||
imgUrl: this.imgInfo.imgUrl
|
||||
})
|
||||
const obj = {
|
||||
title: '修改图片URL成功',
|
||||
body: this.imgInfo.imgUrl,
|
||||
@@ -325,7 +319,7 @@ export default class extends Vue {
|
||||
return true
|
||||
}
|
||||
this.dialogVisible = false
|
||||
this.getGallery()
|
||||
this.updateGallery()
|
||||
}
|
||||
choosePicBed (type: string) {
|
||||
let idx = this.choosedPicBed.indexOf(type)
|
||||
@@ -355,18 +349,21 @@ export default class extends Vue {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
let files: ImgInfo[] = []
|
||||
Object.keys(this.choosedList).forEach(key => {
|
||||
}).then(async () => {
|
||||
let files: IResult<ImgInfo>[] = []
|
||||
const imageIDList = Object.keys(this.choosedList)
|
||||
for (let i = 0; i < imageIDList.length; i++) {
|
||||
const key = imageIDList[i]
|
||||
if (this.choosedList[key]) {
|
||||
const file = this.$db.getById('uploaded', key)
|
||||
files.push(file)
|
||||
this.$db.removeById('uploaded', key)
|
||||
const file = await this.$$db.getById<ImgInfo>(key)
|
||||
if (file) {
|
||||
files.push(file)
|
||||
await this.$$db.removeById(key)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
this.clearChoosedList()
|
||||
this.choosedList = {} // 只有删除才能将这个置空
|
||||
this.getGallery()
|
||||
const obj = {
|
||||
title: '操作结果',
|
||||
body: '删除成功'
|
||||
@@ -376,23 +373,29 @@ export default class extends Vue {
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
this.updateGallery()
|
||||
}).catch(() => {
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
multiCopy () {
|
||||
async multiCopy () {
|
||||
if (Object.values(this.choosedList).some(item => item)) {
|
||||
const copyString: string[] = []
|
||||
const style = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||
const style = await this.getConfig<IPasteStyle>('settings.pasteStyle') || IPasteStyle.MARKDOWN
|
||||
const customLink = await this.getConfig<string>('settings.customLink')
|
||||
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
||||
Object.keys(this.choosedList).forEach(key => {
|
||||
const imageIDList = Object.keys(this.choosedList)
|
||||
for (let i = 0; i < imageIDList.length; i++) {
|
||||
const key = imageIDList[i]
|
||||
if (this.choosedList[key]) {
|
||||
const item = this.$db.getById('uploaded', key)
|
||||
copyString.push(pasteStyle(style, item))
|
||||
this.choosedList[key] = false
|
||||
const item = await this.$$db.getById<ImgInfo>(key)
|
||||
if (item) {
|
||||
copyString.push(pasteStyle(style, item, customLink))
|
||||
this.choosedList[key] = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
const obj = {
|
||||
title: '批量复制链接成功',
|
||||
body: copyString.join('\n')
|
||||
@@ -407,11 +410,11 @@ export default class extends Vue {
|
||||
toggleHandleBar () {
|
||||
this.handleBarActive = !this.handleBarActive
|
||||
}
|
||||
getPasteStyle () {
|
||||
this.pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||
}
|
||||
handlePasteStyleChange (val: string) {
|
||||
this.$db.set('settings.pasteStyle', val)
|
||||
// getPasteStyle () {
|
||||
// this.pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||
// }
|
||||
async handlePasteStyleChange (val: string) {
|
||||
this.saveConfig('settings.pasteStyle', val)
|
||||
this.pasteStyle = val
|
||||
}
|
||||
beforeDestroy () {
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
IpcRendererEvent,
|
||||
remote
|
||||
} from 'electron'
|
||||
import path from 'path'
|
||||
import { SHOW_PRIVACY_MESSAGE } from '~/universal/events/constants'
|
||||
@Component({
|
||||
name: 'mini-page',
|
||||
mixins: [mixin]
|
||||
@@ -136,15 +136,16 @@ export default class extends Vue {
|
||||
openContextMenu () {
|
||||
this.menu!.popup()
|
||||
}
|
||||
buildMenu () {
|
||||
async buildMenu () {
|
||||
const _this = this
|
||||
const current = await this.getConfig('picBed.current')
|
||||
const submenu = this.picBed.filter(item => item.visible).map(item => {
|
||||
return {
|
||||
label: item.name,
|
||||
type: 'radio',
|
||||
checked: this.$db.get('picBed.current') === item.type,
|
||||
checked: current === item.type,
|
||||
click () {
|
||||
_this.letPicGoSaveData({
|
||||
_this.saveConfig({
|
||||
'picBed.current': item.type,
|
||||
'picBed.uploader': item.type
|
||||
})
|
||||
@@ -176,6 +177,12 @@ export default class extends Vue {
|
||||
remote.BrowserWindow.getFocusedWindow()!.hide()
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '隐私协议',
|
||||
click () {
|
||||
ipcRenderer.send(SHOW_PRIVACY_MESSAGE)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '重启应用',
|
||||
click () {
|
||||
|
||||
@@ -338,13 +338,14 @@
|
||||
<script lang="ts">
|
||||
import keyDetect from '@/utils/key-binding'
|
||||
import pkg from 'root/package.json'
|
||||
import path from 'path'
|
||||
import { IConfig } from 'picgo/dist/src/types/index'
|
||||
import { PICGO_OPEN_FILE } from '#/events/constants'
|
||||
import {
|
||||
ipcRenderer,
|
||||
remote
|
||||
} from 'electron'
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
import db from '#/datastore'
|
||||
// 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'
|
||||
@@ -355,30 +356,22 @@ const customLinkRule = (rule: string, value: string, callback: (arg0?: Error) =>
|
||||
return callback()
|
||||
}
|
||||
}
|
||||
let logLevel = db.get('settings.logLevel')
|
||||
if (!Array.isArray(logLevel)) {
|
||||
if (logLevel && logLevel.length > 0) {
|
||||
logLevel = [logLevel]
|
||||
} else {
|
||||
logLevel = ['all']
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
name: 'picgo-setting'
|
||||
})
|
||||
export default class extends Vue {
|
||||
form: ISettingForm = {
|
||||
updateHelper: db.get('settings.showUpdateTip'),
|
||||
updateHelper: false,
|
||||
showPicBedList: [],
|
||||
autoStart: db.get('settings.autoStart') || false,
|
||||
rename: db.get('settings.rename') || false,
|
||||
autoRename: db.get('settings.autoRename') || false,
|
||||
uploadNotification: db.get('settings.uploadNotification') || false,
|
||||
miniWindowOntop: db.get('settings.miniWindowOntop') || false,
|
||||
logLevel,
|
||||
autoCopyUrl: db.get('settings.autoCopy') === undefined ? true : db.get('settings.autoCopy'),
|
||||
checkBetaUpdate: db.get('settings.checkBetaUpdate') === undefined ? true : db.get('settings.checkBetaUpdate')
|
||||
autoStart: false,
|
||||
rename: false,
|
||||
autoRename: false,
|
||||
uploadNotification: false,
|
||||
miniWindowOntop: false,
|
||||
logLevel: ['all'],
|
||||
autoCopyUrl: true,
|
||||
checkBetaUpdate: true
|
||||
}
|
||||
picBed: IPicBedType[] = []
|
||||
logFileVisible = false
|
||||
@@ -388,14 +381,14 @@ export default class extends Vue {
|
||||
serverVisible = false
|
||||
proxyVisible = false
|
||||
customLink = {
|
||||
value: db.get('settings.customLink') || '$url'
|
||||
value: '$url'
|
||||
}
|
||||
shortKey: IShortKeyMap = {
|
||||
upload: db.get('settings.shortKey.upload')
|
||||
upload: ''
|
||||
}
|
||||
proxy = db.get('picBed.proxy') || ''
|
||||
npmRegistry = db.get('settings.registry') || ''
|
||||
npmProxy = db.get('settings.proxy') || ''
|
||||
proxy = ''
|
||||
npmRegistry = ''
|
||||
npmProxy = ''
|
||||
rules = {
|
||||
value: [
|
||||
{ validator: customLinkRule, trigger: 'blur' }
|
||||
@@ -409,7 +402,7 @@ export default class extends Vue {
|
||||
warn: '提醒-Warn',
|
||||
none: '不记录日志-None'
|
||||
}
|
||||
server = db.get('settings.server') || {
|
||||
server = {
|
||||
port: 36677,
|
||||
host: '127.0.0.1',
|
||||
enable: true
|
||||
@@ -429,7 +422,47 @@ export default class extends Vue {
|
||||
this.os = process.platform
|
||||
ipcRenderer.send('getPicBeds')
|
||||
ipcRenderer.on('getPicBeds', this.getPicBeds)
|
||||
this.initData()
|
||||
}
|
||||
async initData () {
|
||||
const config = (await this.getConfig<IConfig>())!
|
||||
if (config !== undefined) {
|
||||
const settings = config.settings || {}
|
||||
const picBed = config.picBed
|
||||
this.form.updateHelper = settings.showUpdateTip || false
|
||||
this.form.autoStart = settings.autoStart || false
|
||||
this.form.rename = settings.rename || false
|
||||
this.form.autoRename = settings.autoRename || false
|
||||
this.form.uploadNotification = settings.uploadNotification || false
|
||||
this.form.miniWindowOntop = settings.miniWindowOntop || false
|
||||
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.customLink.value = settings.customLink || '$url'
|
||||
this.shortKey.upload = settings.shortKey.upload
|
||||
this.proxy = picBed.proxy || ''
|
||||
this.npmRegistry = settings.registry || ''
|
||||
this.npmProxy = settings.proxy || ''
|
||||
this.server = settings.server || {
|
||||
port: 36677,
|
||||
host: '127.0.0.1',
|
||||
enable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initLogLevel (logLevel: string | string[]) {
|
||||
if (!Array.isArray(logLevel)) {
|
||||
if (logLevel && logLevel.length > 0) {
|
||||
logLevel = [logLevel]
|
||||
} else {
|
||||
logLevel = ['all']
|
||||
}
|
||||
}
|
||||
return logLevel
|
||||
}
|
||||
|
||||
getPicBeds (event: Event, picBeds: IPicBedType[]) {
|
||||
this.picBed = picBeds
|
||||
this.form.showPicBedList = this.picBed.map(item => {
|
||||
@@ -439,10 +472,7 @@ export default class extends Vue {
|
||||
}) as string[]
|
||||
}
|
||||
openFile (file: string) {
|
||||
const { app, shell } = remote
|
||||
const STORE_PATH = app.getPath('userData')
|
||||
const FILE = path.join(STORE_PATH, `/${file}`)
|
||||
shell.openItem(FILE)
|
||||
ipcRenderer.send(PICGO_OPEN_FILE, file)
|
||||
}
|
||||
openLogSetting () {
|
||||
this.logFileVisible = true
|
||||
@@ -450,15 +480,15 @@ export default class extends Vue {
|
||||
keyDetect (type: string, event: KeyboardEvent) {
|
||||
this.shortKey[type] = keyDetect(event).join('+')
|
||||
}
|
||||
cancelCustomLink () {
|
||||
async cancelCustomLink () {
|
||||
this.customLinkVisible = false
|
||||
this.customLink.value = db.get('settings.customLink') || '$url'
|
||||
this.customLink.value = await this.getConfig<string>('settings.customLink') || '$url'
|
||||
}
|
||||
confirmCustomLink () {
|
||||
// @ts-ignore
|
||||
this.$refs.customLink.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
db.set('settings.customLink', this.customLink.value)
|
||||
this.saveConfig('settings.customLink', this.customLink.value)
|
||||
this.customLinkVisible = false
|
||||
ipcRenderer.send('updateCustomLink')
|
||||
} else {
|
||||
@@ -466,13 +496,13 @@ export default class extends Vue {
|
||||
}
|
||||
})
|
||||
}
|
||||
cancelProxy () {
|
||||
async cancelProxy () {
|
||||
this.proxyVisible = false
|
||||
this.proxy = db.get('picBed.proxy') || undefined
|
||||
this.proxy = await this.getConfig<string>('picBed.proxy') || ''
|
||||
}
|
||||
confirmProxy () {
|
||||
this.proxyVisible = false
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.proxy': this.proxy,
|
||||
'settings.proxy': this.npmProxy,
|
||||
'settings.registry': this.npmRegistry
|
||||
@@ -485,10 +515,10 @@ export default class extends Vue {
|
||||
}
|
||||
}
|
||||
updateHelperChange (val: boolean) {
|
||||
db.set('settings.showUpdateTip', val)
|
||||
this.saveConfig('settings.showUpdateTip', val)
|
||||
}
|
||||
checkBetaUpdateChange (val: boolean) {
|
||||
db.set('settings.checkBetaUpdate', val)
|
||||
this.saveConfig('settings.checkBetaUpdate', val)
|
||||
}
|
||||
handleShowPicBedListChange (val: string[]) {
|
||||
const list = this.picBed.map(item => {
|
||||
@@ -499,22 +529,22 @@ export default class extends Vue {
|
||||
}
|
||||
return item
|
||||
})
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.list': list
|
||||
})
|
||||
ipcRenderer.send('getPicBeds')
|
||||
}
|
||||
handleAutoStartChange (val: boolean) {
|
||||
db.set('settings.autoStart', val)
|
||||
this.saveConfig('settings.autoStart', val)
|
||||
ipcRenderer.send('autoStart', val)
|
||||
}
|
||||
handleRename (val: boolean) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'settings.rename': val
|
||||
})
|
||||
}
|
||||
handleAutoRename (val: boolean) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'settings.autoRename': val
|
||||
})
|
||||
}
|
||||
@@ -556,14 +586,16 @@ export default class extends Vue {
|
||||
this.checkUpdateVisible = false
|
||||
}
|
||||
handleUploadNotification (val: boolean) {
|
||||
db.set('settings.uploadNotification', val)
|
||||
this.saveConfig({
|
||||
'settings.uploadNotification': val
|
||||
})
|
||||
}
|
||||
handleMiniWindowOntop (val: boolean) {
|
||||
db.set('settings.miniWindowOntop', val)
|
||||
this.saveConfig('settings.miniWindowOntop', val)
|
||||
this.$message.info('需要重启生效')
|
||||
}
|
||||
handleAutoCopyUrl (val: boolean) {
|
||||
db.set('settings.autoCopy', val)
|
||||
this.saveConfig('settings.autoCopy', val)
|
||||
const successNotification = new Notification('设置自动复制链接', {
|
||||
body: '设置成功'
|
||||
})
|
||||
@@ -575,7 +607,7 @@ export default class extends Vue {
|
||||
if (this.form.logLevel.length === 0) {
|
||||
return this.$message.error('请选择日志记录等级')
|
||||
}
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'settings.logLevel': this.form.logLevel
|
||||
})
|
||||
const successNotification = new Notification('设置日志', {
|
||||
@@ -586,9 +618,9 @@ export default class extends Vue {
|
||||
}
|
||||
this.logFileVisible = false
|
||||
}
|
||||
cancelLogLevelSetting () {
|
||||
async cancelLogLevelSetting () {
|
||||
this.logFileVisible = false
|
||||
let logLevel = db.get('settings.logLevel')
|
||||
let logLevel = await this.getConfig<string | string[]>('settings.logLevel')
|
||||
if (!Array.isArray(logLevel)) {
|
||||
if (logLevel && logLevel.length > 0) {
|
||||
logLevel = [logLevel]
|
||||
@@ -599,8 +631,9 @@ export default class extends Vue {
|
||||
this.form.logLevel = logLevel
|
||||
}
|
||||
confirmServerSetting () {
|
||||
// @ts-ignore
|
||||
this.server.port = parseInt(this.server.port, 10)
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'settings.server': this.server
|
||||
})
|
||||
const successNotification = new Notification('设置PicGo-Server', {
|
||||
@@ -612,9 +645,9 @@ export default class extends Vue {
|
||||
this.serverVisible = false
|
||||
ipcRenderer.send('updateServer')
|
||||
}
|
||||
cancelServerSetting () {
|
||||
async cancelServerSetting () {
|
||||
this.serverVisible = false
|
||||
this.server = db.get('settings.server') || {
|
||||
this.server = await this.getConfig('settings.server') || {
|
||||
port: 36677,
|
||||
host: '127.0.0.1',
|
||||
enable: true
|
||||
|
||||
@@ -164,7 +164,7 @@ export default class extends Vue {
|
||||
document.querySelector('.main-content.el-row').style.zIndex = 10
|
||||
}
|
||||
}
|
||||
created () {
|
||||
async created () {
|
||||
this.os = process.platform
|
||||
ipcRenderer.on('hideLoading', () => {
|
||||
this.loading = false
|
||||
@@ -174,12 +174,15 @@ export default class extends Vue {
|
||||
this.pluginNameList = list.map(item => item.fullName)
|
||||
this.loading = false
|
||||
})
|
||||
ipcRenderer.on('installSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||
ipcRenderer.on('installPlugin', (evt: IpcRendererEvent, { success, body }: {
|
||||
success: boolean,
|
||||
body: string
|
||||
}) => {
|
||||
this.loading = false
|
||||
this.pluginList.forEach(item => {
|
||||
if (item.fullName === plugin) {
|
||||
if (item.fullName === body) {
|
||||
item.ing = false
|
||||
item.hasInstall = true
|
||||
item.hasInstall = success
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -213,25 +216,26 @@ export default class extends Vue {
|
||||
})
|
||||
this.getPluginList()
|
||||
this.getSearchResult = debounce(this.getSearchResult, 50)
|
||||
this.needReload = this.$db.get('needReload')
|
||||
this.needReload = await this.getConfig<boolean>('needReload') || false
|
||||
}
|
||||
buildContextMenu (plugin: IPicGoPlugin) {
|
||||
async buildContextMenu (plugin: IPicGoPlugin) {
|
||||
const _this = this
|
||||
let menu = [{
|
||||
label: '启用插件',
|
||||
enabled: !plugin.enabled,
|
||||
click () {
|
||||
_this.letPicGoSaveData({
|
||||
_this.saveConfig({
|
||||
[`picgoPlugins.${plugin.fullName}`]: true
|
||||
})
|
||||
plugin.enabled = true
|
||||
_this.getPicBeds()
|
||||
_this.needReload = true
|
||||
}
|
||||
}, {
|
||||
label: '禁用插件',
|
||||
enabled: plugin.enabled,
|
||||
click () {
|
||||
_this.letPicGoSaveData({
|
||||
_this.saveConfig({
|
||||
[`picgoPlugins.${plugin.fullName}`]: false
|
||||
})
|
||||
plugin.enabled = false
|
||||
@@ -242,6 +246,7 @@ export default class extends Vue {
|
||||
if (plugin.config.uploader.name) {
|
||||
_this.handleRestoreState('uploader', plugin.config.uploader.name)
|
||||
}
|
||||
_this.needReload = true
|
||||
}
|
||||
}, {
|
||||
label: '卸载插件',
|
||||
@@ -263,7 +268,8 @@ export default class extends Vue {
|
||||
_this.configName = plugin.config[i].fullName || plugin.config[i].name
|
||||
_this.dialogVisible = true
|
||||
_this.config = plugin.config[i].config
|
||||
}
|
||||
},
|
||||
enabled: plugin.enabled
|
||||
}
|
||||
menu.push(obj)
|
||||
}
|
||||
@@ -271,7 +277,7 @@ export default class extends Vue {
|
||||
|
||||
// handle transformer
|
||||
if (plugin.config.transformer.name) {
|
||||
let currentTransformer = this.$db.get('picBed.transformer') || 'path'
|
||||
let currentTransformer = await this.getConfig<string>('picBed.transformer') || 'path'
|
||||
let pluginTransformer = plugin.config.transformer.name
|
||||
const obj = {
|
||||
label: `${currentTransformer === pluginTransformer ? '禁用' : '启用'}transformer - ${plugin.config.transformer.name}`,
|
||||
@@ -315,13 +321,13 @@ export default class extends Vue {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
item.ing = true
|
||||
ipcRenderer.send('installPlugin', item.name)
|
||||
ipcRenderer.send('installPlugin', item.fullName)
|
||||
}).catch(() => {
|
||||
console.log('Install canceled')
|
||||
})
|
||||
} else {
|
||||
item.ing = true
|
||||
ipcRenderer.send('installPlugin', item.name)
|
||||
ipcRenderer.send('installPlugin', item.fullName)
|
||||
}
|
||||
}
|
||||
uninstallPlugin (val: string) {
|
||||
@@ -346,8 +352,10 @@ export default class extends Vue {
|
||||
remote.app.relaunch()
|
||||
remote.app.exit(0)
|
||||
}
|
||||
handleReload () {
|
||||
this.$db.set('needReload', true)
|
||||
async handleReload () {
|
||||
this.saveConfig({
|
||||
needReload: true
|
||||
})
|
||||
this.needReload = true
|
||||
const successNotification = new Notification('更新成功', {
|
||||
body: '请点击此通知重启应用以生效'
|
||||
@@ -359,14 +367,14 @@ export default class extends Vue {
|
||||
cleanSearch () {
|
||||
this.searchText = ''
|
||||
}
|
||||
toggleTransformer (transformer: string) {
|
||||
let currentTransformer = this.$db.get('picBed.transformer') || 'path'
|
||||
async toggleTransformer (transformer: string) {
|
||||
let currentTransformer = await this.getConfig<string>('picBed.transformer') || 'path'
|
||||
if (currentTransformer === transformer) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.transformer': 'path'
|
||||
})
|
||||
} else {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.transformer': transformer
|
||||
})
|
||||
}
|
||||
@@ -377,17 +385,17 @@ export default class extends Vue {
|
||||
if (result !== false) {
|
||||
switch (this.currentType) {
|
||||
case 'plugin':
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
[`${this.configName}`]: result
|
||||
})
|
||||
break
|
||||
case 'uploader':
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
[`picBed.${this.configName}`]: result
|
||||
})
|
||||
break
|
||||
case 'transformer':
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
[`transformer.${this.configName}`]: result
|
||||
})
|
||||
break
|
||||
@@ -443,20 +451,20 @@ export default class extends Vue {
|
||||
}
|
||||
}
|
||||
// restore Uploader & Transformer
|
||||
handleRestoreState (item: string, name: string) {
|
||||
async handleRestoreState (item: string, name: string) {
|
||||
if (item === 'uploader') {
|
||||
const current = this.$db.get('picBed.current')
|
||||
const current = await this.getConfig('picBed.current')
|
||||
if (current === name) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.current': 'smms',
|
||||
'picBed.uploader': 'smms'
|
||||
})
|
||||
}
|
||||
}
|
||||
if (item === 'transformer') {
|
||||
const current = this.$db.get('picBed.transformer')
|
||||
const current = await this.getConfig('picBed.transformer')
|
||||
if (current === name) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.transformer': 'path'
|
||||
})
|
||||
}
|
||||
@@ -470,16 +478,13 @@ export default class extends Vue {
|
||||
goAwesomeList () {
|
||||
remote.shell.openExternal('https://github.com/PicGo/Awesome-PicGo')
|
||||
}
|
||||
letPicGoSaveData (data: IObj) {
|
||||
ipcRenderer.send('picgoSaveData', data)
|
||||
}
|
||||
handleImportLocalPlugin () {
|
||||
ipcRenderer.send('importLocalPlugin')
|
||||
this.loading = true
|
||||
}
|
||||
beforeDestroy () {
|
||||
ipcRenderer.removeAllListeners('pluginList')
|
||||
ipcRenderer.removeAllListeners('installSuccess')
|
||||
ipcRenderer.removeAllListeners('installPlugin')
|
||||
ipcRenderer.removeAllListeners('uninstallSuccess')
|
||||
ipcRenderer.removeAllListeners('updateSuccess')
|
||||
ipcRenderer.removeAllListeners('hideLoading')
|
||||
|
||||
@@ -109,8 +109,8 @@ export default class extends Vue {
|
||||
command = ''
|
||||
shortKey = ''
|
||||
currentIndex = 0
|
||||
created () {
|
||||
const shortKeyConfig = this.$db.get('settings.shortKey') as IShortKeyConfigs
|
||||
async created () {
|
||||
const shortKeyConfig = (await this.getConfig<IShortKeyConfigs>('settings.shortKey'))!
|
||||
this.list = Object.keys(shortKeyConfig).map(item => {
|
||||
return {
|
||||
...shortKeyConfig[item],
|
||||
@@ -132,26 +132,23 @@ export default class extends Vue {
|
||||
toggleEnable (item: IShortKeyConfig) {
|
||||
const status = !item.enable
|
||||
item.enable = status
|
||||
// this.$db.set(`settings.shortKey.${item.name}.enable`, status)
|
||||
ipcRenderer.send('bindOrUnbindShortKey', item, item.from)
|
||||
}
|
||||
keyDetect (event: KeyboardEvent) {
|
||||
this.shortKey = keyDetect(event).join('+')
|
||||
}
|
||||
openKeyBindingDialog (config: IShortKeyConfig, index: number) {
|
||||
async openKeyBindingDialog (config: IShortKeyConfig, index: number) {
|
||||
this.command = `${config.from}:${config.name}`
|
||||
this.shortKey = this.$db.get(`settings.shortKey.${this.command}.key`)
|
||||
this.shortKey = await this.getConfig(`settings.shortKey.${this.command}.key`) || ''
|
||||
this.currentIndex = index
|
||||
this.keyBindingVisible = true
|
||||
}
|
||||
cancelKeyBinding () {
|
||||
async cancelKeyBinding () {
|
||||
this.keyBindingVisible = false
|
||||
this.shortKey = this.$db.get(`settings.shortKey.${this.command}.key`)
|
||||
this.shortKey = await this.getConfig<string>(`settings.shortKey.${this.command}.key`) || ''
|
||||
}
|
||||
confirmKeyBinding () {
|
||||
const oldKey = this.$db.get(`settings.shortKey.${this.command}.key`)
|
||||
// this.$db.set(`settings.shortKey.${this.command}.key`, this.shortKey)
|
||||
// const newKey = this.$db.get(`settings.shortKey.${this.command}`)
|
||||
async confirmKeyBinding () {
|
||||
const oldKey = await this.getConfig<string>(`settings.shortKey.${this.command}.key`)
|
||||
const config = Object.assign({}, this.list[this.currentIndex])
|
||||
config.key = this.shortKey
|
||||
ipcRenderer.send('updateShortKey', config, oldKey, config.from)
|
||||
|
||||
@@ -30,12 +30,15 @@ import { Component, Vue } from 'vue-property-decorator'
|
||||
import mixin from '@/utils/mixin'
|
||||
import pasteTemplate from '#/utils/pasteTemplate'
|
||||
import { ipcRenderer, clipboard } from 'electron'
|
||||
import { IPasteStyle } from '#/types/enum'
|
||||
import { IResult } from '@picgo/store/dist/types'
|
||||
|
||||
@Component({
|
||||
name: 'tray-page',
|
||||
mixins: [mixin]
|
||||
})
|
||||
export default class extends Vue {
|
||||
files = []
|
||||
files: IResult<ImgInfo>[] = []
|
||||
notification = {
|
||||
title: '复制链接成功',
|
||||
body: '',
|
||||
@@ -46,16 +49,16 @@ export default class extends Vue {
|
||||
get reverseList () {
|
||||
return this.files.slice().reverse()
|
||||
}
|
||||
getData () {
|
||||
// @ts-ignore
|
||||
this.files = this.$db.read().get('uploaded').slice().reverse().slice(0, 5).value()
|
||||
async getData () {
|
||||
this.files = (await this.$$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
}
|
||||
copyTheLink (item: ImgInfo) {
|
||||
async copyTheLink (item: ImgInfo) {
|
||||
this.notification.body = item.imgUrl!
|
||||
this.notification.icon = item.imgUrl!
|
||||
const myNotification = new Notification(this.notification.title, this.notification)
|
||||
const pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||
clipboard.writeText(pasteTemplate(pasteStyle, item))
|
||||
const pasteStyle = await this.getConfig<IPasteStyle>('settings.pasteStyle') || IPasteStyle.MARKDOWN
|
||||
const customLink = await this.getConfig<string>('settings.customLink')
|
||||
clipboard.writeText(pasteTemplate(pasteStyle, item, customLink))
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
@@ -83,19 +86,18 @@ export default class extends Vue {
|
||||
mounted () {
|
||||
this.disableDragFile()
|
||||
this.getData()
|
||||
ipcRenderer.on('dragFiles', (event: Event, files: string[]) => {
|
||||
files.forEach(item => {
|
||||
this.$db.insert('uploaded', item)
|
||||
})
|
||||
// @ts-ignore
|
||||
this.files = this.$db.read().get('uploaded').slice().reverse().slice(0, 5).value()
|
||||
ipcRenderer.on('dragFiles', async (event: Event, files: string[]) => {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const item = files[i]
|
||||
await this.$$db.insert(item)
|
||||
}
|
||||
this.files = (await this.$$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
})
|
||||
ipcRenderer.on('clipboardFiles', (event: Event, files: ImgInfo[]) => {
|
||||
this.clipboardFiles = files
|
||||
})
|
||||
ipcRenderer.on('uploadFiles', (event: Event) => {
|
||||
// @ts-ignore
|
||||
this.files = this.$db.read().get('uploaded').slice().reverse().slice(0, 5).value()
|
||||
ipcRenderer.on('uploadFiles', async (event: Event) => {
|
||||
this.files = (await this.$$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
|
||||
console.log(this.files)
|
||||
this.uploadFlag = false
|
||||
})
|
||||
|
||||
@@ -169,11 +169,13 @@ export default class extends Vue {
|
||||
})
|
||||
ipcRenderer.send('uploadChoosedFiles', sendFiles)
|
||||
}
|
||||
getPasteStyle () {
|
||||
this.pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||
async getPasteStyle () {
|
||||
this.pasteStyle = await this.getConfig('settings.pasteStyle') || 'markdown'
|
||||
}
|
||||
handlePasteStyleChange (val: string) {
|
||||
this.$db.set('settings.pasteStyle', val)
|
||||
this.saveConfig({
|
||||
'settings.pasteStyle': val
|
||||
})
|
||||
}
|
||||
uploadClipboardFiles () {
|
||||
ipcRenderer.send('uploadClipboardFilesFromUploadPage')
|
||||
@@ -196,10 +198,10 @@ export default class extends Vue {
|
||||
this.$message.error('请输入合法的URL')
|
||||
}
|
||||
}
|
||||
getDefaultPicBed () {
|
||||
const current: string = this.$db.get('picBed.current')
|
||||
async getDefaultPicBed () {
|
||||
const currentPicBed = await this.getConfig<string>('picBed.current')
|
||||
this.picBed.forEach(item => {
|
||||
if (item.type === current) {
|
||||
if (item.type === currentPicBed) {
|
||||
this.picBedName = item.name
|
||||
}
|
||||
})
|
||||
@@ -208,20 +210,21 @@ export default class extends Vue {
|
||||
this.picBed = picBeds
|
||||
this.getDefaultPicBed()
|
||||
}
|
||||
handleChangePicBed () {
|
||||
this.buildMenu()
|
||||
async handleChangePicBed () {
|
||||
await this.buildMenu()
|
||||
// this.menu.popup(remote.getCurrentWindow())
|
||||
this.menu!.popup()
|
||||
}
|
||||
buildMenu () {
|
||||
async buildMenu () {
|
||||
const _this = this
|
||||
const currentPicBed = await this.getConfig<string>('picBed.current')
|
||||
const submenu = this.picBed.filter(item => item.visible).map(item => {
|
||||
return {
|
||||
label: item.name,
|
||||
type: 'radio',
|
||||
checked: this.$db.get('picBed.current') === item.type,
|
||||
checked: currentPicBed === item.type,
|
||||
click () {
|
||||
_this.letPicGoSaveData({
|
||||
_this.saveConfig({
|
||||
'picBed.current': item.type,
|
||||
'picBed.uploader': item.type
|
||||
})
|
||||
|
||||
@@ -86,8 +86,8 @@ export default class extends Vue {
|
||||
customUrl: '',
|
||||
options: ''
|
||||
}
|
||||
created () {
|
||||
const config = this.$db.get('picBed.aliyun') as IAliYunConfig
|
||||
async created () {
|
||||
const config = await this.getConfig<IAliYunConfig>('picBed.aliyun')
|
||||
if (config) {
|
||||
this.form = Object.assign({}, config)
|
||||
}
|
||||
@@ -96,7 +96,7 @@ export default class extends Vue {
|
||||
// @ts-ignore
|
||||
this.$refs.aliyun.validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.aliyun': this.form
|
||||
})
|
||||
const successNotification = new window.Notification('设置结果', {
|
||||
|
||||
@@ -71,8 +71,8 @@ export default class extends Vue {
|
||||
customUrl: '',
|
||||
branch: ''
|
||||
}
|
||||
created () {
|
||||
const config = this.$db.get('picBed.github') as IGitHubConfig
|
||||
async created () {
|
||||
const config = await this.getConfig<IGitHubConfig>('picBed.github')
|
||||
if (config) {
|
||||
this.form = Object.assign({}, config)
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export default class extends Vue {
|
||||
// @ts-ignore
|
||||
this.$refs.github.validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.github': this.form
|
||||
})
|
||||
const successNotification = new Notification('设置结果', {
|
||||
|
||||
@@ -48,8 +48,8 @@ export default class extends Vue {
|
||||
clientId: '',
|
||||
proxy: ''
|
||||
}
|
||||
created () {
|
||||
const config = this.$db.get('picBed.imgur') as IImgurConfig
|
||||
async created () {
|
||||
const config = await this.getConfig<IImgurConfig>('picBed.imgur')
|
||||
if (config) {
|
||||
this.form = Object.assign({}, config)
|
||||
}
|
||||
@@ -58,7 +58,7 @@ export default class extends Vue {
|
||||
// @ts-ignore
|
||||
this.$refs.imgur.validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.imgur': this.form
|
||||
})
|
||||
const successNotification = new Notification('设置结果', {
|
||||
|
||||
@@ -56,7 +56,7 @@ export default class extends Vue {
|
||||
// @ts-ignore
|
||||
const result = await this.$refs.configForm.validate()
|
||||
if (result !== false) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
[`picBed.${this.type}`]: result
|
||||
})
|
||||
const successNotification = new Notification('设置结果', {
|
||||
@@ -68,7 +68,7 @@ export default class extends Vue {
|
||||
}
|
||||
}
|
||||
setDefaultPicBed (type: string) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.current': type,
|
||||
'picBed.uploader': type
|
||||
})
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
:rules="{
|
||||
required: true, message: 'AccessKey不能为空', trigger: 'blur'
|
||||
}">
|
||||
<el-input v-model="form.accessKey" placeholder="AccessKey" @keyup.native.enter="confirm('weiboForm')"></el-input>
|
||||
<el-input v-model="form.accessKey" placeholder="AccessKey" @keyup.native.enter="confirm"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="设定SecretKey"
|
||||
@@ -88,8 +88,8 @@ export default class extends Vue {
|
||||
options: '',
|
||||
path: ''
|
||||
}
|
||||
created () {
|
||||
const config = this.$db.get('picBed.qiniu') as IQiniuConfig
|
||||
async created () {
|
||||
const config = await this.getConfig<IQiniuConfig>('picBed.qiniu')
|
||||
if (config) {
|
||||
this.form = Object.assign({}, config)
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export default class extends Vue {
|
||||
// @ts-ignore
|
||||
this.$refs.qiniu.validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.qiniu': this.form
|
||||
})
|
||||
const successNotification = new Notification('设置结果', {
|
||||
|
||||
@@ -41,17 +41,17 @@ export default class extends Vue {
|
||||
form: ISMMSConfig = {
|
||||
token: ''
|
||||
}
|
||||
created () {
|
||||
const config = this.$db.get('picBed.smms.token') as (string | boolean)
|
||||
async created () {
|
||||
const config = await this.getConfig<string | boolean>('picBed.smms.token')
|
||||
if (typeof config !== 'boolean') {
|
||||
this.form.token = config
|
||||
this.form.token = config || ''
|
||||
}
|
||||
}
|
||||
confirm () {
|
||||
// @ts-ignore
|
||||
this.$refs.smms.validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.smms': this.form
|
||||
})
|
||||
const successNotification = new window.Notification('设置结果', {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
:rules="{
|
||||
required: true, message: 'SecretId不能为空', trigger: 'blur'
|
||||
}">
|
||||
<el-input v-model="form.secretId" placeholder="SecretId" @keyup.native.enter="confirm('weiboForm')"></el-input>
|
||||
<el-input v-model="form.secretId" placeholder="SecretId" @keyup.native.enter="confirm"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="设定SecretKey"
|
||||
@@ -104,8 +104,8 @@ export default class extends Vue {
|
||||
customUrl: '',
|
||||
version: 'v4'
|
||||
}
|
||||
created () {
|
||||
const config = this.$db.get('picBed.tcyun') as ITcYunConfig
|
||||
async created () {
|
||||
const config = await this.getConfig<ITcYunConfig>('picBed.tcyun')
|
||||
if (config) {
|
||||
this.form = Object.assign({}, config)
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export default class extends Vue {
|
||||
// @ts-ignore
|
||||
this.$refs.tcyun.validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.tcyun': this.form
|
||||
})
|
||||
const successNotification = new window.Notification('设置结果', {
|
||||
|
||||
@@ -79,8 +79,8 @@ export default class extends Vue {
|
||||
options: '',
|
||||
path: ''
|
||||
}
|
||||
created () {
|
||||
const config = this.$db.get('picBed.upyun') as IUpYunConfig
|
||||
async created () {
|
||||
const config = await this.getConfig<IUpYunConfig>('picBed.upyun')
|
||||
if (config) {
|
||||
this.form = Object.assign({}, config)
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export default class extends Vue {
|
||||
// @ts-ignore
|
||||
this.$refs.tcyun.validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.upyun': this.form
|
||||
})
|
||||
const successNotification = new Notification('设置结果', {
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
<template>
|
||||
<div id="weibo-view">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="16" :offset="4">
|
||||
<div class="view-title">
|
||||
微博图床设置[已停止支持]
|
||||
</div>
|
||||
<el-form
|
||||
ref="weiboForm"
|
||||
label-position="right"
|
||||
label-width="120px"
|
||||
size="small"
|
||||
:model="form">
|
||||
<el-form-item
|
||||
label="设定用户名"
|
||||
prop="username"
|
||||
:rules="{
|
||||
required: !chooseCookie, message: '用户名不能为空', trigger: 'blur'
|
||||
}">
|
||||
<el-input v-model="form.username" placeholder="用户名" @keyup.native.enter="confirm('weiboForm')" :disabled="chooseCookie"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="设定密码"
|
||||
prop="password"
|
||||
:rules="{required: !chooseCookie,messsage: '密码不能为空',trigger: 'blur'}">
|
||||
<el-input v-model="form.password" type="password" @keyup.native.enter="confirm('weiboForm')" placeholder="密码" :disabled="chooseCookie"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="使用Cookie上传"
|
||||
>
|
||||
<el-switch
|
||||
v-model="chooseCookie"
|
||||
active-text="cookie模式"
|
||||
@change="handleSwitchChange"
|
||||
></el-switch>
|
||||
<i class="el-icon-question" @click="openWiki"></i>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="设定Cookie"
|
||||
prop="cookie"
|
||||
:rules="{
|
||||
required: chooseCookie, message: '密码不能为空', trigger: 'blur'
|
||||
}">
|
||||
<el-input v-model="form.cookie" @keyup.native.enter="confirm('weiboForm')" placeholder="Cookie" :disabled="!chooseCookie"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="* 图片质量">
|
||||
<el-radio-group v-model="quality">
|
||||
<el-radio label="thumbnail">缩略图</el-radio>
|
||||
<el-radio label="mw690">中等尺寸</el-radio>
|
||||
<el-radio label="large">原图</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button-group>
|
||||
<el-button type="primary" @click="confirm('weiboForm')" round>确定</el-button>
|
||||
<el-button type="success" @click="setDefaultPicBed('weibo')" round :disabled="defaultPicBed === 'weibo'">设为默认图床</el-button>
|
||||
</el-button-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import mixin from '@/utils/ConfirmButtonMixin'
|
||||
export default {
|
||||
name: 'weibo',
|
||||
mixins: [mixin],
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
username: '',
|
||||
password: '',
|
||||
cookie: ''
|
||||
},
|
||||
chooseCookie: false,
|
||||
quality: 'large'
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const config = this.$db.get('picBed.weibo')
|
||||
if (config) {
|
||||
this.form.username = config.username
|
||||
this.form.password = config.password
|
||||
this.quality = config.quality || 'large'
|
||||
this.form.cookie = config.cookie
|
||||
this.chooseCookie = config.chooseCookie
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
confirm (formName) {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
this.letPicGoSaveData({
|
||||
'picBed.weibo': {
|
||||
username: this.form.username,
|
||||
password: this.form.password,
|
||||
quality: this.quality,
|
||||
cookie: this.form.cookie,
|
||||
chooseCookie: this.chooseCookie
|
||||
}
|
||||
})
|
||||
const successNotification = new window.Notification('设置结果', {
|
||||
body: '设置成功'
|
||||
})
|
||||
successNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSwitchChange () {
|
||||
this.$refs['weiboForm'].resetFields()
|
||||
},
|
||||
openWiki () {
|
||||
this.$electron.remote.shell.openExternal('https://picgo.github.io/PicGo-Doc/zh/guide/config.html#微博图床')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='stylus'>
|
||||
.el-message
|
||||
left 60%
|
||||
#weibo-view
|
||||
.el-form
|
||||
label
|
||||
line-height 22px
|
||||
padding-bottom 0
|
||||
color #eee
|
||||
.el-button-group
|
||||
width 100%
|
||||
.el-button
|
||||
width 50%
|
||||
.el-input__inner
|
||||
border-radius 19px
|
||||
.el-radio-group
|
||||
margin-left 25px
|
||||
.el-switch__label
|
||||
color #eee
|
||||
&.is-active
|
||||
color #409EFF
|
||||
.el-icon-question
|
||||
font-size 20px
|
||||
float right
|
||||
margin-top 9px
|
||||
color #eee
|
||||
cursor pointer
|
||||
transition .2s color ease-in-out
|
||||
&:hover
|
||||
color #409EFF
|
||||
</style>
|
||||
@@ -31,11 +31,6 @@ export default new Router({
|
||||
component: () => import(/* webpackChunkName: "Upload" */ '@/pages/Upload.vue'),
|
||||
name: 'upload'
|
||||
},
|
||||
{
|
||||
path: 'weibo',
|
||||
component: () => import(/* webpackChunkName: "Weibo" */ '@/pages/picbeds/Weibo.vue'),
|
||||
name: 'weibo'
|
||||
},
|
||||
{
|
||||
path: 'qiniu',
|
||||
component: () => import(/* webpackChunkName: "Qiniu" */ '@/pages/picbeds/Qiniu.vue'),
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { IConfig } from 'picgo/dist/src/types'
|
||||
@Component
|
||||
export default class extends Vue {
|
||||
defaultPicBed = this.$db.get('picBed.current')
|
||||
defaultPicBed = 'smms'
|
||||
async created () {
|
||||
const config = await this.getConfig<IConfig>()
|
||||
if (config) {
|
||||
this.defaultPicBed = config?.picBed?.uploader || config?.picBed?.current || 'smms'
|
||||
}
|
||||
}
|
||||
setDefaultPicBed (type: string) {
|
||||
this.letPicGoSaveData({
|
||||
this.saveConfig({
|
||||
'picBed.current': type,
|
||||
'picBed.uploader': type
|
||||
})
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable camelcase */
|
||||
import {
|
||||
TALKING_DATA_APPID, TALKING_DATA_EVENT
|
||||
} from '~/universal/events/constants'
|
||||
import pkg from 'root/package.json'
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { handleTalkingDataEvent } from './common'
|
||||
const { version } = pkg
|
||||
|
||||
export const initTalkingData = () => {
|
||||
setTimeout(() => {
|
||||
const talkingDataScript = document.createElement('script')
|
||||
|
||||
talkingDataScript.src = `http://sdk.talkingdata.com/app/h5/v1?appid=${TALKING_DATA_APPID}&vn=${version}&vc=${version}`
|
||||
|
||||
const head = document.getElementsByTagName('head')[0]
|
||||
head.appendChild(talkingDataScript)
|
||||
}, 0)
|
||||
}
|
||||
|
||||
ipcRenderer.on(TALKING_DATA_EVENT, (_, data: ITalkingDataOptions) => {
|
||||
handleTalkingDataEvent(data)
|
||||
})
|
||||
@@ -0,0 +1,10 @@
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
/* eslint-disable camelcase */
|
||||
export const handleTalkingDataEvent = (data: ITalkingDataOptions) => {
|
||||
const { EventId, Label = '', MapKv = {} } = data
|
||||
MapKv.from = window.location.href
|
||||
window.TDAPP.onEvent(EventId, Label, MapKv)
|
||||
if (isDevelopment) {
|
||||
console.log('talkingData', data)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { IObject, IResult, IGetResult, IFilter } from '@picgo/store/dist/types'
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import { uuid } from 'uuidv4'
|
||||
import {
|
||||
PICGO_GET_DB,
|
||||
PICGO_INSERT_DB,
|
||||
PICGO_INSERT_MANY_DB,
|
||||
PICGO_UPDATE_BY_ID_DB,
|
||||
PICGO_GET_BY_ID_DB,
|
||||
PICGO_REMOVE_BY_ID_DB
|
||||
} from '#/events/constants'
|
||||
import { IGalleryDB } from '#/types/extra-vue'
|
||||
export class GalleryDB implements IGalleryDB {
|
||||
async get<T> (filter?: IFilter): Promise<IGetResult<T>> {
|
||||
const res = await this.msgHandler<IGetResult<T>>(PICGO_GET_DB, filter)
|
||||
return res
|
||||
}
|
||||
async insert<T> (value: T): Promise<IResult<T>> {
|
||||
const res = await this.msgHandler<IResult<T>>(PICGO_INSERT_DB, value)
|
||||
return res
|
||||
}
|
||||
async insertMany<T> (value: T[]): Promise<IResult<T>[]> {
|
||||
const res = await this.msgHandler<IResult<T>[]>(PICGO_INSERT_MANY_DB, value)
|
||||
return res
|
||||
}
|
||||
async updateById (id: string, value: IObject): Promise<boolean> {
|
||||
const res = await this.msgHandler<boolean>(PICGO_UPDATE_BY_ID_DB, id, value)
|
||||
return res
|
||||
}
|
||||
async getById<T> (id: string): Promise<IResult<T> | undefined> {
|
||||
const res = await this.msgHandler<IResult<T> | undefined>(PICGO_GET_BY_ID_DB, id)
|
||||
return res
|
||||
}
|
||||
async removeById (id: string): Promise<void> {
|
||||
const res = await this.msgHandler<void>(PICGO_REMOVE_BY_ID_DB, id)
|
||||
return res
|
||||
}
|
||||
private msgHandler<T> (method: string, ...args: any[]): Promise<T> {
|
||||
return new Promise((resolve) => {
|
||||
const callbackId = uuid()
|
||||
const callback = (event: IpcRendererEvent, data: T, returnCallbackId: string) => {
|
||||
if (returnCallbackId === callbackId) {
|
||||
resolve(data)
|
||||
ipcRenderer.removeListener(method, callback)
|
||||
}
|
||||
}
|
||||
ipcRenderer.on(method, callback)
|
||||
ipcRenderer.send(method, ...args, callbackId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default new GalleryDB()
|
||||
@@ -1,8 +1,29 @@
|
||||
import { Component, Vue } from 'vue-property-decorator'
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||
import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG } from '#/events/constants'
|
||||
import { uuid } from 'uuidv4'
|
||||
@Component
|
||||
export default class extends Vue {
|
||||
letPicGoSaveData (data: IObj) {
|
||||
ipcRenderer.send('picgoSaveData', data)
|
||||
// support string key + value or object config
|
||||
saveConfig (config: IObj | string, value?: any) {
|
||||
if (typeof config === 'string') {
|
||||
config = {
|
||||
[config]: value
|
||||
}
|
||||
}
|
||||
ipcRenderer.send(PICGO_SAVE_CONFIG, config)
|
||||
}
|
||||
getConfig<T> (key?: string): Promise<T | undefined> {
|
||||
return new Promise((resolve) => {
|
||||
const callbackId = uuid()
|
||||
const callback = (event: IpcRendererEvent, config: T | undefined, returnCallbackId: string) => {
|
||||
if (returnCallbackId === callbackId) {
|
||||
resolve(config)
|
||||
ipcRenderer.removeListener(PICGO_GET_CONFIG, callback)
|
||||
}
|
||||
}
|
||||
ipcRenderer.on(PICGO_GET_CONFIG, callback)
|
||||
ipcRenderer.send(PICGO_GET_CONFIG, key, callbackId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import { app } from 'electron'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const errorMsg = {
|
||||
broken: 'PicGo 配置文件损坏,已经恢复为默认配置',
|
||||
brokenButBackup: 'PicGo 配置文件损坏,已经恢复为备份配置'
|
||||
}
|
||||
|
||||
function dbChecker () {
|
||||
if (process.type !== 'renderer') {
|
||||
if (!global.notificationList) global.notificationList = []
|
||||
const STORE_PATH = app.getPath('userData')
|
||||
const configFilePath = path.join(STORE_PATH, 'data.json')
|
||||
const configFileBackupPath = path.join(STORE_PATH, 'data.bak.json')
|
||||
if (!fs.existsSync(configFilePath)) {
|
||||
return
|
||||
}
|
||||
let configFile: string = '{}'
|
||||
let optionsTpl = {
|
||||
title: '注意',
|
||||
body: ''
|
||||
}
|
||||
try {
|
||||
configFile = fs.readFileSync(configFilePath, { encoding: 'utf-8' })
|
||||
JSON.parse(configFile)
|
||||
} catch (e) {
|
||||
fs.unlinkSync(configFilePath)
|
||||
if (fs.existsSync(configFileBackupPath)) {
|
||||
try {
|
||||
configFile = fs.readFileSync(configFileBackupPath, { encoding: 'utf-8' })
|
||||
JSON.parse(configFile)
|
||||
fs.writeFileSync(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')}`
|
||||
global.notificationList.push(optionsTpl)
|
||||
return
|
||||
} catch (e) {
|
||||
optionsTpl.body = errorMsg.broken
|
||||
global.notificationList.push(optionsTpl)
|
||||
return
|
||||
}
|
||||
}
|
||||
optionsTpl.body = errorMsg.broken
|
||||
global.notificationList.push(optionsTpl)
|
||||
return
|
||||
}
|
||||
fs.writeFileSync(configFileBackupPath, configFile, { encoding: 'utf-8' })
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
dbChecker
|
||||
}
|
||||
@@ -1,3 +1,15 @@
|
||||
export const SHOW_INPUT_BOX = 'SHOW_INPUT_BOX'
|
||||
export const SHOW_INPUT_BOX_RESPONSE = 'SHOW_INPUT_BOX_RESPONSE'
|
||||
export const TOGGLE_SHORTKEY_MODIFIED_MODE = 'TOGGLE_SHORTKEY_MODIFIED_MODE'
|
||||
export const TALKING_DATA_APPID = '7E6832BCE3F1438696579E541DFEBFDA'
|
||||
export const TALKING_DATA_EVENT = 'TALKING_DATA_EVENT'
|
||||
export const SHOW_PRIVACY_MESSAGE = 'SHOW_PRIVACY_MESSAGE'
|
||||
export const PICGO_SAVE_CONFIG = 'PICGO_SAVE_CONFIG'
|
||||
export const PICGO_GET_CONFIG = 'PICGO_GET_CONFIG'
|
||||
export const PICGO_GET_DB = 'PICGO_GET_DB'
|
||||
export const PICGO_INSERT_DB = 'PICGO_INSERT_DB'
|
||||
export const PICGO_INSERT_MANY_DB = 'PICGO_INSERT_MANY_DB'
|
||||
export const PICGO_UPDATE_BY_ID_DB = 'PICGO_UPDATE_BY_ID_DB'
|
||||
export const PICGO_GET_BY_ID_DB = 'PICGO_GET_BY_ID_DB'
|
||||
export const PICGO_REMOVE_BY_ID_DB = 'PICGO_REMOVE_BY_ID_DB'
|
||||
export const PICGO_OPEN_FILE = 'PICGO_OPEN_FILE'
|
||||
|
||||
Vendored
+14
-3
@@ -1,14 +1,25 @@
|
||||
import VueRouter, { Route } from 'vue-router'
|
||||
import db from '#/datastore'
|
||||
import axios from 'axios'
|
||||
import { IObject, IResult, IGetResult, IFilter } from '@picgo/store/dist/types'
|
||||
|
||||
interface IGalleryDB {
|
||||
get<T>(filter?: IFilter): Promise<IGetResult<T>>
|
||||
insert<T> (value: T): Promise<IResult<T>>
|
||||
insertMany<T> (value: T[]): Promise<IResult<T>[]>
|
||||
updateById (id: string, value: IObject): Promise<boolean>
|
||||
getById<T> (id: string): Promise<IResult<T> | undefined>
|
||||
removeById (id: string): Promise<void>
|
||||
}
|
||||
|
||||
declare module 'vue/types/vue' {
|
||||
interface Vue {
|
||||
$router: VueRouter,
|
||||
$route: Route,
|
||||
$db: typeof db
|
||||
$http: typeof axios
|
||||
$builtInPicBed: string[]
|
||||
$bus: Vue
|
||||
letPicGoSaveData(data: IObj): void
|
||||
$$db: IGalleryDB
|
||||
saveConfig(data: IObj | string, value?: any): void
|
||||
getConfig<T>(key?: string): Promise<T | undefined>
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -10,4 +10,10 @@ declare global {
|
||||
[elem: string]: any
|
||||
}
|
||||
}
|
||||
|
||||
interface Window {
|
||||
TDAPP: {
|
||||
onEvent: (EventId: string, Label?: string, MapKv?: IStringKeyMap) => void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+26
@@ -45,6 +45,7 @@ interface ImgInfo {
|
||||
extname?: string
|
||||
imgUrl?: string
|
||||
id?: string
|
||||
type?: string
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
@@ -144,6 +145,14 @@ interface IPicGoPlugin {
|
||||
hasInstall?: boolean
|
||||
}
|
||||
|
||||
interface IPicGoPluginConfig {
|
||||
name: string
|
||||
type: string
|
||||
required: boolean
|
||||
default?: any
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
interface IPluginMenuConfig {
|
||||
name: string
|
||||
fullName?: string
|
||||
@@ -295,3 +304,20 @@ interface IAppNotification {
|
||||
body: string
|
||||
icon?: string
|
||||
}
|
||||
|
||||
interface ITalkingDataOptions {
|
||||
EventId: string
|
||||
Label?: string
|
||||
MapKv?: IStringKeyMap
|
||||
}
|
||||
|
||||
interface IAnalyticsData {
|
||||
fromClipboard: boolean
|
||||
type: string
|
||||
count: number
|
||||
duration?: number // 耗时
|
||||
}
|
||||
|
||||
interface IStringKeyMap {
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import db from '#/datastore'
|
||||
import { IPasteStyle } from '#/types/enum'
|
||||
import { handleUrlEncode } from './common'
|
||||
|
||||
@@ -19,15 +18,15 @@ const formatCustomLink = (customLink: string, item: ImgInfo) => {
|
||||
return customLink
|
||||
}
|
||||
|
||||
export default (style: IPasteStyle, item: ImgInfo) => {
|
||||
export default (style: IPasteStyle, item: ImgInfo, customLink: string | undefined) => {
|
||||
const url = handleUrlEncode(item.url || item.imgUrl)
|
||||
const customLink = db.get('settings.customLink') || '$url'
|
||||
const _customLink = customLink || '$url'
|
||||
const tpl = {
|
||||
'markdown': ``,
|
||||
'HTML': `<img src="${url}"/>`,
|
||||
'URL': url,
|
||||
'UBB': `[IMG]${url}[/IMG]`,
|
||||
'Custom': formatCustomLink(customLink, item)
|
||||
'Custom': formatCustomLink(_customLink, item)
|
||||
}
|
||||
return tpl[style]
|
||||
}
|
||||
|
||||
+18
-2
@@ -3,6 +3,8 @@ function resolve (dir) {
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
const arch = process.argv.includes('--ia32') ? 'ia32' : 'x64'
|
||||
|
||||
const config = {
|
||||
configureWebpack: {
|
||||
devtool: 'nosources-source-map'
|
||||
@@ -13,6 +15,11 @@ const config = {
|
||||
.set('~', resolve('src'))
|
||||
.set('root', resolve('./'))
|
||||
.set('#', resolve('src/universal'))
|
||||
// define
|
||||
// config.plugin('define')
|
||||
// .tap(args => {
|
||||
// return args
|
||||
// })
|
||||
},
|
||||
pluginOptions: {
|
||||
electronBuilder: {
|
||||
@@ -61,7 +68,14 @@ const config = {
|
||||
},
|
||||
win: {
|
||||
icon: 'build/icons/icon.ico',
|
||||
target: 'nsis'
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
artifactName: `PicGo Setup \${version}-${arch}.exe`,
|
||||
target: [{
|
||||
target: 'nsis',
|
||||
arch: [
|
||||
arch
|
||||
]
|
||||
}]
|
||||
},
|
||||
nsis: {
|
||||
shortcutName: 'PicGo',
|
||||
@@ -81,8 +95,10 @@ const config = {
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
config.configureWebpack = {
|
||||
devtool: 'eval-source-map'
|
||||
devtool: 'source-map'
|
||||
}
|
||||
// for dev main process hot reload
|
||||
config.pluginOptions.electronBuilder.mainProcessWatch = ['src/main/**/*']
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -918,6 +918,18 @@
|
||||
dependencies:
|
||||
ora "^3.4.0"
|
||||
|
||||
"@picgo/store@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@picgo/store/-/store-1.0.3.tgz#cfe346ad30c80f378e0bc81311e7468df436bc1f"
|
||||
integrity sha512-quyu56yuUsFFJGQ88suTwUSEzKosZPzR1M52eyqzyQ2HZWZVn0pa/eBBsh7OYefS0V13YLR5llnIkQaL8y11Ww==
|
||||
dependencies:
|
||||
"@types/bson" "^4.0.1"
|
||||
"@types/graceful-fs" "^4.1.3"
|
||||
bson "^4.0.3"
|
||||
comment-json "^4.1.0"
|
||||
lodash-id "^0.14.0"
|
||||
lowdb "^1.0.0"
|
||||
|
||||
"@sindresorhus/is@^0.14.0":
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
||||
@@ -939,6 +951,13 @@
|
||||
dependencies:
|
||||
defer-to-connect "^1.0.1"
|
||||
|
||||
"@types/bson@^4.0.1":
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.4.tgz#79d2d26e81070044db2a1a8b2cc2f673c840e1e5"
|
||||
integrity sha512-awqorHvQS0DqxkHQ/FxcPX9E+H7Du51Qw/2F+5TBMSaE3G0hm+8D3eXJ6MAzFw75nE8V7xF0QvzUSdxIjJb/GA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/caseless@*":
|
||||
version "0.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
|
||||
@@ -980,6 +999,13 @@
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/graceful-fs@^4.1.3":
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15"
|
||||
integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/inquirer@^6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be"
|
||||
@@ -1064,6 +1090,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.6.tgz#c880579e087d7a0db13777ff8af689f4ffc7b0d5"
|
||||
integrity sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ==
|
||||
|
||||
"@types/uuid@8.3.1":
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f"
|
||||
integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==
|
||||
|
||||
"@types/webpack-env@^1.13.9":
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7"
|
||||
@@ -1812,6 +1843,11 @@ array-includes@^3.0.3:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.0-next.0"
|
||||
|
||||
array-timsort@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926"
|
||||
integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==
|
||||
|
||||
array-union@^1.0.1, array-union@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
|
||||
@@ -2009,6 +2045,11 @@ base64-js@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
|
||||
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
|
||||
|
||||
base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
||||
base@^0.11.1:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
|
||||
@@ -2252,6 +2293,13 @@ browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.7.3, browserslist@^4.8
|
||||
electron-to-chromium "^1.3.322"
|
||||
node-releases "^1.1.42"
|
||||
|
||||
bson@^4.0.3:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/bson/-/bson-4.4.1.tgz#682c3cb8b90b222414ce14ef8398154ba2cc21bc"
|
||||
integrity sha512-Uu4OCZa0jouQJCKOk1EmmyqtdWAP5HVLru4lQxTwzJzxT+sJ13lVpEZU/MATDxtHiekWMAL84oQY3Xn1LpJVSg==
|
||||
dependencies:
|
||||
buffer "^5.6.0"
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||
@@ -2312,6 +2360,14 @@ buffer@^5.1.0, buffer@^5.2.1:
|
||||
base64-js "^1.0.2"
|
||||
ieee754 "^1.1.4"
|
||||
|
||||
buffer@^5.6.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
|
||||
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
|
||||
dependencies:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
builder-util-runtime@8.3.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.3.0.tgz#f5fac9139af6facf42a21fbe4d3aebed88fda33e"
|
||||
@@ -2879,6 +2935,17 @@ comment-json@^2.3.1:
|
||||
has-own-prop "^2.0.0"
|
||||
repeat-string "^1.6.1"
|
||||
|
||||
comment-json@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.1.0.tgz#09d08f0fbc4ad5eeccbac20f469adbb967dcbd2c"
|
||||
integrity sha512-WEghmVYaNq9NlWbrkzQTSsya9ycLyxJxpTQfZEan6a5Jomnjw18zS3Podf8q1Zf9BvonvQd/+Z7Z39L7KKzzdQ==
|
||||
dependencies:
|
||||
array-timsort "^1.0.3"
|
||||
core-util-is "^1.0.2"
|
||||
esprima "^4.0.1"
|
||||
has-own-prop "^2.0.0"
|
||||
repeat-string "^1.6.1"
|
||||
|
||||
commitizen@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/commitizen/-/commitizen-4.0.3.tgz#c19a4213257d0525b85139e2f36db7cc3b4f6dae"
|
||||
@@ -4189,6 +4256,16 @@ electron-chromedriver@^5.0.1:
|
||||
electron-download "^4.1.1"
|
||||
extract-zip "^1.6.7"
|
||||
|
||||
electron-devtools-installer@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz#acc48d24eb7033fe5af284a19667e73b78d406d0"
|
||||
integrity sha512-t3UczsYugm4OAbqvdImMCImIMVdFzJAHgbwHpkl5jmfu1izVgUcP/mnrPqJIpEeCK1uZGpt+yHgWEN+9EwoYhQ==
|
||||
dependencies:
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.2.1"
|
||||
tslib "^2.1.0"
|
||||
unzip-crx-3 "^0.2.0"
|
||||
|
||||
electron-download@^4.1.0, electron-download@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.1.tgz#02e69556705cc456e520f9e035556ed5a015ebe8"
|
||||
@@ -5969,6 +6046,11 @@ icss-utils@^4.0.0, icss-utils@^4.1.1:
|
||||
dependencies:
|
||||
postcss "^7.0.14"
|
||||
|
||||
ieee754@^1.1.13:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
|
||||
@@ -6348,6 +6430,11 @@ is-directory@^0.3.1:
|
||||
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
|
||||
integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=
|
||||
|
||||
is-docker@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
|
||||
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
|
||||
|
||||
is-extendable@^0.1.0, is-extendable@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
|
||||
@@ -6559,6 +6646,13 @@ is-wsl@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
||||
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
||||
|
||||
is-wsl@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
|
||||
integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
|
||||
dependencies:
|
||||
is-docker "^2.0.0"
|
||||
|
||||
is-yarn-global@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
|
||||
@@ -7109,6 +7203,13 @@ lru-cache@^5.1.1:
|
||||
dependencies:
|
||||
yallist "^3.0.2"
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
make-dir@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
|
||||
@@ -8289,10 +8390,10 @@ performance-now@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
picgo@^1.4.19:
|
||||
version "1.4.19"
|
||||
resolved "https://registry.yarnpkg.com/picgo/-/picgo-1.4.19.tgz#cbd4b39f1d1a2a5f231e62a7fdbf87f53298f2a8"
|
||||
integrity sha512-Y1BUrwq9rzEDQ06ZV5ZR8WRZqQe5hAHNVs4F/nEtwWBfr2YFwPxdce0b/rEPMZDSM7dfCWrts2M1qZC8VxB2+g==
|
||||
picgo@^1.4.24:
|
||||
version "1.4.24"
|
||||
resolved "https://registry.yarnpkg.com/picgo/-/picgo-1.4.24.tgz#0d5a492e1f4d29823912535122fdc14928a6ddad"
|
||||
integrity sha512-4QVTRIMLJes9c5vDuUl/c0TOEtUJycQhVdsXYtwx0fkKk/vhvfh0pRYUc33DEW88eGRi2CzAE2JJ93KHy5A8cg==
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
commander "^2.17.0"
|
||||
@@ -8305,6 +8406,7 @@ picgo@^1.4.19:
|
||||
globby "^8.0.2"
|
||||
image-size "^0.8.3"
|
||||
inquirer "^6.0.0"
|
||||
is-wsl "^2.2.0"
|
||||
lodash-id "^0.14.0"
|
||||
lowdb "^1.0.0"
|
||||
md5 "^2.2.1"
|
||||
@@ -9454,6 +9556,13 @@ rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rimraf@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
|
||||
@@ -9607,6 +9716,13 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.2.1:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
send@0.17.1:
|
||||
version "0.17.1"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
|
||||
@@ -10713,6 +10829,11 @@ tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
||||
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
|
||||
|
||||
tslib@^2.1.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
|
||||
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
|
||||
|
||||
tslint@^5.20.1:
|
||||
version "5.20.1"
|
||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"
|
||||
@@ -10909,6 +11030,15 @@ unset-value@^1.0.0:
|
||||
has-value "^0.3.1"
|
||||
isobject "^3.0.0"
|
||||
|
||||
unzip-crx-3@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz#d5324147b104a8aed9ae8639c95521f6f7cda292"
|
||||
integrity sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==
|
||||
dependencies:
|
||||
jszip "^3.1.0"
|
||||
mkdirp "^0.5.1"
|
||||
yaku "^0.16.6"
|
||||
|
||||
unzip-crx@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/unzip-crx/-/unzip-crx-0.2.0.tgz#4c0baa8bdac756256754beca7843c13d7b858c18"
|
||||
@@ -11084,11 +11214,24 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||
|
||||
uuid@8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
uuid@^3.0.1, uuid@^3.3.2:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
|
||||
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
|
||||
|
||||
uuidv4@^6.2.11:
|
||||
version "6.2.11"
|
||||
resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.2.11.tgz#34d5a03324eb38296b87ae523a64233b5286cc27"
|
||||
integrity sha512-OTS4waH9KplrXNADKo+Q1kT9AHWr8DaC0S5F54RQzEwcUaEzBEWQQlJyDUw/u1bkRhJyqkqhLD4M4lbFbV+89g==
|
||||
dependencies:
|
||||
"@types/uuid" "8.3.1"
|
||||
uuid "8.3.2"
|
||||
|
||||
validate-npm-package-license@^3.0.1:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
||||
|
||||
Reference in New Issue
Block a user