Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3caeccc492 | ||
|
|
c4f0a30c51 | ||
|
|
762dc9b2cc | ||
|
|
73870a5326 | ||
|
|
5f2b7c7802 | ||
|
|
0d6fdc4727 | ||
|
|
ded7998fbc | ||
|
|
3913cef1e6 | ||
|
|
b4f10c61f0 | ||
|
|
a04a25c7e0 | ||
|
|
e1a0cbb8a1 | ||
|
|
6b57cf7981 | ||
|
|
9a8b95e356 | ||
|
|
81e6acb29b | ||
|
|
c56d4efa79 | ||
|
|
3fd95725cf | ||
|
|
c6ead5b8cd | ||
|
|
f2750e1234 | ||
|
|
9d4d605acf | ||
|
|
cd30a6c70c | ||
|
|
a33f1adeb3 | ||
|
|
1b3522e536 | ||
|
|
3418560c63 | ||
|
|
fec4360043 | ||
|
|
b8ec879e23 | ||
|
|
29a55ed855 | ||
|
|
514fc40f71 | ||
|
|
bc8e641fda | ||
|
|
4e3fa28be6 | ||
|
|
87638a2882 | ||
|
|
1d98601757 | ||
|
|
4e67a75be0 | ||
|
|
72e6e2aed5 | ||
|
|
b63ac03b84 | ||
|
|
554cc0dbf8 | ||
|
|
1274893154 | ||
|
|
f491209bd6 | ||
|
|
f21940ef23 | ||
|
|
fe9e19a84d | ||
|
|
91b397de9a | ||
|
|
d06be462ff | ||
|
|
8fcbef5b0e | ||
|
|
c5adf3b68c | ||
|
|
5a064830c6 | ||
|
|
e38e6f038c | ||
|
|
c7ea9a8628 | ||
|
|
a5b6526fa4 | ||
|
|
46a49ed9d3 | ||
|
|
9344d7d762 | ||
|
|
e81b8f428c | ||
|
|
6f1fca7f7f |
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"comments": false,
|
|
||||||
"env": {
|
|
||||||
"test": {
|
|
||||||
"presets": [
|
|
||||||
["env", {
|
|
||||||
"targets": { "node": 7 }
|
|
||||||
}],
|
|
||||||
"stage-0"
|
|
||||||
],
|
|
||||||
"plugins": ["istanbul"]
|
|
||||||
},
|
|
||||||
"main": {
|
|
||||||
"presets": [
|
|
||||||
["env", {
|
|
||||||
"targets": { "node": 7 }
|
|
||||||
}],
|
|
||||||
"stage-0"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"renderer": {
|
|
||||||
"presets": [
|
|
||||||
["env", {
|
|
||||||
"modules": false
|
|
||||||
}],
|
|
||||||
"stage-0"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"production": {
|
|
||||||
"presets": [
|
|
||||||
["env", {
|
|
||||||
"modules": false
|
|
||||||
}],
|
|
||||||
"stage-0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"plugins": ["transform-runtime"]
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
process.env.NODE_ENV = 'production'
|
|
||||||
|
|
||||||
const { say } = require('cfonts')
|
|
||||||
const chalk = require('chalk')
|
|
||||||
const del = require('del')
|
|
||||||
const { spawn } = require('child_process')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
const Multispinner = require('multispinner')
|
|
||||||
|
|
||||||
|
|
||||||
const mainConfig = require('./webpack.main.config')
|
|
||||||
const rendererConfig = require('./webpack.renderer.config')
|
|
||||||
// const webConfig = require('./webpack.web.config')
|
|
||||||
|
|
||||||
const doneLog = chalk.bgGreen.white(' DONE ') + ' '
|
|
||||||
const errorLog = chalk.bgRed.white(' ERROR ') + ' '
|
|
||||||
const okayLog = chalk.bgBlue.white(' OKAY ') + ' '
|
|
||||||
const isCI = process.env.CI || false
|
|
||||||
|
|
||||||
if (process.env.BUILD_TARGET === 'clean') clean()
|
|
||||||
else if (process.env.BUILD_TARGET === 'web') web()
|
|
||||||
else build()
|
|
||||||
|
|
||||||
function clean () {
|
|
||||||
del.sync(['build/*', '!build/icons', '!build/icons/icon.*'])
|
|
||||||
console.log(`\n${doneLog}\n`)
|
|
||||||
process.exit()
|
|
||||||
}
|
|
||||||
|
|
||||||
function build () {
|
|
||||||
greeting()
|
|
||||||
|
|
||||||
del.sync(['dist/electron/*', '!.gitkeep'])
|
|
||||||
|
|
||||||
const tasks = ['main', 'renderer']
|
|
||||||
const m = new Multispinner(tasks, {
|
|
||||||
preText: 'building',
|
|
||||||
postText: 'process'
|
|
||||||
})
|
|
||||||
|
|
||||||
let results = ''
|
|
||||||
|
|
||||||
m.on('success', () => {
|
|
||||||
process.stdout.write('\x1B[2J\x1B[0f')
|
|
||||||
console.log(`\n\n${results}`)
|
|
||||||
console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
|
|
||||||
process.exit()
|
|
||||||
})
|
|
||||||
|
|
||||||
pack(mainConfig).then(result => {
|
|
||||||
results += result + '\n\n'
|
|
||||||
m.success('main')
|
|
||||||
}).catch(err => {
|
|
||||||
m.error('main')
|
|
||||||
console.log(`\n ${errorLog}failed to build main process`)
|
|
||||||
console.error(`\n${err}\n`)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
pack(rendererConfig).then(result => {
|
|
||||||
results += result + '\n\n'
|
|
||||||
m.success('renderer')
|
|
||||||
}).catch(err => {
|
|
||||||
m.error('renderer')
|
|
||||||
console.log(`\n ${errorLog}failed to build renderer process`)
|
|
||||||
console.error(`\n${err}\n`)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function pack (config) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
config.mode = 'production'
|
|
||||||
webpack(config, (err, stats) => {
|
|
||||||
if (err) reject(err.stack || err)
|
|
||||||
else if (stats.hasErrors()) {
|
|
||||||
let err = ''
|
|
||||||
|
|
||||||
stats.toString({
|
|
||||||
chunks: false,
|
|
||||||
colors: true
|
|
||||||
})
|
|
||||||
.split(/\r?\n/)
|
|
||||||
.forEach(line => {
|
|
||||||
err += ` ${line}\n`
|
|
||||||
})
|
|
||||||
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
resolve(stats.toString({
|
|
||||||
chunks: false,
|
|
||||||
colors: true
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// function web () {
|
|
||||||
// del.sync(['dist/web/*', '!.gitkeep'])
|
|
||||||
// webConfig.mode = 'production'
|
|
||||||
// webpack(webConfig, (err, stats) => {
|
|
||||||
// if (err || stats.hasErrors()) console.log(err)
|
|
||||||
|
|
||||||
// console.log(stats.toString({
|
|
||||||
// chunks: false,
|
|
||||||
// colors: true
|
|
||||||
// }))
|
|
||||||
|
|
||||||
// process.exit()
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
function greeting () {
|
|
||||||
const cols = process.stdout.columns
|
|
||||||
let text = ''
|
|
||||||
|
|
||||||
if (cols > 85) text = 'lets-build'
|
|
||||||
else if (cols > 60) text = 'lets-|build'
|
|
||||||
else text = false
|
|
||||||
|
|
||||||
if (text && !isCI) {
|
|
||||||
say(text, {
|
|
||||||
colors: ['yellow'],
|
|
||||||
font: 'simple3d',
|
|
||||||
space: false
|
|
||||||
})
|
|
||||||
} else console.log(chalk.yellow.bold('\n lets-build'))
|
|
||||||
console.log()
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
|
||||||
|
|
||||||
hotClient.subscribe(event => {
|
|
||||||
/**
|
|
||||||
* Reload browser when HTMLWebpackPlugin emits a new index.html
|
|
||||||
*
|
|
||||||
* Currently disabled until jantimon/html-webpack-plugin#680 is resolved.
|
|
||||||
* https://github.com/SimulatedGREG/electron-vue/issues/437
|
|
||||||
* https://github.com/jantimon/html-webpack-plugin/issues/680
|
|
||||||
*/
|
|
||||||
// if (event.action === 'reload') {
|
|
||||||
// window.location.reload()
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify `mainWindow` when `main` process is compiling,
|
|
||||||
* giving notice for an expected reload of the `electron` process
|
|
||||||
*/
|
|
||||||
if (event.action === 'compiling') {
|
|
||||||
document.body.innerHTML += `
|
|
||||||
<style>
|
|
||||||
#dev-client {
|
|
||||||
background: #4fc08d;
|
|
||||||
border-radius: 4px;
|
|
||||||
bottom: 20px;
|
|
||||||
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
|
|
||||||
color: #fff;
|
|
||||||
font-family: 'Source Sans Pro', sans-serif;
|
|
||||||
left: 20px;
|
|
||||||
padding: 8px 12px;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="dev-client">
|
|
||||||
Compiling Main Process...
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const chalk = require('chalk')
|
|
||||||
const electron = require('electron')
|
|
||||||
const path = require('path')
|
|
||||||
const { say } = require('cfonts')
|
|
||||||
const { spawn } = require('child_process')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
const WebpackDevServer = require('webpack-dev-server')
|
|
||||||
const webpackHotMiddleware = require('webpack-hot-middleware')
|
|
||||||
|
|
||||||
const mainConfig = require('./webpack.main.config')
|
|
||||||
const rendererConfig = require('./webpack.renderer.config')
|
|
||||||
|
|
||||||
let electronProcess = null
|
|
||||||
let manualRestart = false
|
|
||||||
let hotMiddleware
|
|
||||||
|
|
||||||
function logStats (proc, data) {
|
|
||||||
let log = ''
|
|
||||||
|
|
||||||
log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`)
|
|
||||||
log += '\n\n'
|
|
||||||
|
|
||||||
if (typeof data === 'object') {
|
|
||||||
data.toString({
|
|
||||||
colors: true,
|
|
||||||
chunks: false
|
|
||||||
}).split(/\r?\n/).forEach(line => {
|
|
||||||
log += ' ' + line + '\n'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
log += ` ${data}\n`
|
|
||||||
}
|
|
||||||
|
|
||||||
log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n'
|
|
||||||
|
|
||||||
console.log(log)
|
|
||||||
}
|
|
||||||
|
|
||||||
function startRenderer () {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
|
|
||||||
rendererConfig.mode = 'development'
|
|
||||||
const compiler = webpack(rendererConfig)
|
|
||||||
hotMiddleware = webpackHotMiddleware(compiler, {
|
|
||||||
log: false,
|
|
||||||
heartbeat: 2500
|
|
||||||
})
|
|
||||||
|
|
||||||
compiler.hooks.compilation.tap('compilation', compilation => {
|
|
||||||
compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
|
||||||
hotMiddleware.publish({ action: 'reload' })
|
|
||||||
cb()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
compiler.hooks.done.tap('done', stats => {
|
|
||||||
logStats('Renderer', stats)
|
|
||||||
})
|
|
||||||
|
|
||||||
const server = new WebpackDevServer(
|
|
||||||
compiler,
|
|
||||||
{
|
|
||||||
contentBase: path.join(__dirname, '../'),
|
|
||||||
quiet: true,
|
|
||||||
before (app, ctx) {
|
|
||||||
app.use(hotMiddleware)
|
|
||||||
ctx.middleware.waitUntilValid(() => {
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
server.listen(9080)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function startMain () {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
|
|
||||||
mainConfig.mode = 'development'
|
|
||||||
const compiler = webpack(mainConfig)
|
|
||||||
|
|
||||||
compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
|
|
||||||
logStats('Main', chalk.white.bold('compiling...'))
|
|
||||||
hotMiddleware.publish({ action: 'compiling' })
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
|
|
||||||
compiler.watch({}, (err, stats) => {
|
|
||||||
if (err) {
|
|
||||||
console.log(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logStats('Main', stats)
|
|
||||||
|
|
||||||
if (electronProcess && electronProcess.kill) {
|
|
||||||
manualRestart = true
|
|
||||||
process.kill(electronProcess.pid)
|
|
||||||
electronProcess = null
|
|
||||||
startElectron()
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
manualRestart = false
|
|
||||||
}, 5000)
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function startElectron () {
|
|
||||||
var args = [
|
|
||||||
'--inspect=5858',
|
|
||||||
path.join(__dirname, '../dist/electron/main.js')
|
|
||||||
]
|
|
||||||
|
|
||||||
// detect yarn or npm and process commandline args accordingly
|
|
||||||
if (process.env.npm_execpath.endsWith('yarn.js')) {
|
|
||||||
args = args.concat(process.argv.slice(3))
|
|
||||||
} else if (process.env.npm_execpath.endsWith('npm-cli.js')) {
|
|
||||||
args = args.concat(process.argv.slice(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
electronProcess = spawn(electron, args)
|
|
||||||
|
|
||||||
electronProcess.stdout.on('data', data => {
|
|
||||||
electronLog(data, 'blue')
|
|
||||||
})
|
|
||||||
electronProcess.stderr.on('data', data => {
|
|
||||||
electronLog(data, 'red')
|
|
||||||
})
|
|
||||||
|
|
||||||
electronProcess.on('close', () => {
|
|
||||||
if (!manualRestart) process.exit()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function electronLog (data, color) {
|
|
||||||
let log = ''
|
|
||||||
data = data.toString().split(/\r?\n/)
|
|
||||||
data.forEach(line => {
|
|
||||||
log += ` ${line}\n`
|
|
||||||
})
|
|
||||||
if (/[0-9A-z]+/.test(log)) {
|
|
||||||
console.log(
|
|
||||||
chalk[color].bold('┏ Electron -------------------') +
|
|
||||||
'\n\n' +
|
|
||||||
log +
|
|
||||||
chalk[color].bold('┗ ----------------------------') +
|
|
||||||
'\n'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function greeting () {
|
|
||||||
const cols = process.stdout.columns
|
|
||||||
let text = ''
|
|
||||||
|
|
||||||
if (cols > 104) text = 'electron-vue'
|
|
||||||
else if (cols > 76) text = 'electron-|vue'
|
|
||||||
else text = false
|
|
||||||
|
|
||||||
if (text) {
|
|
||||||
say(text, {
|
|
||||||
colors: ['yellow'],
|
|
||||||
font: 'simple3d',
|
|
||||||
space: false
|
|
||||||
})
|
|
||||||
} else console.log(chalk.yellow.bold('\n electron-vue'))
|
|
||||||
console.log(chalk.blue(' getting ready...') + '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
function init () {
|
|
||||||
greeting()
|
|
||||||
|
|
||||||
Promise.all([startRenderer(), startMain()])
|
|
||||||
.then(() => {
|
|
||||||
startElectron()
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
init()
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
||||||
const path = require('path')
|
|
||||||
const { VueLoaderPlugin } = require('vue-loader')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mode: 'development',
|
|
||||||
context: path.resolve(__dirname, '../docs'),
|
|
||||||
entry: './main.js',
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, '../docs/dist'),
|
|
||||||
filename: "index.js"
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'icons': path.resolve(__dirname, '../build/icons')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.(js|vue)$/,
|
|
||||||
enforce: 'pre',
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'eslint-loader',
|
|
||||||
options: {
|
|
||||||
formatter: require('eslint-friendly-formatter')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.styl(us)?$/,
|
|
||||||
use: [
|
|
||||||
'vue-style-loader',
|
|
||||||
'css-loader',
|
|
||||||
'stylus-loader'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.pug$/, loader: "pug-plain-loader"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
use: ['vue-style-loader', 'css-loader']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.html$/,
|
|
||||||
use: 'vue-html-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
use: 'babel-loader',
|
|
||||||
exclude: /node_modules/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.node$/,
|
|
||||||
use: 'node-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.vue$/,
|
|
||||||
use: {
|
|
||||||
loader: 'vue-loader',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
query: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'imgs/[name]--[folder].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'media/[name]--[folder].[ext]'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
query: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'fonts/[name]--[folder].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new VueLoaderPlugin(),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: path.resolve(__dirname, '../docs/template.html')
|
|
||||||
}),
|
|
||||||
new MiniCssExtractPlugin({filename: 'styles.css'}),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
// module.exports.devtool = '#source-map'
|
|
||||||
// http://vue-loader.vuejs.org/en/workflow/production.html
|
|
||||||
module.exports.mode = 'production'
|
|
||||||
module.exports.plugins = (module.exports.plugins || []).concat([
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
NODE_ENV: '"production"'
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
minimize: true
|
|
||||||
})
|
|
||||||
])
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
process.env.BABEL_ENV = 'main'
|
|
||||||
|
|
||||||
const path = require('path')
|
|
||||||
const { dependencies } = require('../package.json')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
|
|
||||||
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
|
||||||
|
|
||||||
let mainConfig = {
|
|
||||||
entry: {
|
|
||||||
main: path.join(__dirname, '../src/main/index.js')
|
|
||||||
},
|
|
||||||
externals: [
|
|
||||||
...Object.keys(dependencies || {})
|
|
||||||
],
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.(js)$/,
|
|
||||||
enforce: 'pre',
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'eslint-loader',
|
|
||||||
options: {
|
|
||||||
formatter: require('eslint-friendly-formatter')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
use: 'babel-loader',
|
|
||||||
exclude: /node_modules/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.node$/,
|
|
||||||
use: 'node-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
__dirname: process.env.NODE_ENV !== 'production',
|
|
||||||
__filename: process.env.NODE_ENV !== 'production'
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
filename: '[name].js',
|
|
||||||
libraryTarget: 'commonjs2',
|
|
||||||
path: path.join(__dirname, '../dist/electron')
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.NoEmitOnErrorsPlugin()
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.js', '.json', '.node']
|
|
||||||
},
|
|
||||||
target: 'electron-main'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjust mainConfig for development settings
|
|
||||||
*/
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
mainConfig.plugins.push(
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjust mainConfig for production settings
|
|
||||||
*/
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
mainConfig.plugins.push(
|
|
||||||
new BabiliWebpackPlugin(),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.NODE_ENV': '"production"'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = mainConfig
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
process.env.BABEL_ENV = 'renderer'
|
|
||||||
|
|
||||||
const path = require('path')
|
|
||||||
const { dependencies } = require('../package.json')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
|
|
||||||
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
const { VueLoaderPlugin } = require('vue-loader')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of node_modules to include in webpack bundle
|
|
||||||
*
|
|
||||||
* Required for specific packages like Vue UI libraries
|
|
||||||
* that provide pure *.vue files that need compiling
|
|
||||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
|
|
||||||
*/
|
|
||||||
let whiteListedModules = ['vue']
|
|
||||||
|
|
||||||
let rendererConfig = {
|
|
||||||
devtool: '#cheap-module-eval-source-map',
|
|
||||||
entry: {
|
|
||||||
renderer: path.join(__dirname, '../src/renderer/main.js')
|
|
||||||
},
|
|
||||||
externals: [
|
|
||||||
// ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
|
|
||||||
],
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.(js|vue)$/,
|
|
||||||
enforce: 'pre',
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'eslint-loader',
|
|
||||||
options: {
|
|
||||||
formatter: require('eslint-friendly-formatter')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.styl(us)?$/,
|
|
||||||
use: [
|
|
||||||
'vue-style-loader',
|
|
||||||
'css-loader',
|
|
||||||
'stylus-loader'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.less$/,
|
|
||||||
use: ['vue-style-loader', 'css-loader', 'less-loader']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
use: ['vue-style-loader', 'css-loader']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.html$/,
|
|
||||||
use: 'vue-html-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
use: 'babel-loader',
|
|
||||||
exclude: /node_modules/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.node$/,
|
|
||||||
use: 'node-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.vue$/,
|
|
||||||
use: {
|
|
||||||
loader: 'vue-loader',
|
|
||||||
options: {
|
|
||||||
extractCSS: process.env.NODE_ENV === 'production',
|
|
||||||
loaders: {
|
|
||||||
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
|
||||||
scss: 'vue-style-loader!css-loader!sass-loader',
|
|
||||||
less: 'vue-style-loader!css-loader!less-loader',
|
|
||||||
stylus: 'vue-style-loader!css-loader!stylus-loader'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
query: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'imgs/[name]--[folder].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'media/[name]--[folder].[ext]'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
query: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'fonts/[name]--[folder].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
__dirname: process.env.NODE_ENV !== 'production',
|
|
||||||
__filename: process.env.NODE_ENV !== 'production'
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new VueLoaderPlugin(),
|
|
||||||
new MiniCssExtractPlugin({filename: 'styles.css'}),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
filename: 'index.html',
|
|
||||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
|
||||||
minify: {
|
|
||||||
collapseWhitespace: true,
|
|
||||||
removeAttributeQuotes: true,
|
|
||||||
removeComments: true
|
|
||||||
},
|
|
||||||
nodeModules: process.env.NODE_ENV !== 'production'
|
|
||||||
? path.resolve(__dirname, '../node_modules')
|
|
||||||
: false
|
|
||||||
}),
|
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
|
||||||
new webpack.NoEmitOnErrorsPlugin()
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
filename: '[name].js',
|
|
||||||
libraryTarget: 'commonjs2',
|
|
||||||
path: path.join(__dirname, '../dist/electron')
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@': path.join(__dirname, '../src/renderer'),
|
|
||||||
'vue$': 'vue/dist/vue.esm.js',
|
|
||||||
'utils': path.join(__dirname, '../src/renderer/utils'),
|
|
||||||
'~': path.join(__dirname, '../src'),
|
|
||||||
'root': path.join(__dirname, '../')
|
|
||||||
},
|
|
||||||
extensions: ['.js', '.vue', '.json', '.css', '.node']
|
|
||||||
},
|
|
||||||
target: 'electron-renderer'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjust rendererConfig for development settings
|
|
||||||
*/
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
rendererConfig.plugins.push(
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjust rendererConfig for production settings
|
|
||||||
*/
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
rendererConfig.devtool = ''
|
|
||||||
|
|
||||||
rendererConfig.plugins.push(
|
|
||||||
new BabiliWebpackPlugin(),
|
|
||||||
new CopyWebpackPlugin([
|
|
||||||
{
|
|
||||||
from: path.join(__dirname, '../static'),
|
|
||||||
to: path.join(__dirname, '../dist/electron/static'),
|
|
||||||
ignore: ['.*']
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.NODE_ENV': '"production"'
|
|
||||||
}),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
minimize: true
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = rendererConfig
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
process.env.BABEL_ENV = 'web'
|
|
||||||
|
|
||||||
const path = require('path')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
|
|
||||||
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
|
|
||||||
let webConfig = {
|
|
||||||
devtool: '#cheap-module-eval-source-map',
|
|
||||||
entry: {
|
|
||||||
web: path.join(__dirname, '../src/renderer/main.js')
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.(js|vue)$/,
|
|
||||||
enforce: 'pre',
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'eslint-loader',
|
|
||||||
options: {
|
|
||||||
formatter: require('eslint-friendly-formatter')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
use: ExtractTextPlugin.extract({
|
|
||||||
fallback: 'style-loader',
|
|
||||||
use: 'css-loader'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.html$/,
|
|
||||||
use: 'vue-html-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
use: 'babel-loader',
|
|
||||||
include: [ path.resolve(__dirname, '../src/renderer') ],
|
|
||||||
exclude: /node_modules/
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.vue$/,
|
|
||||||
use: {
|
|
||||||
loader: 'vue-loader',
|
|
||||||
options: {
|
|
||||||
extractCSS: true,
|
|
||||||
loaders: {
|
|
||||||
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
|
||||||
scss: 'vue-style-loader!css-loader!sass-loader'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
query: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'imgs/[name].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
|
||||||
use: {
|
|
||||||
loader: 'url-loader',
|
|
||||||
query: {
|
|
||||||
limit: 10000,
|
|
||||||
name: 'fonts/[name].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new ExtractTextPlugin('styles.css'),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
filename: 'index.html',
|
|
||||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
|
||||||
minify: {
|
|
||||||
collapseWhitespace: true,
|
|
||||||
removeAttributeQuotes: true,
|
|
||||||
removeComments: true
|
|
||||||
},
|
|
||||||
nodeModules: false
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.IS_WEB': 'true'
|
|
||||||
}),
|
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
|
||||||
new webpack.NoEmitOnErrorsPlugin()
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
filename: '[name].js',
|
|
||||||
path: path.join(__dirname, '../dist/web')
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@': path.join(__dirname, '../src/renderer'),
|
|
||||||
'vue$': 'vue/dist/vue.esm.js'
|
|
||||||
},
|
|
||||||
extensions: ['.js', '.vue', '.json', '.css']
|
|
||||||
},
|
|
||||||
target: 'web'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjust webConfig for production settings
|
|
||||||
*/
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
webConfig.devtool = ''
|
|
||||||
|
|
||||||
webConfig.plugins.push(
|
|
||||||
new BabiliWebpackPlugin(),
|
|
||||||
new CopyWebpackPlugin([
|
|
||||||
{
|
|
||||||
from: path.join(__dirname, '../static'),
|
|
||||||
to: path.join(__dirname, '../dist/web/static'),
|
|
||||||
ignore: ['.*']
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.NODE_ENV': '"production"'
|
|
||||||
}),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
minimize: true
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = webConfig
|
|
||||||
@@ -1,26 +1,23 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parser: 'babel-eslint',
|
globals: {
|
||||||
parserOptions: {
|
__static: 'readonly'
|
||||||
sourceType: 'module'
|
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
|
||||||
node: true
|
node: true
|
||||||
},
|
},
|
||||||
extends: 'standard',
|
parser: "vue-eslint-parser",
|
||||||
globals: {
|
'extends': [
|
||||||
__static: true
|
'plugin:vue/essential',
|
||||||
},
|
'@vue/standard',
|
||||||
plugins: [
|
'@vue/typescript'
|
||||||
'html'
|
|
||||||
],
|
],
|
||||||
'rules': {
|
'plugins': ['@typescript-eslint'],
|
||||||
// allow paren-less arrow functions
|
rules: {
|
||||||
'arrow-parens': 0,
|
'no-console': process.env.NODE_ENV === 'production' ? 'off' : 'off',
|
||||||
// allow async-await
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||||
'generator-star-spacing': 0,
|
},
|
||||||
// allow debugger during development
|
parserOptions: {
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
|
parser: '@typescript-eslint/parser'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,3 +12,7 @@ thumbs.db
|
|||||||
!.gitkeep
|
!.gitkeep
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
docs/dist/
|
docs/dist/
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
dist_electron/
|
||||||
|
|||||||
@@ -38,15 +38,15 @@ script:
|
|||||||
#- xvfb-maybe node_modules/.bin/karma start test/unit/karma.conf.js
|
#- xvfb-maybe node_modules/.bin/karma start test/unit/karma.conf.js
|
||||||
#- yarn run pack && xvfb-maybe node_modules/.bin/mocha test/e2e
|
#- yarn run pack && xvfb-maybe node_modules/.bin/mocha test/e2e
|
||||||
- npm run release
|
- npm run release
|
||||||
- yarn run build:docs
|
# - yarn run build:docs
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
after_script:
|
# after_script:
|
||||||
- cd docs/dist
|
# - cd docs/dist
|
||||||
- git init
|
# - git init
|
||||||
- git config user.name "Molunerfinn"
|
# - git config user.name "Molunerfinn"
|
||||||
- git config user.email "marksz@teamsz.xyz"
|
# - git config user.email "marksz@teamsz.xyz"
|
||||||
- git add .
|
# - git add .
|
||||||
- git commit -m "Travis build docs"
|
# - git commit -m "Travis build docs"
|
||||||
- git push --force --quiet "https://${GH_TOKEN}@github.com/Molunerfinn/PicGo.git" master:gh-pages
|
# - git push --force --quiet "https://${GH_TOKEN}@github.com/Molunerfinn/PicGo.git" master:gh-pages
|
||||||
|
|||||||
@@ -1,4 +1,25 @@
|
|||||||
{
|
{
|
||||||
"eslint.enable": true,
|
"eslint.enable": true,
|
||||||
"eslint.autoFixOnSave": true
|
"eslint.alwaysShowStatus": true,
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"vue",
|
||||||
|
"typescriptreact"
|
||||||
|
],
|
||||||
|
"[stylus]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"stylusSupremacy.insertSemicolons": false,
|
||||||
|
"stylusSupremacy.insertBraces": false,
|
||||||
|
"stylusSupremacy.insertNewLineBetweenSelectors": true,
|
||||||
|
"stylusSupremacy.insertParenthesisAroundIfCondition": false,
|
||||||
|
"stylusSupremacy.alwaysUseNoneOverZero": true,
|
||||||
|
"stylusSupremacy.alwaysUseZeroWithoutUnit": true,
|
||||||
|
"stylusSupremacy.sortProperties": "grouped",
|
||||||
|
"stylusSupremacy.quoteChar": "\"",
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,86 @@
|
|||||||
|
## :tada: 2.2.1 (2020-01-09)
|
||||||
|
|
||||||
|
|
||||||
|
### :sparkles: Features
|
||||||
|
|
||||||
|
* add alias for plugin config name ([5a06483](https://github.com/Molunerfinn/PicGo/commit/5a06483))
|
||||||
|
* add aliyun oss options ([a33f1ad](https://github.com/Molunerfinn/PicGo/commit/a33f1ad)), closes [#347](https://github.com/Molunerfinn/PicGo/issues/347)
|
||||||
|
* **server:** add http server for uploading images by a http request ([c56d4ef](https://github.com/Molunerfinn/PicGo/commit/c56d4ef))
|
||||||
|
* add server config settings ([6b57cf7](https://github.com/Molunerfinn/PicGo/commit/6b57cf7))
|
||||||
|
* only shows visible pic-beds ([9d4d605](https://github.com/Molunerfinn/PicGo/commit/9d4d605)), closes [#310](https://github.com/Molunerfinn/PicGo/issues/310)
|
||||||
|
|
||||||
|
|
||||||
|
### :bug: Bug Fixes
|
||||||
|
|
||||||
|
* decrease title-bar z-index when config-form dialog shows ([f2750e1](https://github.com/Molunerfinn/PicGo/commit/f2750e1))
|
||||||
|
* **website:** website pictures error ([a5b6526](https://github.com/Molunerfinn/PicGo/commit/a5b6526))
|
||||||
|
* add new tray icon for macOS dark-mode ([c5adf3b](https://github.com/Molunerfinn/PicGo/commit/c5adf3b)), closes [#267](https://github.com/Molunerfinn/PicGo/issues/267)
|
||||||
|
* beforeOpen handler in windows ([cd30a6c](https://github.com/Molunerfinn/PicGo/commit/cd30a6c))
|
||||||
|
* busApi event register first && emit later ([e1a0cbb](https://github.com/Molunerfinn/PicGo/commit/e1a0cbb))
|
||||||
|
* enum type error ([4e3fa28](https://github.com/Molunerfinn/PicGo/commit/4e3fa28))
|
||||||
|
* handle empty request-body ([81e6acb](https://github.com/Molunerfinn/PicGo/commit/81e6acb))
|
||||||
|
* launch error in new structrue ([bc8e641](https://github.com/Molunerfinn/PicGo/commit/bc8e641))
|
||||||
|
* miniWindow minimize bug ([5f2b7c7](https://github.com/Molunerfinn/PicGo/commit/5f2b7c7))
|
||||||
|
* plugin config-form && default plugin logo ([514fc40](https://github.com/Molunerfinn/PicGo/commit/514fc40))
|
||||||
|
* release script ([b4f10c6](https://github.com/Molunerfinn/PicGo/commit/b4f10c6))
|
||||||
|
* removeById handler error ([c4f0a30](https://github.com/Molunerfinn/PicGo/commit/c4f0a30)), closes [#382](https://github.com/Molunerfinn/PicGo/issues/382)
|
||||||
|
* rename page not work ([29a55ed](https://github.com/Molunerfinn/PicGo/commit/29a55ed))
|
||||||
|
* save debug mode && PICGO_ENV into config file ([c6ead5b](https://github.com/Molunerfinn/PicGo/commit/c6ead5b))
|
||||||
|
* server may never start ([73870a5](https://github.com/Molunerfinn/PicGo/commit/73870a5))
|
||||||
|
* settingPage && miniPage style in windows ([3fd9572](https://github.com/Molunerfinn/PicGo/commit/3fd9572))
|
||||||
|
|
||||||
|
|
||||||
|
### :pencil: Documentation
|
||||||
|
|
||||||
|
* add note for windows electron mirror ([46a49ed](https://github.com/Molunerfinn/PicGo/commit/46a49ed))
|
||||||
|
* remove weibo picbed ([e81b8f4](https://github.com/Molunerfinn/PicGo/commit/e81b8f4))
|
||||||
|
* update installation by scoop ([91b397d](https://github.com/Molunerfinn/PicGo/commit/91b397d)), closes [#295](https://github.com/Molunerfinn/PicGo/issues/295)
|
||||||
|
* update readme ([1b3522e](https://github.com/Molunerfinn/PicGo/commit/1b3522e))
|
||||||
|
* update README ([f491209](https://github.com/Molunerfinn/PicGo/commit/f491209))
|
||||||
|
* update site ([fe9e19a](https://github.com/Molunerfinn/PicGo/commit/fe9e19a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# :tada: 2.2.0 (2020-01-01)
|
||||||
|
|
||||||
|
|
||||||
|
### :sparkles: Features
|
||||||
|
|
||||||
|
* add alias for plugin config name ([5a06483](https://github.com/Molunerfinn/PicGo/commit/5a06483))
|
||||||
|
* add aliyun oss options ([a33f1ad](https://github.com/Molunerfinn/PicGo/commit/a33f1ad)), closes [#347](https://github.com/Molunerfinn/PicGo/issues/347)
|
||||||
|
* **server:** add http server for uploading images by a http request ([c56d4ef](https://github.com/Molunerfinn/PicGo/commit/c56d4ef))
|
||||||
|
* add server config settings ([6b57cf7](https://github.com/Molunerfinn/PicGo/commit/6b57cf7))
|
||||||
|
* only shows visible pic-beds ([9d4d605](https://github.com/Molunerfinn/PicGo/commit/9d4d605)), closes [#310](https://github.com/Molunerfinn/PicGo/issues/310)
|
||||||
|
|
||||||
|
|
||||||
|
### :bug: Bug Fixes
|
||||||
|
|
||||||
|
* beforeOpen handler in windows ([cd30a6c](https://github.com/Molunerfinn/PicGo/commit/cd30a6c))
|
||||||
|
* **website:** website pictures error ([a5b6526](https://github.com/Molunerfinn/PicGo/commit/a5b6526))
|
||||||
|
* add new tray icon for macOS dark-mode ([c5adf3b](https://github.com/Molunerfinn/PicGo/commit/c5adf3b)), closes [#267](https://github.com/Molunerfinn/PicGo/issues/267)
|
||||||
|
* busApi event register first && emit later ([e1a0cbb](https://github.com/Molunerfinn/PicGo/commit/e1a0cbb))
|
||||||
|
* decrease title-bar z-index when config-form dialog shows ([f2750e1](https://github.com/Molunerfinn/PicGo/commit/f2750e1))
|
||||||
|
* enum type error ([4e3fa28](https://github.com/Molunerfinn/PicGo/commit/4e3fa28))
|
||||||
|
* handle empty request-body ([81e6acb](https://github.com/Molunerfinn/PicGo/commit/81e6acb))
|
||||||
|
* launch error in new structrue ([bc8e641](https://github.com/Molunerfinn/PicGo/commit/bc8e641))
|
||||||
|
* plugin config-form && default plugin logo ([514fc40](https://github.com/Molunerfinn/PicGo/commit/514fc40))
|
||||||
|
* release script ([b4f10c6](https://github.com/Molunerfinn/PicGo/commit/b4f10c6))
|
||||||
|
* rename page not work ([29a55ed](https://github.com/Molunerfinn/PicGo/commit/29a55ed))
|
||||||
|
* save debug mode && PICGO_ENV into config file ([c6ead5b](https://github.com/Molunerfinn/PicGo/commit/c6ead5b))
|
||||||
|
* settingPage && miniPage style in windows ([3fd9572](https://github.com/Molunerfinn/PicGo/commit/3fd9572))
|
||||||
|
|
||||||
|
|
||||||
|
### :pencil: Documentation
|
||||||
|
|
||||||
|
* add note for windows electron mirror ([46a49ed](https://github.com/Molunerfinn/PicGo/commit/46a49ed))
|
||||||
|
* remove weibo picbed ([e81b8f4](https://github.com/Molunerfinn/PicGo/commit/e81b8f4))
|
||||||
|
* update installation by scoop ([91b397d](https://github.com/Molunerfinn/PicGo/commit/91b397d)), closes [#295](https://github.com/Molunerfinn/PicGo/issues/295)
|
||||||
|
* update readme ([1b3522e](https://github.com/Molunerfinn/PicGo/commit/1b3522e))
|
||||||
|
* update README ([f491209](https://github.com/Molunerfinn/PicGo/commit/f491209))
|
||||||
|
* update site ([fe9e19a](https://github.com/Molunerfinn/PicGo/commit/fe9e19a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## :tada: 2.1.2 (2019-04-19)
|
## :tada: 2.1.2 (2019-04-19)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
The 996ICU License (996ICU)
|
The MIT License (MIT)
|
||||||
Version 0.1, March 2019
|
|
||||||
|
|
||||||
PACKAGE is distributed under LICENSE with the following restriction:
|
Copyright (c) 2017-present, Molunerfinn
|
||||||
|
|
||||||
The above license is only granted to entities that act in concordance
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
with local labor laws. In addition, the following requirements must be
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
observed:
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
* The licencee must not, explicitly or implicitly, request or schedule
|
The above copyright notice and this permission notice shall be included in
|
||||||
their employees to work more than 45 hours in any single week.
|
all copies or substantial portions of the Software.
|
||||||
* The licencee must not, explicitly or implicitly, request or schedule
|
|
||||||
their employees to be at work consecutively for 10 hours.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
# PicGo
|
<div align="center">
|
||||||
|
|
||||||
> 图片上传+管理新体验
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://raw.githubusercontent.com/Molunerfinn/test/master/picgo/New%20LOGO-150.png" alt="">
|
<img src="https://raw.githubusercontent.com/Molunerfinn/test/master/picgo/New%20LOGO-150.png" alt="">
|
||||||
</p>
|
<h1>PicGo</h1>
|
||||||
<p align="center">
|
<blockquote>图片上传+管理新体验 </blockquote>
|
||||||
<a href="https://github.com/feross/standard">
|
<a href="https://github.com/feross/standard">
|
||||||
<img src="https://img.shields.io/badge/code%20style-standard-green.svg?style=flat-square" alt="">
|
<img src="https://img.shields.io/badge/code%20style-standard-green.svg?style=flat-square" alt="">
|
||||||
</a>
|
</a>
|
||||||
@@ -21,45 +17,47 @@
|
|||||||
<a href="https://github.com/PicGo/bump-version">
|
<a href="https://github.com/PicGo/bump-version">
|
||||||
<img src="https://img.shields.io/badge/picgo-convention-blue.svg?style=flat-square" alt="">
|
<img src="https://img.shields.io/badge/picgo-convention-blue.svg?style=flat-square" alt="">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</div>
|
||||||
|
|
||||||
## 应用说明
|
## 应用说明
|
||||||
|
|
||||||
**PicGo在上传图片之后自动会将图片链接复制到你的剪贴板里,可选5种复制的链接格式。**
|
**PicGo 在上传图片之后自动会将图片链接复制到你的剪贴板里,可选 5 种复制的链接格式。**
|
||||||
|
|
||||||
PicGo目前支持了
|
PicGo 目前支持了
|
||||||
|
|
||||||
- `微博图床` v1.0
|
- ~~`微博图床` v1.0~~ **微博图床从 2019 年 4 月开始进行防盗链,不建议继续使用**
|
||||||
- `七牛图床` v1.0
|
- `七牛图床` v1.0
|
||||||
- `腾讯云COS v4\v5版本` v1.1 & v1.5.0
|
- `腾讯云 COS v4\v5版本` v1.1 & v1.5.0
|
||||||
- `又拍云` v1.2.0
|
- `又拍云` v1.2.0
|
||||||
- `GitHub` v1.5.0
|
- `GitHub` v1.5.0
|
||||||
- `SM.MS` v1.5.1
|
- `SM.MS` v1.5.1
|
||||||
- `阿里云OSS` v1.6.0
|
- `阿里云 OSS` v1.6.0
|
||||||
- `Imgur` v1.6.0
|
- `Imgur` v1.6.0
|
||||||
|
|
||||||
**本体不再增加默认的图床支持。你可以自行开发第三方图床插件。详见[PicGo-Core](https://picgo.github.io/PicGo-Core-Doc/)**。
|
**本体不再增加默认的图床支持。你可以自行开发第三方图床插件。详见 [PicGo-Core](https://picgo.github.io/PicGo-Core-Doc/)**。
|
||||||
|
|
||||||
第三方插件以及使用了PicGo底层的应用可以在[Awesome-PicGo](https://github.com/PicGo/Awesome-PicGo)看到。欢迎贡献!
|
第三方插件以及使用了 PicGo 底层的应用可以在 [Awesome-PicGo](https://github.com/PicGo/Awesome-PicGo) 找到。欢迎贡献!
|
||||||
|
|
||||||
支持macOS、windows 64位(>= v1.3.1),linux(>= v1.6.0)。
|
PicGo 支持 macOS、Windows 64位(>= v1.3.1),Linux(>= v1.6.0)。
|
||||||
|
|
||||||
支持快捷键`command+shift+p`(macOS)或者`control+shift+p`(windows\linux)用以支持快捷上传剪贴板里的图片(第一张)。
|
支持快捷键`command+shift+p`(macOS)或者`control+shift+p`(Windows\Linux)用以支持快捷上传剪贴板里的图片(第一张)。
|
||||||
PicGo支持自定义快捷键,使用方法见[配置手册](https://picgo.github.io/PicGo-Doc/zh/guide/config.html)。
|
PicGo 支持自定义快捷键,使用方法见[配置手册](https://picgo.github.io/PicGo-Doc/zh/guide/config.html)。
|
||||||
|
|
||||||
开发进度可以查看[Projects](https://github.com/Molunerfinn/PicGo/projects),会同步更新开发进度。
|
开发进度可以查看 [Projects](https://github.com/Molunerfinn/PicGo/projects),会同步更新开发进度。
|
||||||
|
|
||||||
**如果第一次使用,请参考应用使用[快速上手](https://picgo.github.io/PicGo-Doc/zh/guide/getting-started.html)。遇到问题了还可以看看[FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md)以及被关闭的[issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed)。**
|
**如果第一次使用,请参考应用使用[快速上手](https://picgo.github.io/PicGo-Doc/zh/guide/getting-started.html)。遇到问题了还可以看看 [FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md) 以及被关闭的 [issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed)。**
|
||||||
|
|
||||||
## 下载安装
|
## 下载安装
|
||||||
|
|
||||||
点击此处下载[应用](https://github.com/Molunerfinn/PicGo/releases)。
|
点击此处下载[应用](https://github.com/Molunerfinn/PicGo/releases)。
|
||||||
|
|
||||||
macOS用户请下载最新版本的`dmg`文件,windows用户请下载最新版本的`exe`文件,linux用户请下载`AppImage`文件。
|
macOS 用户请下载最新版本的 `dmg` 文件,Windows 用户请下载最新版本的 `exe` 文件,Linux用户请下载 `AppImage` 文件。
|
||||||
|
|
||||||
**如果你是Arch类的Linux用户,可以直接通过`aurman -S picgo-appimage`来安装PicGo。感谢 @houbaron 的贡献!**
|
**如果你是 Arch 类的 Linux 用户,可以直接通过 `aurman -S picgo-appimage` 来安装 PicGo。感谢 @houbaron 的贡献!**
|
||||||
|
|
||||||
**如果你是macOS用户,可以使用brew cask来安装PicGo: `brew cask install picgo`。感谢 @womeimingzi11 的贡献!**
|
**如果你是 macOS 用户,可以使用 `brew cask` 来安装 PicGo: `brew cask install picgo`。感谢 @womeimingzi11 的贡献!**
|
||||||
|
|
||||||
|
**如果你是 Windows 用户,还可以使用 [Scoop](https://scoop.sh/) 来安装 PicGo: `scoop bucket add helbing https://github.com/helbing/scoop-bucket` & `scoop install picgo`。 感谢 @helbing 的贡献!**
|
||||||
|
|
||||||
## 应用截图
|
## 应用截图
|
||||||
|
|
||||||
@@ -69,20 +67,20 @@ macOS用户请下载最新版本的`dmg`文件,windows用户请下载最新版
|
|||||||
|
|
||||||
## 开发说明
|
## 开发说明
|
||||||
|
|
||||||
> 目前仅针对Mac、Windows。Linux平台并未测试。
|
> 目前仅针对 Mac、Windows。Linux 平台并未测试。
|
||||||
|
|
||||||
如果你想要学习、开发、修改或自行构建PicGo,可以依照下面的指示:
|
如果你想要学习、开发、修改或自行构建 PicGo,可以依照下面的指示:
|
||||||
|
|
||||||
> 如果想学习Electron-vue的开发,可以查看我写的系列教程——[Electron-vue开发实战](https://molunerfinn.com/tags/Electron-vue/)
|
> 如果想学习 Electron-vue 的开发,可以查看我写的系列教程——[Electron-vue 开发实战](https://molunerfinn.com/tags/Electron-vue/)
|
||||||
|
|
||||||
1. 你需要有node、git环境。需要了解npm的相关知识。
|
1. 你需要有 Node、Git环境,了解 npm 的相关知识。
|
||||||
2. `git clone https://github.com/Molunerfinn/PicGo.git` 并进入项目
|
2. `git clone https://github.com/Molunerfinn/PicGo.git` 并进入项目
|
||||||
3. `npm install` 下载依赖
|
3. `npm install` 下载依赖
|
||||||
4. Mac需要有Xcode环境,Windows需要有VS环境。
|
4. Mac 需要有 Xcode 环境,Windows 需要有 VS 环境。
|
||||||
|
|
||||||
### 开发模式
|
### 开发模式
|
||||||
|
|
||||||
输入`npm run dev`进入开发模式,开发模式具有热重载特性。不过需要注意的是,开发模式不稳定,会有进程崩溃的情况。此时需要:
|
输入 `npm run electron:serve` 进入开发模式,开发模式具有热重载特性。不过需要注意的是,开发模式不稳定,会有进程崩溃的情况。此时需要:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ctrl+c # 退出开发模式
|
ctrl+c # 退出开发模式
|
||||||
@@ -91,24 +89,25 @@ npm run dev # 重新进入开发模式
|
|||||||
|
|
||||||
### 生产模式
|
### 生产模式
|
||||||
|
|
||||||
如果你需要自行构建,可以`npm run build`开始进行构建。构建成功后,会在`build`目录里出现构建成功的相应安装文件。
|
如果你需要自行构建,可以 `npm run electron:build` 开始进行构建。构建成功后,会在 `dist_electron` 目录里出现构建成功的相应安装文件。
|
||||||
|
|
||||||
**注意**:如果你的网络环境不太好,可能会出现`electron-builder`下载`electron`二进制文件失败的情况。这个时候需要在`npm run build`之前指定一下`electron`的源为国内源:
|
**注意**:如果你的网络环境不太好,可能会出现 `electron-builder` 下载 `electron` 二进制文件失败的情况。这个时候需要在 `npm run build` 之前指定一下 `electron` 的源为国内源:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/"
|
export ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/"
|
||||||
|
# 在 Windows 上,则可以使用 set ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/ (无需引号)
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
只需第一次构建的时候指定一下国内源即可。后续构建不需要特地指定。二进制文件下载在`~/.electron/`目录下。如果想要更新`electron`构建版本,可以删除`~/.electron/`目录,然后重新运行上一步,让`electron-builder`去下载最新的`electron`二进制文件。
|
只需第一次构建的时候指定一下国内源即可。后续构建不需要特地指定。二进制文件下载在 `~/.electron/` 目录下。如果想要更新 `electron` 构建版本,可以删除 `~/.electron/` 目录,然后重新运行上一步,让 `electron-builder `去下载最新的 `electron` 二进制文件。
|
||||||
|
|
||||||
## 其他相关
|
## 其他相关
|
||||||
|
|
||||||
- [vs-picgo](https://github.com/Spades-S/vs-picgo):picgo的VSCode版。
|
- [vs-picgo](https://github.com/Spades-S/vs-picgo):PicGo 的 VS Code 版。
|
||||||
|
|
||||||
## 赞助
|
## 赞助
|
||||||
|
|
||||||
如果你喜欢PicGo并且它对你确实有帮助,欢迎给我打赏一杯咖啡哈~
|
如果你喜欢 PicGo 并且它对你确实有帮助,欢迎给我打赏一杯咖啡哈~
|
||||||
|
|
||||||
支付宝:
|
支付宝:
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ platform:
|
|||||||
- x64
|
- x64
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
- node_modules
|
|
||||||
- '%APPDATA%\npm-cache'
|
- '%APPDATA%\npm-cache'
|
||||||
- '%USERPROFILE%\.electron'
|
- '%USERPROFILE%\.electron'
|
||||||
- '%USERPROFILE%\AppData\Local\Yarn\cache'
|
- '%USERPROFILE%\AppData\Local\Yarn\cache'
|
||||||
@@ -20,9 +19,9 @@ init:
|
|||||||
- git config --global core.autocrlf input
|
- git config --global core.autocrlf input
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- ps: Install-Product node 8 x64
|
- ps: Install-Product node 12 x64
|
||||||
- git reset --hard HEAD
|
- git reset --hard HEAD
|
||||||
- npm install
|
- yarn
|
||||||
- node --version
|
- node --version
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -13,10 +13,10 @@
|
|||||||
h3.desc
|
h3.desc
|
||||||
| 支持macOS,Windows,Linux
|
| 支持macOS,Windows,Linux
|
||||||
h3.desc
|
h3.desc
|
||||||
| 支持插件系统,让PicGo更强大
|
| 支持#[a(href="https://picgo.github.io/PicGo-Doc/zh/guide/config.html#%E6%8F%92%E4%BB%B6%E8%AE%BE%E7%BD%AE%EF%BC%88v2-0%EF%BC%89" target="_blank") 插件系统],让PicGo更强大
|
||||||
#container.container-fluid
|
#container.container-fluid
|
||||||
.row.ex-width
|
.row.ex-width
|
||||||
img.gallery.col-xs-10.col-xs-offset-1.col-md-offset-2.col-md-8(src="https://ws1.sinaimg.cn/large/8700af19gy1fmayjwttnbj218g0p0q4e")
|
img.gallery.col-xs-10.col-xs-offset-1.col-md-offset-2.col-md-8(src="https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/first.png")
|
||||||
.row.ex-width.display-list
|
.row.ex-width.display-list
|
||||||
.display-list__item(v-for="(item, index) in itemList" :key="index" :class="{ 'o-item': index % 2 !== 0 }")
|
.display-list__item(v-for="(item, index) in itemList" :key="index" :class="{ 'o-item': index % 2 !== 0 }")
|
||||||
.col-xs-10.col-xs-offset-1.col-md-7.col-md-offset-0
|
.col-xs-10.col-xs-offset-1.col-md-7.col-md-offset-0
|
||||||
@@ -37,32 +37,32 @@ export default {
|
|||||||
year: new Date().getFullYear(),
|
year: new Date().getFullYear(),
|
||||||
itemList: [
|
itemList: [
|
||||||
{
|
{
|
||||||
url: 'https://ws1.sinaimg.cn/large/8700af19ly1fma907llb5j20m30ed46a',
|
url: 'https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/second.png',
|
||||||
title: '精致设计',
|
title: '精致设计',
|
||||||
desc: 'macOS系统下,支持拖拽至menubar图标实现上传。menubar app 窗口显示最新上传的5张图片以及剪贴板里的图片。点击图片自动将上传的链接复制到剪贴板。(Windows平台不支持)'
|
desc: 'macOS系统下,支持拖拽至menubar图标实现上传。menubar app 窗口显示最新上传的5张图片以及剪贴板里的图片。点击图片自动将上传的链接复制到剪贴板。(Windows平台不支持)'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: 'https://i.loli.net/2018/07/11/5b45768fb1276.png',
|
url: 'https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/third.png',
|
||||||
title: 'Mini小窗',
|
title: 'Mini小窗',
|
||||||
desc: 'Windows以及Linux系统下提供一个mini悬浮窗用于用户拖拽上传,节约你宝贵的桌面空间。'
|
desc: 'Windows以及Linux系统下提供一个mini悬浮窗用于用户拖拽上传,节约你宝贵的桌面空间。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: 'https://ws1.sinaimg.cn/large/8700af19ly1fmd56zm2nej218g0p0teb',
|
url: 'https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/forth.png',
|
||||||
title: '便捷管理',
|
title: '便捷管理',
|
||||||
desc: '查看你的上传记录,重复使用更方便。支持点击图片大图查看。支持删除图片(仅本地记录),让界面更加干净。'
|
desc: '查看你的上传记录,重复使用更方便。支持点击图片大图查看。支持删除图片(仅本地记录),让界面更加干净。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: 'https://ws1.sinaimg.cn/large/8700af19ly1fmd5ck9m0wj20lr0cxmzs',
|
url: 'https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/fifth.png',
|
||||||
title: '可选图床',
|
title: '可选图床',
|
||||||
desc: '默认支持微博图床、七牛图床、腾讯云COS、又拍云、GitHub、SM.MS、阿里云OSS、Imgur。方便不同图床的上传需求。2.0版本开始更可以自己开发插件实现其他图床的上传需求。'
|
desc: '默认支持微博图床、七牛图床、腾讯云COS、又拍云、GitHub、SM.MS、阿里云OSS、Imgur。方便不同图床的上传需求。2.0版本开始更可以自己开发插件实现其他图床的上传需求。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: 'https://ws1.sinaimg.cn/large/8700af19gy1fmayjwttnbj218g0p0q4e',
|
url: 'https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/sixth.png',
|
||||||
title: '多样链接',
|
title: '多样链接',
|
||||||
desc: '支持5种默认剪贴板链接格式,包括一种自定义格式,让你的文本编辑游刃有余。'
|
desc: '支持5种默认剪贴板链接格式,包括一种自定义格式,让你的文本编辑游刃有余。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: 'https://i.loli.net/2019/01/12/5c39a2f60a32a.png',
|
url: 'https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/seventh.png',
|
||||||
title: '插件系统',
|
title: '插件系统',
|
||||||
desc: '2.0版本开始支持插件系统,让PicGo发挥无限潜能,成为一个极致的效率工具。'
|
desc: '2.0版本开始支持插件系统,让PicGo发挥无限潜能,成为一个极致的效率工具。'
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ h1
|
|||||||
#header
|
#header
|
||||||
height 100vh
|
height 100vh
|
||||||
width 100%
|
width 100%
|
||||||
background-image url("https://ws1.sinaimg.cn/large/8700af19ly1fm9ru6fqvjj22p81stdta")
|
background-image url("https://cdn.jsdelivr.net/gh/Molunerfinn/test/picgo-site/bg.jpeg")
|
||||||
background-attachment fixed
|
background-attachment fixed
|
||||||
background-size cover
|
background-size cover
|
||||||
background-position center
|
background-position center
|
||||||
|
|||||||
@@ -1,35 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "picgo",
|
"name": "picgo",
|
||||||
"version": "2.1.2",
|
"version": "2.2.1",
|
||||||
"author": "Molunerfinn <marksz@teamsz.xyz>",
|
"private": true,
|
||||||
"description": "Easy to upload your pic & copy to write",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "./dist/electron/main.js",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"render": "webpack-dev-server --hot --colors --config .electron-vue/webpack.renderer.config.js --port 9080 --content-base app/dist",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "node .electron-vue/build.js && electron-builder",
|
"build": "vue-cli-service build",
|
||||||
"release": "node .electron-vue/build.js && electron-builder",
|
"lint": "vue-cli-service lint",
|
||||||
"build:dir": "node .electron-vue/build.js && electron-builder --dir",
|
"electron:build": "vue-cli-service electron:build",
|
||||||
"build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js",
|
"electron:serve": "vue-cli-service electron:serve",
|
||||||
"build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js",
|
"postinstall": "electron-builder install-app-deps",
|
||||||
"dev": "node .electron-vue/dev-runner.js",
|
"postuninstall": "electron-builder install-app-deps",
|
||||||
"e2e": "npm run pack && mocha test/e2e",
|
|
||||||
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src test",
|
|
||||||
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src test",
|
|
||||||
"pack": "npm run pack:main && npm run pack:renderer",
|
|
||||||
"pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js",
|
|
||||||
"pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js",
|
|
||||||
"test": "npm run unit && npm run e2e",
|
|
||||||
"unit": "karma start test/unit/karma.conf.js",
|
|
||||||
"postinstall": "npm run lint:fix",
|
|
||||||
"build:docs": "cross-env NODE_ENV=production webpack -p --config .electron-vue/webpack.docs.config.js",
|
|
||||||
"docs": "webpack-dev-server --content-base docs/dist --config .electron-vue/webpack.docs.config.js --hot --inline",
|
|
||||||
"patch": "npm version patch && git push origin master && git push origin --tags",
|
|
||||||
"minor": "npm version minor && git push origin master && git push origin --tags",
|
|
||||||
"major": "npm version major && git push origin master && git push origin --tags",
|
|
||||||
"cz": "git-cz",
|
"cz": "git-cz",
|
||||||
"bump": "bump-version"
|
"bump": "bump-version",
|
||||||
|
"release": "vue-cli-service electron:build --publish always"
|
||||||
},
|
},
|
||||||
|
"main": "background.js",
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||||
@@ -48,138 +33,51 @@
|
|||||||
"./node_modules/@picgo/bump-version/commitlint-picgo"
|
"./node_modules/@picgo/bump-version/commitlint-picgo"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"build": {
|
|
||||||
"productName": "PicGo",
|
|
||||||
"appId": "com.molunerfinn.picgo",
|
|
||||||
"directories": {
|
|
||||||
"output": "build"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"dist/electron/**/*"
|
|
||||||
],
|
|
||||||
"dmg": {
|
|
||||||
"contents": [
|
|
||||||
{
|
|
||||||
"x": 410,
|
|
||||||
"y": 150,
|
|
||||||
"type": "link",
|
|
||||||
"path": "/Applications"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": 130,
|
|
||||||
"y": 150,
|
|
||||||
"type": "file"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mac": {
|
|
||||||
"icon": "build/icons/icon.icns",
|
|
||||||
"extendInfo": {
|
|
||||||
"LSUIElement": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"win": {
|
|
||||||
"icon": "build/icons/icon.ico",
|
|
||||||
"target": "nsis"
|
|
||||||
},
|
|
||||||
"nsis": {
|
|
||||||
"oneClick": false,
|
|
||||||
"allowToChangeInstallationDirectory": true
|
|
||||||
},
|
|
||||||
"linux": {
|
|
||||||
"icon": "build/icons/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.16.1",
|
"axios": "^0.19.0",
|
||||||
"dateformat": "^3.0.3",
|
"core-js": "^3.3.2",
|
||||||
"element-ui": "^2.4.11",
|
"element-ui": "^2.13.0",
|
||||||
"fix-path": "^2.1.0",
|
"fix-path": "^2.1.0",
|
||||||
"fs-extra": "^4.0.2",
|
"fs-extra": "^8.1.0",
|
||||||
"image-size": "^0.6.1",
|
"keycode": "^2.2.0",
|
||||||
"keycode": "^2.1.9",
|
|
||||||
"lodash-id": "^0.14.0",
|
"lodash-id": "^0.14.0",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"md5": "^2.2.1",
|
"picgo": "^1.4.4",
|
||||||
"melody.css": "^1.0.2",
|
"vue": "^2.6.10",
|
||||||
"picgo": "^1.3.5",
|
"vue-gallery": "^2.0.1",
|
||||||
"qiniu": "^7.1.1",
|
|
||||||
"vue": "^2.3.3",
|
|
||||||
"vue-electron": "^1.0.6",
|
|
||||||
"vue-gallery": "^1.2.4",
|
|
||||||
"vue-lazyload": "^1.2.6",
|
"vue-lazyload": "^1.2.6",
|
||||||
"vue-router": "^2.5.3",
|
"vue-router": "^3.1.3"
|
||||||
"vuex": "^2.3.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^7.5.2",
|
"@commitlint/cli": "^8.2.0",
|
||||||
"@picgo/bump-version": "^1.0.2",
|
"@picgo/bump-version": "^1.0.3",
|
||||||
"babel-core": "^6.25.0",
|
"@types/fs-extra": "^8.0.1",
|
||||||
"babel-eslint": "^7.2.3",
|
"@types/inquirer": "^6.5.0",
|
||||||
"babel-loader": "^7.1.1",
|
"@types/lowdb": "^1.0.9",
|
||||||
"babel-plugin-istanbul": "^4.1.1",
|
"@types/node": "10.17.6",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"@types/request-promise-native": "^1.0.17",
|
||||||
"babel-preset-env": "^1.6.0",
|
"@vue/cli-plugin-babel": "^4.0.0",
|
||||||
"babel-preset-stage-0": "^6.24.1",
|
"@vue/cli-plugin-eslint": "^4.0.0",
|
||||||
"babel-register": "^6.24.1",
|
"@vue/cli-plugin-router": "^4.0.0",
|
||||||
"babili-webpack-plugin": "^0.1.2",
|
"@vue/cli-plugin-typescript": "^4.0.0",
|
||||||
"cfonts": "^1.1.3",
|
"@vue/cli-service": "^4.0.0",
|
||||||
"chai": "^4.0.0",
|
"@vue/eslint-config-standard": "^4.0.0",
|
||||||
"chalk": "^2.1.0",
|
"@vue/eslint-config-typescript": "^4.0.0",
|
||||||
"commitizen": "^3.0.7",
|
"commitizen": "^4.0.3",
|
||||||
"conventional-changelog": "^3.0.6",
|
"conventional-changelog": "^3.1.18",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"cz-customizable": "^6.2.0",
|
||||||
"cross-env": "^5.0.5",
|
"electron": "^6.0.0",
|
||||||
"css-loader": "^0.28.4",
|
"eslint": "^5.16.0",
|
||||||
"cz-customizable": "^5.10.0",
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
"del": "^3.0.0",
|
"husky": "^3.1.0",
|
||||||
"devtron": "^1.4.0",
|
"stylus": "^0.54.7",
|
||||||
"electron": "4.0.2",
|
"stylus-loader": "^3.0.2",
|
||||||
"electron-builder": "^20.38.4",
|
"typescript": "~3.7.3",
|
||||||
"electron-debug": "^1.4.0",
|
"vue-cli-plugin-electron-builder": "^1.4.2",
|
||||||
"electron-devtools-installer": "^2.2.0",
|
"vue-property-decorator": "^8.3.0",
|
||||||
"eslint": "^4.4.1",
|
"vue-template-compiler": "^2.6.10"
|
||||||
"eslint-config-standard": "^10.2.1",
|
},
|
||||||
"eslint-friendly-formatter": "^3.0.0",
|
"resolutions": {
|
||||||
"eslint-loader": "^2.1.1",
|
"@types/node": "12.0.2"
|
||||||
"eslint-plugin-html": "^3.1.1",
|
|
||||||
"eslint-plugin-import": "^2.7.0",
|
|
||||||
"eslint-plugin-node": "^5.1.1",
|
|
||||||
"eslint-plugin-promise": "^3.5.0",
|
|
||||||
"eslint-plugin-standard": "^3.0.1",
|
|
||||||
"file-loader": "^3.0.1",
|
|
||||||
"html-webpack-plugin": "^3.2.0",
|
|
||||||
"husky": "^1.3.1",
|
|
||||||
"inject-loader": "^3.0.0",
|
|
||||||
"karma": "^1.3.0",
|
|
||||||
"karma-chai": "^0.1.0",
|
|
||||||
"karma-coverage": "^1.1.1",
|
|
||||||
"karma-electron": "^5.1.1",
|
|
||||||
"karma-mocha": "^1.2.0",
|
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
|
||||||
"karma-spec-reporter": "^0.0.31",
|
|
||||||
"karma-webpack": "^2.0.1",
|
|
||||||
"mini-css-extract-plugin": "0.4.0",
|
|
||||||
"mocha": "^3.0.2",
|
|
||||||
"multispinner": "^0.2.1",
|
|
||||||
"node-loader": "^0.6.0",
|
|
||||||
"pug": "^2.0.0-rc.4",
|
|
||||||
"pug-loader": "^2.3.0",
|
|
||||||
"pug-plain-loader": "^1.0.0",
|
|
||||||
"require-dir": "^0.3.0",
|
|
||||||
"spectron": "^3.7.1",
|
|
||||||
"style-loader": "^0.23.1",
|
|
||||||
"stylus": "^0.54.5",
|
|
||||||
"stylus-loader": "^3.0.1",
|
|
||||||
"url-loader": "^1.1.2",
|
|
||||||
"vue-html-loader": "^1.2.4",
|
|
||||||
"vue-loader": "^15.4.2",
|
|
||||||
"vue-style-loader": "^4.1.2",
|
|
||||||
"vue-template-compiler": "^2.4.2",
|
|
||||||
"webpack": "^4.15.1",
|
|
||||||
"webpack-cli": "^3.0.8",
|
|
||||||
"webpack-dev-server": "^3.1.4",
|
|
||||||
"webpack-hot-middleware": "^2.22.2",
|
|
||||||
"webpack-merge": "^4.1.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="referrer" content="never">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title>PicGo</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but picgo-new doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 497 B After Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 915 B After Width: | Height: | Size: 915 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 823 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 777 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
param($imagePath)
|
||||||
|
|
||||||
|
# Adapted from https://github.com/octan3/img-clipboard-dump/blob/master/dump-clipboard-png.ps1
|
||||||
|
|
||||||
|
Add-Type -Assembly PresentationCore
|
||||||
|
$img = [Windows.Clipboard]::GetImage()
|
||||||
|
|
||||||
|
if ($img -eq $null) {
|
||||||
|
"no image"
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $imagePath) {
|
||||||
|
"no image"
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$fcb = new-object Windows.Media.Imaging.FormatConvertedBitmap($img, [Windows.Media.PixelFormats]::Rgb24, $null, 0)
|
||||||
|
$stream = [IO.File]::Open($imagePath, "OpenOrCreate")
|
||||||
|
$encoder = New-Object Windows.Media.Imaging.PngBitmapEncoder
|
||||||
|
$encoder.Frames.Add([Windows.Media.Imaging.BitmapFrame]::Create($fcb)) | out-null
|
||||||
|
$encoder.Save($stream) | out-null
|
||||||
|
$stream.Dispose() | out-null
|
||||||
|
|
||||||
|
$imagePath
|
||||||
@@ -0,0 +1,612 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
import {
|
||||||
|
app,
|
||||||
|
BrowserWindow,
|
||||||
|
Tray,
|
||||||
|
Menu,
|
||||||
|
Notification,
|
||||||
|
clipboard,
|
||||||
|
ipcMain,
|
||||||
|
globalShortcut,
|
||||||
|
dialog,
|
||||||
|
systemPreferences,
|
||||||
|
WebContents,
|
||||||
|
IpcMainEvent,
|
||||||
|
protocol
|
||||||
|
} from 'electron'
|
||||||
|
import {
|
||||||
|
createProtocol,
|
||||||
|
installVueDevtools
|
||||||
|
} from 'vue-cli-plugin-electron-builder/lib'
|
||||||
|
import db from '#/datastore'
|
||||||
|
import picgo from '~/main/apis/picgo'
|
||||||
|
import uploader from '~/main/apis/uploader'
|
||||||
|
import beforeOpen from '~/main/utils/beforeOpen'
|
||||||
|
import pasteTemplate from '#/utils/pasteTemplate'
|
||||||
|
import updateChecker from '~/main/utils/updateChecker'
|
||||||
|
import getPicBeds from '~/main/utils/getPicBeds'
|
||||||
|
import pkg from 'root/package.json'
|
||||||
|
import picgoCoreIPC from '~/main/utils/picgoCoreIPC'
|
||||||
|
import fixPath from 'fix-path'
|
||||||
|
import { getUploadFiles } from '~/main/utils/handleArgv'
|
||||||
|
import bus from '~/main/utils/eventBus'
|
||||||
|
import {
|
||||||
|
updateShortKeyFromVersion212
|
||||||
|
} from '~/main/migrate'
|
||||||
|
import shortKeyHandler from '~/main/apis/shortKey/shortKeyHandler'
|
||||||
|
import logger from '~/main/utils/logger'
|
||||||
|
import {
|
||||||
|
UPLOAD_WITH_FILES,
|
||||||
|
UPLOAD_WITH_FILES_RESPONSE,
|
||||||
|
UPLOAD_WITH_CLIPBOARD_FILES,
|
||||||
|
UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE,
|
||||||
|
GET_WINDOW_ID,
|
||||||
|
GET_WINDOW_ID_REPONSE,
|
||||||
|
GET_SETTING_WINDOW_ID,
|
||||||
|
GET_SETTING_WINDOW_ID_RESPONSE,
|
||||||
|
CREATE_APP_MENU
|
||||||
|
} from '~/main/apis/bus/constants'
|
||||||
|
import server from '~/main/server/index'
|
||||||
|
import { IWindowList } from '~/main/apis/window/constants'
|
||||||
|
import windowManager from '~/main/apis/window/windowManager'
|
||||||
|
|
||||||
|
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||||
|
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
|
||||||
|
|
||||||
|
beforeOpen()
|
||||||
|
|
||||||
|
let tray: Tray | null
|
||||||
|
let menu: Menu | null
|
||||||
|
let contextMenu: Menu | null
|
||||||
|
const winURL = isDevelopment
|
||||||
|
? (process.env.WEBPACK_DEV_SERVER_URL as string)
|
||||||
|
: `picgo://./index.html`
|
||||||
|
const settingWinURL = isDevelopment
|
||||||
|
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#setting/upload`
|
||||||
|
: `picgo://./index.html#setting/upload`
|
||||||
|
const miniWinURL = isDevelopment
|
||||||
|
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#mini-page`
|
||||||
|
: `picgo://./index.html#mini-page`
|
||||||
|
|
||||||
|
// fix the $PATH in macOS
|
||||||
|
fixPath()
|
||||||
|
|
||||||
|
function createContextMenu () {
|
||||||
|
const picBeds = getPicBeds()
|
||||||
|
const submenu = picBeds.filter(item => item.visible).map(item => {
|
||||||
|
return {
|
||||||
|
label: item.name,
|
||||||
|
type: 'radio',
|
||||||
|
checked: db.get('picBed.current') === item.type,
|
||||||
|
click () {
|
||||||
|
picgo.saveConfig({
|
||||||
|
'picBed.current': item.type
|
||||||
|
})
|
||||||
|
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
contextMenu = Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: '关于',
|
||||||
|
click () {
|
||||||
|
dialog.showMessageBox({
|
||||||
|
title: 'PicGo',
|
||||||
|
message: 'PicGo',
|
||||||
|
detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '打开详细窗口',
|
||||||
|
click () {
|
||||||
|
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
|
||||||
|
settingWindow!.show()
|
||||||
|
settingWindow!.focus()
|
||||||
|
if (windowManager.has(IWindowList.MINI_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '选择默认图床',
|
||||||
|
type: 'submenu',
|
||||||
|
// @ts-ignore
|
||||||
|
submenu
|
||||||
|
},
|
||||||
|
// @ts-ignore
|
||||||
|
{
|
||||||
|
label: '打开更新助手',
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: db.get('settings.showUpdateTip'),
|
||||||
|
click () {
|
||||||
|
const value = db.get('settings.showUpdateTip')
|
||||||
|
db.set('settings.showUpdateTip', !value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '重启应用',
|
||||||
|
click () {
|
||||||
|
app.relaunch()
|
||||||
|
app.exit(0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// @ts-ignore
|
||||||
|
{
|
||||||
|
role: 'quit',
|
||||||
|
label: '退出'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTray () {
|
||||||
|
const menubarPic = process.platform === 'darwin' ? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png`
|
||||||
|
tray = new Tray(menubarPic)
|
||||||
|
tray.on('right-click', () => {
|
||||||
|
if (windowManager.has(IWindowList.TRAY_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
|
||||||
|
}
|
||||||
|
createContextMenu()
|
||||||
|
tray!.popUpContextMenu(contextMenu!)
|
||||||
|
})
|
||||||
|
tray.on('click', (event, bounds) => {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
toggleWindow(bounds)
|
||||||
|
setTimeout(() => {
|
||||||
|
let img = clipboard.readImage()
|
||||||
|
let obj: ImgInfo[] = []
|
||||||
|
if (!img.isEmpty()) {
|
||||||
|
// 从剪贴板来的图片默认转为png
|
||||||
|
// @ts-ignore
|
||||||
|
const imgUrl = 'data:image/png;base64,' + Buffer.from(img.toPNG(), 'binary').toString('base64')
|
||||||
|
obj.push({
|
||||||
|
width: img.getSize().width,
|
||||||
|
height: img.getSize().height,
|
||||||
|
imgUrl
|
||||||
|
})
|
||||||
|
}
|
||||||
|
windowManager.get(IWindowList.TRAY_WINDOW)!.webContents.send('clipboardFiles', obj)
|
||||||
|
}, 0)
|
||||||
|
} else {
|
||||||
|
if (windowManager.has(IWindowList.TRAY_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
|
||||||
|
}
|
||||||
|
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
|
||||||
|
settingWindow!.show()
|
||||||
|
settingWindow!.focus()
|
||||||
|
if (windowManager.has(IWindowList.MINI_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
tray.on('drag-enter', () => {
|
||||||
|
if (systemPreferences.isDarkMode()) {
|
||||||
|
tray!.setImage(`${__static}/upload-dark.png`)
|
||||||
|
} else {
|
||||||
|
tray!.setImage(`${__static}/upload.png`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
tray.on('drag-end', () => {
|
||||||
|
tray!.setImage(`${__static}/menubar.png`)
|
||||||
|
})
|
||||||
|
|
||||||
|
tray.on('drop-files', async (event: Event, files: string[]) => {
|
||||||
|
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||||
|
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||||
|
const imgs = await uploader
|
||||||
|
.setWebContents(trayWindow.webContents)
|
||||||
|
.upload(files)
|
||||||
|
if (imgs !== false) {
|
||||||
|
for (let i = 0; i < imgs.length; i++) {
|
||||||
|
clipboard.writeText(pasteTemplate(pasteStyle, imgs[i]))
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '上传成功',
|
||||||
|
body: imgs[i].imgUrl!,
|
||||||
|
icon: files[i]
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.show()
|
||||||
|
}, i * 100)
|
||||||
|
db.insert('uploaded', imgs[i])
|
||||||
|
}
|
||||||
|
trayWindow.webContents.send('dragFiles', imgs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// toggleWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
const createMenu = () => {
|
||||||
|
if (process.env.NODE_ENV !== 'development') {
|
||||||
|
const template = [{
|
||||||
|
label: 'Edit',
|
||||||
|
submenu: [
|
||||||
|
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
|
||||||
|
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
|
||||||
|
{ type: 'separator' },
|
||||||
|
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
|
||||||
|
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
|
||||||
|
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
|
||||||
|
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' },
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
accelerator: 'CmdOrCtrl+Q',
|
||||||
|
click () {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
// @ts-ignore
|
||||||
|
menu = Menu.buildFromTemplate(template)
|
||||||
|
Menu.setApplicationMenu(menu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleWindow = (bounds: IBounds) => {
|
||||||
|
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||||
|
if (trayWindow.isVisible()) {
|
||||||
|
trayWindow.hide()
|
||||||
|
} else {
|
||||||
|
trayWindow.setPosition(bounds.x - 98 + 11, bounds.y, false)
|
||||||
|
trayWindow.webContents.send('updateFiles')
|
||||||
|
trayWindow.show()
|
||||||
|
trayWindow.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadClipboardFiles = async (): Promise<string> => {
|
||||||
|
const win = windowManager.getAvailableWindow()
|
||||||
|
let img = await uploader.setWebContents(win!.webContents).upload()
|
||||||
|
if (img !== false) {
|
||||||
|
if (img.length > 0) {
|
||||||
|
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||||
|
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||||
|
clipboard.writeText(pasteTemplate(pasteStyle, img[0]))
|
||||||
|
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)
|
||||||
|
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
|
||||||
|
}
|
||||||
|
return img[0].imgUrl as string
|
||||||
|
} else {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '上传不成功',
|
||||||
|
body: '你剪贴板最新的一条记录不是图片哦'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadChoosedFiles = async (webContents: WebContents, files: IFileWithPath[]): Promise<string[]> => {
|
||||||
|
const input = files.map(item => item.path)
|
||||||
|
const imgs = await uploader.setWebContents(webContents).upload(input)
|
||||||
|
const result = []
|
||||||
|
if (imgs !== false) {
|
||||||
|
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||||
|
let pasteText = ''
|
||||||
|
for (let i = 0; i < imgs.length; i++) {
|
||||||
|
pasteText += pasteTemplate(pasteStyle, imgs[i]) + '\r\n'
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '上传成功',
|
||||||
|
body: imgs[i].imgUrl!,
|
||||||
|
icon: files[i].path
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.show()
|
||||||
|
}, i * 100)
|
||||||
|
db.insert('uploaded', imgs[i])
|
||||||
|
result.push(imgs[i].imgUrl!)
|
||||||
|
}
|
||||||
|
clipboard.writeText(pasteText)
|
||||||
|
windowManager.get(IWindowList.TRAY_WINDOW)!.webContents.send('uploadFiles', imgs)
|
||||||
|
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
picgoCoreIPC()
|
||||||
|
|
||||||
|
// from macOS tray
|
||||||
|
ipcMain.on('uploadClipboardFiles', async () => {
|
||||||
|
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
|
||||||
|
const img = await uploader.setWebContents(trayWindow.webContents).upload()
|
||||||
|
if (img !== false) {
|
||||||
|
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||||
|
clipboard.writeText(pasteTemplate(pasteStyle, img[0]))
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '上传成功',
|
||||||
|
body: img[0].imgUrl!,
|
||||||
|
// icon: file[0]
|
||||||
|
icon: img[0].imgUrl
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
db.insert('uploaded', img[0])
|
||||||
|
trayWindow.webContents.send('clipboardFiles', [])
|
||||||
|
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trayWindow.webContents.send('uploadFiles')
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('uploadClipboardFilesFromUploadPage', () => {
|
||||||
|
uploadClipboardFiles()
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('uploadChoosedFiles', async (evt: IpcMainEvent, files: IFileWithPath[]) => {
|
||||||
|
return uploadChoosedFiles(evt.sender, files)
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('updateShortKey', (evt: IpcMainEvent, item: IShortKeyConfig, oldKey: string, from: string) => {
|
||||||
|
const result = shortKeyHandler.updateShortKey(item, oldKey, from)
|
||||||
|
evt.sender.send('updateShortKeyResponse', result)
|
||||||
|
if (result) {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '操作成功',
|
||||||
|
body: '你的快捷键已经修改成功'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
} else {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '操作失败',
|
||||||
|
body: '快捷键冲突,请重新设置'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('bindOrUnbindShortKey', (evt: IpcMainEvent, item: IShortKeyConfig, from: string) => {
|
||||||
|
const result = shortKeyHandler.bindOrUnbindShortKey(item, from)
|
||||||
|
if (result) {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '操作成功',
|
||||||
|
body: '你的快捷键已经修改成功'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
} else {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '操作失败',
|
||||||
|
body: '快捷键冲突,请重新设置'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('updateCustomLink', () => {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '操作成功',
|
||||||
|
body: '你的自定义链接格式已经修改成功'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('autoStart', (evt: IpcMainEvent, val: boolean) => {
|
||||||
|
app.setLoginItemSettings({
|
||||||
|
openAtLogin: val
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('openSettingWindow', () => {
|
||||||
|
windowManager.get(IWindowList.SETTING_WINDOW)!.show()
|
||||||
|
if (windowManager.has(IWindowList.MINI_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('openMiniWindow', () => {
|
||||||
|
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
|
||||||
|
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
|
miniWindow.show()
|
||||||
|
miniWindow.focus()
|
||||||
|
settingWindow.hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
// from mini window
|
||||||
|
ipcMain.on('syncPicBed', () => {
|
||||||
|
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
|
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('getPicBeds', (evt: IpcMainEvent) => {
|
||||||
|
const picBeds = getPicBeds()
|
||||||
|
evt.sender.send('getPicBeds', picBeds)
|
||||||
|
evt.returnValue = picBeds
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('toggleShortKeyModifiedMode', (evt: IpcMainEvent, val: boolean) => {
|
||||||
|
bus.emit('toggleShortKeyModifiedMode', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('updateServer', () => {
|
||||||
|
server.restart()
|
||||||
|
})
|
||||||
|
|
||||||
|
const gotTheLock = app.requestSingleInstanceLock()
|
||||||
|
|
||||||
|
if (!gotTheLock) {
|
||||||
|
app.quit()
|
||||||
|
} else {
|
||||||
|
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 {
|
||||||
|
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
|
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
|
if (settingWindow.isMinimized()) {
|
||||||
|
settingWindow.restore()
|
||||||
|
}
|
||||||
|
settingWindow.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
app.setAppUserModelId('com.molunerfinn.picgo')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.XDG_CURRENT_DESKTOP && process.env.XDG_CURRENT_DESKTOP.includes('Unity')) {
|
||||||
|
process.env.XDG_CURRENT_DESKTOP = 'Unity'
|
||||||
|
}
|
||||||
|
|
||||||
|
app.on('ready', async () => {
|
||||||
|
createProtocol('picgo')
|
||||||
|
if (isDevelopment && !process.env.IS_TEST) {
|
||||||
|
// Install Vue Devtools
|
||||||
|
try {
|
||||||
|
await installVueDevtools()
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Vue Devtools failed to install:', e.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
windowManager.create(IWindowList.TRAY_WINDOW)
|
||||||
|
windowManager.create(IWindowList.SETTING_WINDOW)
|
||||||
|
if (process.platform === 'darwin' || process.platform === 'win32') {
|
||||||
|
createTray()
|
||||||
|
}
|
||||||
|
db.set('needReload', false)
|
||||||
|
updateChecker()
|
||||||
|
initEventCenter()
|
||||||
|
// 不需要阻塞
|
||||||
|
process.nextTick(() => {
|
||||||
|
updateShortKeyFromVersion212(db, db.get('settings.shortKey'))
|
||||||
|
shortKeyHandler.init()
|
||||||
|
})
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
createProtocol('picgo')
|
||||||
|
if (!windowManager.has(IWindowList.TRAY_WINDOW)) {
|
||||||
|
windowManager.create(IWindowList.TRAY_WINDOW)
|
||||||
|
}
|
||||||
|
if (!windowManager.has(IWindowList.SETTING_WINDOW)) {
|
||||||
|
windowManager.create(IWindowList.SETTING_WINDOW)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('will-quit', () => {
|
||||||
|
globalShortcut.unregisterAll()
|
||||||
|
bus.removeAllListeners()
|
||||||
|
server.shutdown()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.setLoginItemSettings({
|
||||||
|
openAtLogin: db.get('settings.autoStart') || false
|
||||||
|
})
|
||||||
|
|
||||||
|
function initEventCenter () {
|
||||||
|
const eventList: any = {
|
||||||
|
'picgo:upload': uploadClipboardFiles,
|
||||||
|
[UPLOAD_WITH_CLIPBOARD_FILES]: busCallUploadClipboardFiles,
|
||||||
|
[UPLOAD_WITH_FILES]: busCallUploadFiles,
|
||||||
|
[GET_WINDOW_ID]: busCallGetWindowId,
|
||||||
|
[GET_SETTING_WINDOW_ID]: busCallGetSettingWindowId,
|
||||||
|
[CREATE_APP_MENU]: createMenu
|
||||||
|
}
|
||||||
|
for (let i in eventList) {
|
||||||
|
bus.on(i, eventList[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function busCallUploadClipboardFiles () {
|
||||||
|
const imgUrl = await uploadClipboardFiles()
|
||||||
|
bus.emit(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, imgUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function busCallUploadFiles (pathList: IFileWithPath[]) {
|
||||||
|
const win = windowManager.getAvailableWindow()
|
||||||
|
const urls = await uploadChoosedFiles(win.webContents, pathList)
|
||||||
|
bus.emit(UPLOAD_WITH_FILES_RESPONSE, urls)
|
||||||
|
}
|
||||||
|
|
||||||
|
function busCallGetWindowId () {
|
||||||
|
const win = windowManager.getAvailableWindow()
|
||||||
|
bus.emit(GET_WINDOW_ID_REPONSE, win.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function busCallGetSettingWindowId () {
|
||||||
|
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
|
||||||
|
bus.emit(GET_SETTING_WINDOW_ID_RESPONSE, settingWindow.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit cleanly on request from parent process in development mode.
|
||||||
|
if (isDevelopment) {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
process.on('message', data => {
|
||||||
|
if (data === 'graceful-exit') {
|
||||||
|
app.quit()
|
||||||
|
server.shutdown()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
app.quit()
|
||||||
|
server.shutdown()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto Updater
|
||||||
|
*
|
||||||
|
* Uncomment the following code below and install `electron-updater` to
|
||||||
|
* support auto updating. Code Signing with a valid certificate is required.
|
||||||
|
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
|
||||||
|
*/
|
||||||
|
|
||||||
|
// import { autoUpdater } from 'electron-updater'
|
||||||
|
|
||||||
|
// autoUpdater.on('update-downloaded', () => {
|
||||||
|
// autoUpdater.quitAndInstall()
|
||||||
|
// })
|
||||||
|
|
||||||
|
// app.on('ready', () => {
|
||||||
|
// if (process.env.NODE_ENV === 'production') {
|
||||||
|
// autoUpdater.checkForUpdates()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import Datastore from 'lowdb'
|
|
||||||
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'
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'development') {
|
|
||||||
global.__static = path.join(__dirname, '/static').replace(/\\/g, '\\\\')
|
|
||||||
}
|
|
||||||
if (process.env.DEBUG_ENV === 'debug') {
|
|
||||||
global.__static = path.join(__dirname, '../../static').replace(/\\/g, '\\\\')
|
|
||||||
}
|
|
||||||
|
|
||||||
const APP = process.type === 'renderer' ? remote.app : app
|
|
||||||
const STORE_PATH = APP.getPath('userData')
|
|
||||||
|
|
||||||
if (process.type !== 'renderer') {
|
|
||||||
if (!fs.pathExistsSync(STORE_PATH)) {
|
|
||||||
fs.mkdirpSync(STORE_PATH)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const adapter = new FileSync(path.join(STORE_PATH, '/data.json'))
|
|
||||||
|
|
||||||
const db = Datastore(adapter)
|
|
||||||
db._.mixin(LodashId)
|
|
||||||
|
|
||||||
if (!db.has('uploaded').value()) {
|
|
||||||
db.set('uploaded', []).write()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!db.has('picBed').value()) {
|
|
||||||
db.set('picBed', {
|
|
||||||
current: 'weibo'
|
|
||||||
}).write()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!db.has('settings.shortKey').value()) {
|
|
||||||
db.set('settings.shortKey', {
|
|
||||||
upload: 'CommandOrControl+Shift+P'
|
|
||||||
}).write()
|
|
||||||
}
|
|
||||||
|
|
||||||
// init generate clipboard image files
|
|
||||||
let clipboardFiles = getClipboardFiles()
|
|
||||||
if (!fs.pathExistsSync(path.join(STORE_PATH, 'windows.ps1'))) {
|
|
||||||
clipboardFiles.forEach(item => {
|
|
||||||
fs.copyFileSync(item.origin, item.dest)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
clipboardFiles.forEach(item => {
|
|
||||||
diffFilesAndUpdate(item.origin, item.dest)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function diffFilesAndUpdate (filePath1, filePath2) {
|
|
||||||
let file1 = fs.readFileSync(filePath1)
|
|
||||||
let file2 = fs.readFileSync(filePath2)
|
|
||||||
|
|
||||||
if (!file1.equals(file2)) {
|
|
||||||
fs.copyFileSync(filePath1, filePath2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getClipboardFiles () {
|
|
||||||
let files = [
|
|
||||||
'/linux.sh',
|
|
||||||
'/mac.applescript',
|
|
||||||
'/windows.ps1'
|
|
||||||
]
|
|
||||||
|
|
||||||
return files.map(item => {
|
|
||||||
return {
|
|
||||||
origin: path.join(__static, item),
|
|
||||||
dest: path.join(STORE_PATH, item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default db
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import db from './index'
|
|
||||||
|
|
||||||
let picBed = [
|
|
||||||
{
|
|
||||||
type: 'weibo',
|
|
||||||
name: '微博图床',
|
|
||||||
visible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'qiniu',
|
|
||||||
name: '七牛图床',
|
|
||||||
visible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'tcyun',
|
|
||||||
name: '腾讯云COS',
|
|
||||||
visible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'upyun',
|
|
||||||
name: '又拍云图床',
|
|
||||||
visible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'github',
|
|
||||||
name: 'GitHub图床',
|
|
||||||
visible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'smms',
|
|
||||||
name: 'SM.MS图床',
|
|
||||||
visible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'aliyun',
|
|
||||||
name: '阿里云OSS',
|
|
||||||
visible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'imgur',
|
|
||||||
name: 'Imgur图床',
|
|
||||||
visible: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
let picBedFromDB = db.read().get('picBed.list').value() || []
|
|
||||||
let oldLength = picBedFromDB.length
|
|
||||||
let newLength = picBed.length
|
|
||||||
|
|
||||||
if (oldLength !== newLength) {
|
|
||||||
for (let i = oldLength; i < newLength; i++) {
|
|
||||||
picBedFromDB.push(picBed[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default picBedFromDB
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="referrer" content="never">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
||||||
<title>PicGo</title>
|
|
||||||
<% if (htmlWebpackPlugin.options.nodeModules) { %>
|
|
||||||
<!-- Add `node_modules/` to global paths so `require` works properly in development -->
|
|
||||||
<script>
|
|
||||||
require('module').globalPaths.push("<%= htmlWebpackPlugin.options.nodeModules.replace(/\\/g, '\\\\') %>")
|
|
||||||
</script>
|
|
||||||
<% } %>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
<!-- Set `__static` path to static files in production -->
|
|
||||||
<script>
|
|
||||||
if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- webpack builds are automatically injected -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,24 +1,18 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import axios from 'axios'
|
import App from './renderer/App.vue'
|
||||||
|
import router from './renderer/router'
|
||||||
|
import db from '#/datastore/index'
|
||||||
import ElementUI from 'element-ui'
|
import ElementUI from 'element-ui'
|
||||||
import 'element-ui/lib/theme-chalk/index.css'
|
|
||||||
import App from './App'
|
|
||||||
import router from './router'
|
|
||||||
import store from './store'
|
|
||||||
import db from '../datastore/index'
|
|
||||||
import { webFrame } from 'electron'
|
import { webFrame } from 'electron'
|
||||||
import './assets/fonts/iconfont.css'
|
import 'element-ui/lib/theme-chalk/index.css'
|
||||||
import VueLazyLoad from 'vue-lazyload'
|
import VueLazyLoad from 'vue-lazyload'
|
||||||
|
import axios from 'axios'
|
||||||
Vue.use(ElementUI)
|
import mainMixin from './renderer/utils/mainMixin'
|
||||||
Vue.use(VueLazyLoad)
|
|
||||||
|
|
||||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
webFrame.setVisualZoomLevelLimits(1, 1)
|
||||||
webFrame.setLayoutZoomLevelLimits(0, 0)
|
webFrame.setLayoutZoomLevelLimits(0, 0)
|
||||||
|
|
||||||
if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
|
Vue.config.productionTip = false
|
||||||
Vue.http = Vue.prototype.$http = axios
|
|
||||||
Vue.prototype.$db = db
|
|
||||||
Vue.prototype.$builtInPicBed = [
|
Vue.prototype.$builtInPicBed = [
|
||||||
'smms',
|
'smms',
|
||||||
'weibo',
|
'weibo',
|
||||||
@@ -29,12 +23,14 @@ Vue.prototype.$builtInPicBed = [
|
|||||||
'aliyun',
|
'aliyun',
|
||||||
'github'
|
'github'
|
||||||
]
|
]
|
||||||
Vue.config.productionTip = false
|
Vue.prototype.$db = db
|
||||||
|
Vue.prototype.$http = axios
|
||||||
|
|
||||||
|
Vue.use(ElementUI)
|
||||||
|
Vue.use(VueLazyLoad)
|
||||||
|
Vue.mixin(mainMixin)
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
|
||||||
new Vue({
|
new Vue({
|
||||||
components: { App },
|
|
||||||
router,
|
router,
|
||||||
store,
|
render: h => h(App)
|
||||||
template: '<App/>'
|
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export const GET_WINDOW_ID = 'GET_WINDOW_ID' // get a current window
|
||||||
|
export const GET_WINDOW_ID_REPONSE = 'GET_WINDOW_ID_REPONSE'
|
||||||
|
export const GET_SETTING_WINDOW_ID = 'GET_SETTING_WINDOW_ID' // get setting window
|
||||||
|
export const GET_SETTING_WINDOW_ID_RESPONSE = 'GET_SETTING_WINDOW_ID_RESPONSE'
|
||||||
|
export const UPLOAD_WITH_FILES = 'UPLOAD_WITH_FILES'
|
||||||
|
export const UPLOAD_WITH_FILES_RESPONSE = 'UPLOAD_WITH_FILES_RESPONSE'
|
||||||
|
export const UPLOAD_WITH_CLIPBOARD_FILES = 'UPLOAD_WITH_CLIPBOARD_FILES'
|
||||||
|
export const UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE = 'UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE'
|
||||||
|
export const CREATE_APP_MENU = 'CREATE_APP_MENU'
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import bus from '../../utils/eventBus'
|
||||||
|
import {
|
||||||
|
UPLOAD_WITH_FILES,
|
||||||
|
UPLOAD_WITH_FILES_RESPONSE,
|
||||||
|
UPLOAD_WITH_CLIPBOARD_FILES,
|
||||||
|
UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE,
|
||||||
|
GET_WINDOW_ID,
|
||||||
|
GET_WINDOW_ID_REPONSE,
|
||||||
|
GET_SETTING_WINDOW_ID,
|
||||||
|
GET_SETTING_WINDOW_ID_RESPONSE
|
||||||
|
} from './constants'
|
||||||
|
|
||||||
|
export const uploadWithClipboardFiles = (): Promise<{
|
||||||
|
success: boolean,
|
||||||
|
result?: string[]
|
||||||
|
}> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bus.once(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, (result: string) => {
|
||||||
|
if (result) {
|
||||||
|
return resolve({
|
||||||
|
success: true,
|
||||||
|
result: [result]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return resolve({
|
||||||
|
success: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
bus.emit(UPLOAD_WITH_CLIPBOARD_FILES)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uploadWithFiles = (pathList: IFileWithPath[]): Promise<{
|
||||||
|
success: boolean,
|
||||||
|
result?: string[]
|
||||||
|
}> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bus.once(UPLOAD_WITH_FILES_RESPONSE, (result: string[]) => {
|
||||||
|
if (result.length) {
|
||||||
|
return resolve({
|
||||||
|
success: true,
|
||||||
|
result
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return resolve({
|
||||||
|
success: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
bus.emit(UPLOAD_WITH_FILES, pathList)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// get available window id:
|
||||||
|
// miniWindow or settingWindow or trayWindow
|
||||||
|
export const getWindowId = (): Promise<number> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bus.once(GET_WINDOW_ID_REPONSE, (id: number) => {
|
||||||
|
resolve(id)
|
||||||
|
})
|
||||||
|
bus.emit(GET_WINDOW_ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// get settingWindow id:
|
||||||
|
export const getSettingWindowId = (): Promise<number> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bus.once(GET_SETTING_WINDOW_ID_RESPONSE, (id: number) => {
|
||||||
|
resolve(id)
|
||||||
|
})
|
||||||
|
bus.emit(GET_SETTING_WINDOW_ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import {
|
||||||
|
dialog,
|
||||||
|
BrowserWindow,
|
||||||
|
clipboard,
|
||||||
|
Notification,
|
||||||
|
WebContents,
|
||||||
|
ipcMain,
|
||||||
|
webContents
|
||||||
|
} from 'electron'
|
||||||
|
import db from '#/datastore'
|
||||||
|
import uploader from '../uploader'
|
||||||
|
import pasteTemplate from '#/utils/pasteTemplate'
|
||||||
|
import {
|
||||||
|
getWindowId,
|
||||||
|
getSettingWindowId
|
||||||
|
} from '~/main/apis/bus'
|
||||||
|
|
||||||
|
class GuiApi implements IGuiApi {
|
||||||
|
private windowId: number = -1
|
||||||
|
private settingWindowId: number = -1
|
||||||
|
private async showSettingWindow () {
|
||||||
|
this.settingWindowId = await getSettingWindowId()
|
||||||
|
const settingWindow = BrowserWindow.fromId(this.settingWindowId)
|
||||||
|
if (settingWindow.isVisible()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
settingWindow.show()
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve()
|
||||||
|
}, 1000) // TODO: a better way to wait page loaded.
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private getWebcontentsByWindowId (id: number) {
|
||||||
|
return BrowserWindow.fromId(id).webContents
|
||||||
|
}
|
||||||
|
|
||||||
|
async showInputBox (options: IShowInputBoxOption = {
|
||||||
|
title: '',
|
||||||
|
placeholder: ''
|
||||||
|
}) {
|
||||||
|
await this.showSettingWindow()
|
||||||
|
this.getWebcontentsByWindowId(this.settingWindowId)
|
||||||
|
.send('showInputBox', options)
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
ipcMain.once('showInputBox', (event: Event, value: string) => {
|
||||||
|
resolve(value)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
showFileExplorer (options: IShowFileExplorerOption = {}) {
|
||||||
|
return new Promise<string>(async (resolve, reject) => {
|
||||||
|
this.windowId = await getWindowId()
|
||||||
|
dialog.showOpenDialog(BrowserWindow.fromId(this.windowId), options, (filename: string) => {
|
||||||
|
resolve(filename)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async upload (input: IUploadOption) {
|
||||||
|
this.windowId = await getWindowId()
|
||||||
|
const webContents = this.getWebcontentsByWindowId(this.windowId)
|
||||||
|
const imgs = await uploader.setWebContents(webContents).upload(input)
|
||||||
|
if (imgs !== false) {
|
||||||
|
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
|
||||||
|
let pasteText = ''
|
||||||
|
for (let i = 0; i < imgs.length; i++) {
|
||||||
|
pasteText += pasteTemplate(pasteStyle, imgs[i]) + '\r\n'
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '上传成功',
|
||||||
|
body: imgs[i].imgUrl as string,
|
||||||
|
icon: imgs[i].imgUrl
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.show()
|
||||||
|
}, i * 100)
|
||||||
|
db.insert('uploaded', imgs[i])
|
||||||
|
}
|
||||||
|
clipboard.writeText(pasteText)
|
||||||
|
webContents.send('uploadFiles', imgs)
|
||||||
|
webContents.send('updateGallery')
|
||||||
|
return imgs
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
showNotification (options: IShowNotificationOption = {
|
||||||
|
title: '',
|
||||||
|
body: ''
|
||||||
|
}) {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: options.title,
|
||||||
|
body: options.body
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
showMessageBox (options: IShowMessageBoxOption = {
|
||||||
|
title: '',
|
||||||
|
message: '',
|
||||||
|
type: 'info',
|
||||||
|
buttons: ['Yes', 'No']
|
||||||
|
}) {
|
||||||
|
return new Promise<IShowMessageBoxResult>(async (resolve, reject) => {
|
||||||
|
this.windowId = await getWindowId()
|
||||||
|
dialog.showMessageBox(
|
||||||
|
BrowserWindow.fromId(this.windowId),
|
||||||
|
options
|
||||||
|
).then((res) => {
|
||||||
|
resolve({
|
||||||
|
result: res.response,
|
||||||
|
checkboxChecked: res.checkboxChecked
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GuiApi
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import PicGoCore from '~/universal/types/picgo'
|
||||||
|
import {
|
||||||
|
app
|
||||||
|
} from 'electron'
|
||||||
|
import path from 'path'
|
||||||
|
// 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 picgo = new PicGo(CONFIG_PATH)
|
||||||
|
picgo.saveConfig({
|
||||||
|
debug: true,
|
||||||
|
PICGO_ENV: 'GUI'
|
||||||
|
})
|
||||||
|
|
||||||
|
export default picgo as PicGoCore
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import bus from '../../utils/eventBus'
|
||||||
|
import PicGoCore from '~/universal/types/picgo'
|
||||||
|
import path from 'path'
|
||||||
|
import {
|
||||||
|
app,
|
||||||
|
globalShortcut,
|
||||||
|
BrowserWindow
|
||||||
|
} from 'electron'
|
||||||
|
import logger from '../../utils/logger'
|
||||||
|
import GuiApi from '../gui'
|
||||||
|
import db from '#/datastore'
|
||||||
|
import shortKeyService from './shortKeyService'
|
||||||
|
import picgo from '../picgo'
|
||||||
|
|
||||||
|
class ShortKeyHandler {
|
||||||
|
private isInModifiedMode: boolean = false
|
||||||
|
constructor () {
|
||||||
|
bus.on('toggleShortKeyModifiedMode', flag => {
|
||||||
|
this.isInModifiedMode = flag
|
||||||
|
})
|
||||||
|
}
|
||||||
|
init () {
|
||||||
|
this.initBuiltInShortKey()
|
||||||
|
this.initPluginsShortKey()
|
||||||
|
}
|
||||||
|
private initBuiltInShortKey () {
|
||||||
|
const commands = db.get('settings.shortKey') as IShortKeyConfigs
|
||||||
|
Object.keys(commands)
|
||||||
|
.filter(item => item.includes('picgo:'))
|
||||||
|
.map(command => {
|
||||||
|
const config = commands[command]
|
||||||
|
globalShortcut.register(config.key, () => {
|
||||||
|
this.handler(command)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
private initPluginsShortKey () {
|
||||||
|
const pluginList = picgo.pluginLoader.getList()
|
||||||
|
for (let item of pluginList) {
|
||||||
|
const plugin = picgo.pluginLoader.getPlugin(item)
|
||||||
|
// if a plugin has commands
|
||||||
|
if (plugin && plugin.commands) {
|
||||||
|
if (typeof plugin.commands !== 'function') {
|
||||||
|
logger.warn(`${item}'s commands is not a function`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const commands = plugin.commands(picgo) as IPluginShortKeyConfig[]
|
||||||
|
for (let cmd of commands) {
|
||||||
|
const command = `${item}:${cmd.name}`
|
||||||
|
if (db.has(`settings.shortKey[${command}]`)) {
|
||||||
|
const commandConfig = db.get(`settings.shortKey.${command}`) as IShortKeyConfig
|
||||||
|
this.registerShortKey(commandConfig, command, cmd.handle, false)
|
||||||
|
} else {
|
||||||
|
this.registerShortKey(cmd, command, cmd.handle, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private registerShortKey (config: IShortKeyConfig | IPluginShortKeyConfig, command: string, handler: IShortKeyHandler, writeFlag: boolean) {
|
||||||
|
shortKeyService.registerCommand(command, handler)
|
||||||
|
if (config.key) {
|
||||||
|
globalShortcut.register(config.key, () => {
|
||||||
|
this.handler(command)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.warn(`${command} do not provide a key to bind`)
|
||||||
|
}
|
||||||
|
if (writeFlag) {
|
||||||
|
picgo.saveConfig({
|
||||||
|
[`settings.shortKey.${command}`]: {
|
||||||
|
enable: true,
|
||||||
|
name: config.name,
|
||||||
|
label: config.label,
|
||||||
|
key: config.key
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// enable or disable shortKey
|
||||||
|
bindOrUnbindShortKey (item: IShortKeyConfig, from: string): boolean {
|
||||||
|
const command = `${from}:${item.name}`
|
||||||
|
if (item.enable === false) {
|
||||||
|
globalShortcut.unregister(item.key)
|
||||||
|
picgo.saveConfig({
|
||||||
|
[`settings.shortKey.${command}.enable`]: false
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
if (globalShortcut.isRegistered(item.key)) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
picgo.saveConfig({
|
||||||
|
[`settings.shortKey.${command}.enable`]: true
|
||||||
|
})
|
||||||
|
globalShortcut.register(item.key, () => {
|
||||||
|
this.handler(command)
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update shortKey bindings
|
||||||
|
updateShortKey (item: IShortKeyConfig, oldKey: string, from: string): boolean {
|
||||||
|
const command = `${from}:${item.name}`
|
||||||
|
if (globalShortcut.isRegistered(item.key)) return false
|
||||||
|
globalShortcut.unregister(oldKey)
|
||||||
|
picgo.saveConfig({
|
||||||
|
[`settings.shortKey.${command}.key`]: item.key
|
||||||
|
})
|
||||||
|
globalShortcut.register(item.key, () => {
|
||||||
|
this.handler(`${from}:${item.name}`)
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
private async handler (command: string) {
|
||||||
|
if (this.isInModifiedMode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (command.includes('picgo:')) {
|
||||||
|
bus.emit(command)
|
||||||
|
} else if (command.includes('picgo-plugin-')) {
|
||||||
|
const handler = shortKeyService.getShortKeyHandler(command)
|
||||||
|
if (handler) {
|
||||||
|
const guiApi = new GuiApi()
|
||||||
|
return handler(picgo, guiApi)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn(`can not find command: ${command}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registerPluginShortKey (pluginName: string) {
|
||||||
|
const plugin = picgo.pluginLoader.getPlugin(pluginName)
|
||||||
|
if (plugin && plugin.commands) {
|
||||||
|
if (typeof plugin.commands !== 'function') {
|
||||||
|
logger.warn(`${pluginName}'s commands is not a function`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const commands = plugin.commands(picgo) as IPluginShortKeyConfig[]
|
||||||
|
for (let cmd of commands) {
|
||||||
|
const command = `${pluginName}:${cmd.name}`
|
||||||
|
if (db.has(`settings.shortKey[${command}]`)) {
|
||||||
|
const commandConfig = db.get(`settings.shortKey[${command}]`) as IShortKeyConfig
|
||||||
|
this.registerShortKey(commandConfig, command, cmd.handle, false)
|
||||||
|
} else {
|
||||||
|
this.registerShortKey(cmd, command, cmd.handle, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unregisterPluginShortKey (pluginName: string) {
|
||||||
|
const commands = db.get('settings.shortKey') as IShortKeyConfigs
|
||||||
|
const keyList = Object.keys(commands)
|
||||||
|
.filter(command => command.includes(pluginName))
|
||||||
|
.map(command => {
|
||||||
|
return {
|
||||||
|
command,
|
||||||
|
key: commands[command].key
|
||||||
|
}
|
||||||
|
}) as IKeyCommandType[]
|
||||||
|
keyList.forEach(item => {
|
||||||
|
globalShortcut.unregister(item.key)
|
||||||
|
shortKeyService.unregisterCommand(item.command)
|
||||||
|
picgo.unsetConfig('settings.shortKey', item.command)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new ShortKeyHandler()
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import logger from '../../utils/logger'
|
||||||
|
class ShortKeyService {
|
||||||
|
private commandList: Map<string, IShortKeyHandler> = new Map()
|
||||||
|
registerCommand (command: string, handler: IShortKeyHandler) {
|
||||||
|
this.commandList.set(command, handler)
|
||||||
|
}
|
||||||
|
unregisterCommand (command: string) {
|
||||||
|
this.commandList.delete(command)
|
||||||
|
}
|
||||||
|
getShortKeyHandler (command: string): IShortKeyHandler | null {
|
||||||
|
const handler = this.commandList.get(command)
|
||||||
|
if (handler) return handler
|
||||||
|
logger.warn(`cannot find command: ${command}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
getCommandList () {
|
||||||
|
return [...this.commandList.keys()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new ShortKeyService()
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import {
|
||||||
|
app,
|
||||||
|
Notification,
|
||||||
|
BrowserWindow,
|
||||||
|
ipcMain,
|
||||||
|
WebContents
|
||||||
|
} from 'electron'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import picgo from '~/main/apis/picgo'
|
||||||
|
import db from '#/datastore'
|
||||||
|
import windowManager from '~/main/apis/window/windowManager'
|
||||||
|
import { IWindowList } from '~/main/apis/window/constants'
|
||||||
|
|
||||||
|
const waitForShow = (webcontent: WebContents) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
webcontent.on('did-finish-load', () => {
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const windowId = window.id
|
||||||
|
ipcMain.once(`rename${id}`, (evt: Event, newName: string) => {
|
||||||
|
resolve(newName)
|
||||||
|
window.close()
|
||||||
|
})
|
||||||
|
window.on('close', () => {
|
||||||
|
resolve(null)
|
||||||
|
ipcMain.removeAllListeners(`rename${id}`)
|
||||||
|
windowManager.deleteById(windowId)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
class Uploader {
|
||||||
|
private webContents: WebContents | null = null
|
||||||
|
constructor () {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
init () {
|
||||||
|
picgo.on('notification', message => {
|
||||||
|
const notification = new Notification(message)
|
||||||
|
notification.show()
|
||||||
|
})
|
||||||
|
|
||||||
|
picgo.on('uploadProgress', progress => {
|
||||||
|
this.webContents?.send('uploadProgress', progress)
|
||||||
|
})
|
||||||
|
picgo.on('beforeTransform', ctx => {
|
||||||
|
if (db.get('settings.uploadNotification')) {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '上传进度',
|
||||||
|
body: '正在上传'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
picgo.helper.beforeUploadPlugins.register('renameFn', {
|
||||||
|
handle: async ctx => {
|
||||||
|
const rename = db.get('settings.rename')
|
||||||
|
const autoRename = db.get('settings.autoRename')
|
||||||
|
await Promise.all(ctx.output.map(async (item, index) => {
|
||||||
|
let name: undefined | string | null
|
||||||
|
let fileName: string | undefined
|
||||||
|
if (autoRename) {
|
||||||
|
fileName = dayjs().add(index, 'second').format('YYYYMMDDHHmmss') + item.extname
|
||||||
|
} else {
|
||||||
|
fileName = item.fileName
|
||||||
|
}
|
||||||
|
if (rename) {
|
||||||
|
const window = windowManager.create(IWindowList.RENAME_WINDOW)!
|
||||||
|
await waitForShow(window.webContents)
|
||||||
|
window.webContents.send('rename', fileName, window.webContents.id)
|
||||||
|
name = await waitForRename(window, window.webContents.id)
|
||||||
|
}
|
||||||
|
item.fileName = name || fileName
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setWebContents (webContents: WebContents) {
|
||||||
|
this.webContents = webContents
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
upload (img?: IUploadOption): Promise<ImgInfo[]|false> {
|
||||||
|
picgo.upload(img)
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
picgo.once('finished', ctx => {
|
||||||
|
if (ctx.output.every((item: ImgInfo) => item.imgUrl)) {
|
||||||
|
resolve(ctx.output)
|
||||||
|
} else {
|
||||||
|
resolve(false)
|
||||||
|
}
|
||||||
|
picgo.removeAllListeners('failed')
|
||||||
|
})
|
||||||
|
picgo.once('failed', ctx => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: '上传失败',
|
||||||
|
body: '请检查配置和上传的文件是否符合要求'
|
||||||
|
})
|
||||||
|
notification.show()
|
||||||
|
}, 500)
|
||||||
|
picgo.removeAllListeners('finished')
|
||||||
|
resolve(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Uploader()
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
export enum IWindowList {
|
||||||
|
SETTING_WINDOW = 'SETTING_WINDOW',
|
||||||
|
TRAY_WINDOW = 'TRAY_WINDOW',
|
||||||
|
MINI_WINDOW = 'MINI_WINDOW',
|
||||||
|
RENAME_WINDOW = 'RENAME_WINDOW'
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||||
|
|
||||||
|
export const TRAY_WINDOW_URL = isDevelopment
|
||||||
|
? (process.env.WEBPACK_DEV_SERVER_URL as string)
|
||||||
|
: `picgo://./index.html`
|
||||||
|
|
||||||
|
export const SETTING_WINDOW_URL = isDevelopment
|
||||||
|
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#setting/upload`
|
||||||
|
: `picgo://./index.html#setting/upload`
|
||||||
|
|
||||||
|
export const MINI_WINDOW_URL = isDevelopment
|
||||||
|
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#mini-page`
|
||||||
|
: `picgo://./index.html#mini-page`
|
||||||
|
|
||||||
|
export const RENAME_WINDOW_URL = process.env.NODE_ENV === 'development'
|
||||||
|
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#rename-page`
|
||||||
|
: `picgo://./index.html#rename-page`
|
||||||
|
|
||||||
|
export const DELETE_WINDOW_EVENT = 'DELETE_WINDOW_EVENT'
|
||||||
|
export const CREATE_WINDOW_EVENT = 'CREATE_WINDOW_EVENT'
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
import {
|
||||||
|
IWindowList,
|
||||||
|
DELETE_WINDOW_EVENT,
|
||||||
|
CREATE_WINDOW_EVENT,
|
||||||
|
SETTING_WINDOW_URL,
|
||||||
|
TRAY_WINDOW_URL,
|
||||||
|
MINI_WINDOW_URL,
|
||||||
|
RENAME_WINDOW_URL
|
||||||
|
} from './constants'
|
||||||
|
import { IWindowListItem } from '#/types/electron'
|
||||||
|
import bus from '~/main/utils/eventBus'
|
||||||
|
import db from '#/datastore'
|
||||||
|
import { getWindowId } from '~/main/apis/bus'
|
||||||
|
import { BrowserWindow, app } from 'electron'
|
||||||
|
import { CREATE_APP_MENU } from '~/main/apis/bus/constants'
|
||||||
|
|
||||||
|
const windowList = new Map<IWindowList, IWindowListItem>()
|
||||||
|
|
||||||
|
windowList.set(IWindowList.TRAY_WINDOW, {
|
||||||
|
isValid: process.platform !== 'linux',
|
||||||
|
multiple: false,
|
||||||
|
options () {
|
||||||
|
return {
|
||||||
|
height: 350,
|
||||||
|
width: 196, // 196
|
||||||
|
show: false,
|
||||||
|
frame: false,
|
||||||
|
fullscreenable: false,
|
||||||
|
resizable: false,
|
||||||
|
transparent: true,
|
||||||
|
vibrancy: 'ultra-dark',
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
nodeIntegrationInWorker: true,
|
||||||
|
backgroundThrottling: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback (window) {
|
||||||
|
const id = window!.id
|
||||||
|
window!.loadURL(TRAY_WINDOW_URL)
|
||||||
|
window!.on('closed', () => {
|
||||||
|
bus.emit(DELETE_WINDOW_EVENT, id)
|
||||||
|
})
|
||||||
|
|
||||||
|
window!.on('blur', () => {
|
||||||
|
window!.hide()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
windowList.set(IWindowList.SETTING_WINDOW, {
|
||||||
|
isValid: true,
|
||||||
|
multiple: false,
|
||||||
|
options () {
|
||||||
|
const options: IBrowserWindowOptions = {
|
||||||
|
height: 450,
|
||||||
|
width: 800,
|
||||||
|
show: false,
|
||||||
|
frame: true,
|
||||||
|
center: true,
|
||||||
|
fullscreenable: false,
|
||||||
|
resizable: false,
|
||||||
|
title: 'PicGo',
|
||||||
|
vibrancy: 'ultra-dark',
|
||||||
|
transparent: true,
|
||||||
|
titleBarStyle: 'hidden',
|
||||||
|
webPreferences: {
|
||||||
|
backgroundThrottling: false,
|
||||||
|
nodeIntegration: true,
|
||||||
|
nodeIntegrationInWorker: true,
|
||||||
|
webSecurity: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
options.show = false
|
||||||
|
options.frame = false
|
||||||
|
options.backgroundColor = '#3f3c37'
|
||||||
|
options.transparent = false
|
||||||
|
options.icon = `${__static}/logo.png`
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
},
|
||||||
|
callback (window) {
|
||||||
|
const id = window!.id
|
||||||
|
window!.loadURL(SETTING_WINDOW_URL)
|
||||||
|
window!.on('closed', () => {
|
||||||
|
bus.emit('toggleShortKeyModifiedMode', false)
|
||||||
|
bus.emit(DELETE_WINDOW_EVENT, id)
|
||||||
|
if (process.platform === 'linux') {
|
||||||
|
process.nextTick(() => {
|
||||||
|
app.quit()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
bus.emit(CREATE_APP_MENU)
|
||||||
|
bus.emit(CREATE_WINDOW_EVENT, IWindowList.MINI_WINDOW)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
windowList.set(IWindowList.MINI_WINDOW, {
|
||||||
|
isValid: process.platform !== 'darwin',
|
||||||
|
multiple: false,
|
||||||
|
options () {
|
||||||
|
let obj: IBrowserWindowOptions = {
|
||||||
|
height: 64,
|
||||||
|
width: 64,
|
||||||
|
show: process.platform === 'linux',
|
||||||
|
frame: false,
|
||||||
|
fullscreenable: false,
|
||||||
|
skipTaskbar: true,
|
||||||
|
resizable: false,
|
||||||
|
transparent: process.platform !== 'linux',
|
||||||
|
icon: `${__static}/logo.png`,
|
||||||
|
webPreferences: {
|
||||||
|
backgroundThrottling: false,
|
||||||
|
nodeIntegration: true,
|
||||||
|
nodeIntegrationInWorker: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (db.get('settings.miniWindowOntop')) {
|
||||||
|
obj.alwaysOnTop = true
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
},
|
||||||
|
callback (window) {
|
||||||
|
const id = window!.id
|
||||||
|
window!.loadURL(MINI_WINDOW_URL)
|
||||||
|
window!.on('closed', () => {
|
||||||
|
bus.emit(DELETE_WINDOW_EVENT, id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
windowList.set(IWindowList.RENAME_WINDOW, {
|
||||||
|
isValid: true,
|
||||||
|
multiple: true,
|
||||||
|
options () {
|
||||||
|
let options: IBrowserWindowOptions = {
|
||||||
|
height: 175,
|
||||||
|
width: 300,
|
||||||
|
show: true,
|
||||||
|
fullscreenable: false,
|
||||||
|
resizable: false,
|
||||||
|
vibrancy: 'ultra-dark',
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
nodeIntegrationInWorker: true,
|
||||||
|
backgroundThrottling: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
options.show = true
|
||||||
|
options.backgroundColor = '#3f3c37'
|
||||||
|
options.autoHideMenuBar = true
|
||||||
|
options.transparent = false
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
},
|
||||||
|
async callback (window) {
|
||||||
|
window!.loadURL(RENAME_WINDOW_URL)
|
||||||
|
const currentWindowId = await getWindowId()
|
||||||
|
const currentWindow = BrowserWindow.fromId(currentWindowId)
|
||||||
|
if (currentWindow && currentWindow.isVisible()) {
|
||||||
|
// bounds: { x: 821, y: 75, width: 800, height: 450 }
|
||||||
|
const bounds = currentWindow.getBounds()
|
||||||
|
const positionX = bounds.x + bounds.width / 2 - 150
|
||||||
|
let positionY
|
||||||
|
// if is the settingWindow
|
||||||
|
if (bounds.height > 400) {
|
||||||
|
positionY = bounds.y + bounds.height / 2 - 88
|
||||||
|
} else { // if is the miniWindow
|
||||||
|
positionY = bounds.y + bounds.height / 2
|
||||||
|
}
|
||||||
|
window!.setPosition(positionX, positionY, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default windowList
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import {
|
||||||
|
BrowserWindow
|
||||||
|
} from 'electron'
|
||||||
|
import { IWindowManager, IWindowListItem } from '#/types/electron'
|
||||||
|
import windowList from './windowList'
|
||||||
|
import {
|
||||||
|
IWindowList,
|
||||||
|
DELETE_WINDOW_EVENT,
|
||||||
|
CREATE_WINDOW_EVENT
|
||||||
|
} from './constants'
|
||||||
|
import bus from '~/main/utils/eventBus'
|
||||||
|
|
||||||
|
class WindowManager implements IWindowManager {
|
||||||
|
private windowMap: Map<IWindowList | string, BrowserWindow> = new Map()
|
||||||
|
private windowIdMap: Map<number, IWindowList | string> = new Map()
|
||||||
|
constructor () {
|
||||||
|
bus.on(DELETE_WINDOW_EVENT, this.deleteById)
|
||||||
|
bus.on(CREATE_WINDOW_EVENT, this.create)
|
||||||
|
}
|
||||||
|
create = (name: IWindowList) => {
|
||||||
|
const windowConfig: IWindowListItem = windowList.get(name)!
|
||||||
|
if (windowConfig.isValid) {
|
||||||
|
if (!windowConfig.multiple) {
|
||||||
|
if (this.windowMap.has(name)) return this.windowMap.get(name)!
|
||||||
|
}
|
||||||
|
const window = new BrowserWindow(windowConfig.options())
|
||||||
|
if (windowConfig.multiple) {
|
||||||
|
this.windowMap.set(`${name}_${window.id}`, window)
|
||||||
|
this.windowIdMap.set(window.id, `${name}_${window.id}`)
|
||||||
|
} else {
|
||||||
|
this.windowMap.set(name, window)
|
||||||
|
this.windowIdMap.set(window.id, name)
|
||||||
|
}
|
||||||
|
windowConfig.callback(window)
|
||||||
|
return window
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get (name: IWindowList) {
|
||||||
|
if (this.windowMap.has(name)) {
|
||||||
|
return this.windowMap.get(name)!
|
||||||
|
} else {
|
||||||
|
const window = this.create(name)
|
||||||
|
return window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has (name: IWindowList) {
|
||||||
|
return this.windowMap.has(name)
|
||||||
|
}
|
||||||
|
delete = (name: IWindowList) => {
|
||||||
|
const window = this.windowMap.get(name)
|
||||||
|
if (window) {
|
||||||
|
this.windowIdMap.delete(window.id)
|
||||||
|
this.windowMap.delete(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deleteById = (id: number) => {
|
||||||
|
const name = this.windowIdMap.get(id)
|
||||||
|
if (name) {
|
||||||
|
this.windowMap.delete(name)
|
||||||
|
this.windowIdMap.delete(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getAvailableWindow () {
|
||||||
|
const miniWindow = this.windowMap.get(IWindowList.MINI_WINDOW)
|
||||||
|
if (miniWindow && miniWindow.isVisible()) {
|
||||||
|
return miniWindow
|
||||||
|
} else {
|
||||||
|
const settingWindow = this.windowMap.get(IWindowList.SETTING_WINDOW)
|
||||||
|
const trayWindow = this.windowMap.get(IWindowList.TRAY_WINDOW)
|
||||||
|
return settingWindow || trayWindow || this.create(IWindowList.SETTING_WINDOW)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new WindowManager()
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/**
|
|
||||||
* This file is used specifically and only for development. It installs
|
|
||||||
* `electron-debug` & `vue-devtools`. There shouldn't be any need to
|
|
||||||
* modify this file, but it can be used to extend your development
|
|
||||||
* environment.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
// Install `electron-debug` with `devtron`
|
|
||||||
require('electron-debug')({ showDevTools: false })
|
|
||||||
|
|
||||||
// Install `vue-devtools`
|
|
||||||
require('electron').app.on('ready', () => {
|
|
||||||
let installExtension = require('electron-devtools-installer')
|
|
||||||
installExtension.default(installExtension.VUEJS_DEVTOOLS)
|
|
||||||
.then(() => {})
|
|
||||||
.catch(err => {
|
|
||||||
console.log('Unable to install `vue-devtools`: \n', err)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Require `main` process to boot app
|
|
||||||
require('./index')
|
|
||||||
@@ -1,598 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
import Uploader from './utils/uploader.js'
|
|
||||||
import { app, BrowserWindow, Tray, Menu, Notification, clipboard, ipcMain, globalShortcut, dialog } from 'electron'
|
|
||||||
import db from '../datastore'
|
|
||||||
import beforeOpen from './utils/beforeOpen'
|
|
||||||
import pasteTemplate from './utils/pasteTemplate'
|
|
||||||
import updateChecker from './utils/updateChecker'
|
|
||||||
import { getPicBeds } from './utils/getPicBeds'
|
|
||||||
import pkg from '../../package.json'
|
|
||||||
import picgoCoreIPC from './utils/picgoCoreIPC'
|
|
||||||
import fixPath from 'fix-path'
|
|
||||||
import { getUploadFiles } from './utils/handleArgv'
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
beforeOpen()
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Set `__static` path to static files in production
|
|
||||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
|
|
||||||
*/
|
|
||||||
if (process.env.NODE_ENV !== 'development') {
|
|
||||||
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
|
|
||||||
}
|
|
||||||
if (process.env.DEBUG_ENV === 'debug') {
|
|
||||||
global.__static = require('path').join(__dirname, '../../static').replace(/\\/g, '\\\\')
|
|
||||||
}
|
|
||||||
|
|
||||||
let window
|
|
||||||
let settingWindow
|
|
||||||
let miniWindow
|
|
||||||
let tray
|
|
||||||
let menu
|
|
||||||
let contextMenu
|
|
||||||
const winURL = process.env.NODE_ENV === 'development'
|
|
||||||
? `http://localhost:9080`
|
|
||||||
: `file://${__dirname}/index.html`
|
|
||||||
const settingWinURL = process.env.NODE_ENV === 'development'
|
|
||||||
? `http://localhost:9080/#setting/upload`
|
|
||||||
: `file://${__dirname}/index.html#setting/upload`
|
|
||||||
const miniWinURL = process.env.NODE_ENV === 'development'
|
|
||||||
? `http://localhost:9080/#mini-page`
|
|
||||||
: `file://${__dirname}/index.html#mini-page`
|
|
||||||
|
|
||||||
// fix the $PATH in macOS
|
|
||||||
fixPath()
|
|
||||||
|
|
||||||
function createContextMenu () {
|
|
||||||
const picBeds = getPicBeds(app)
|
|
||||||
const submenu = picBeds.map(item => {
|
|
||||||
return {
|
|
||||||
label: item.name,
|
|
||||||
type: 'radio',
|
|
||||||
checked: db.read().get('picBed.current').value() === item.type,
|
|
||||||
click () {
|
|
||||||
db.read().set('picBed.current', item.type).write()
|
|
||||||
if (settingWindow) {
|
|
||||||
settingWindow.webContents.send('syncPicBed')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
contextMenu = Menu.buildFromTemplate([
|
|
||||||
{
|
|
||||||
label: '关于',
|
|
||||||
click () {
|
|
||||||
dialog.showMessageBox({
|
|
||||||
title: 'PicGo',
|
|
||||||
message: 'PicGo',
|
|
||||||
detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '打开详细窗口',
|
|
||||||
click () {
|
|
||||||
if (settingWindow === null) {
|
|
||||||
createSettingWindow()
|
|
||||||
settingWindow.show()
|
|
||||||
} else {
|
|
||||||
settingWindow.show()
|
|
||||||
settingWindow.focus()
|
|
||||||
}
|
|
||||||
if (miniWindow) {
|
|
||||||
miniWindow.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '选择默认图床',
|
|
||||||
type: 'submenu',
|
|
||||||
submenu
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '打开更新助手',
|
|
||||||
type: 'checkbox',
|
|
||||||
checked: db.get('settings.showUpdateTip').value(),
|
|
||||||
click () {
|
|
||||||
const value = db.read().get('settings.showUpdateTip').value()
|
|
||||||
db.read().set('settings.showUpdateTip', !value).write()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '重启应用',
|
|
||||||
click () {
|
|
||||||
app.relaunch()
|
|
||||||
app.exit(0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: 'quit',
|
|
||||||
label: '退出'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTray () {
|
|
||||||
const menubarPic = process.platform === 'darwin' ? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png`
|
|
||||||
tray = new Tray(menubarPic)
|
|
||||||
tray.on('right-click', () => {
|
|
||||||
if (window) {
|
|
||||||
window.hide()
|
|
||||||
}
|
|
||||||
createContextMenu()
|
|
||||||
tray.popUpContextMenu(contextMenu)
|
|
||||||
})
|
|
||||||
tray.on('click', (event, bounds) => {
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
let img = clipboard.readImage()
|
|
||||||
let obj = []
|
|
||||||
if (!img.isEmpty()) {
|
|
||||||
// 从剪贴板来的图片默认转为png
|
|
||||||
const imgUrl = 'data:image/png;base64,' + Buffer.from(img.toPNG(), 'binary').toString('base64')
|
|
||||||
obj.push({
|
|
||||||
width: img.getSize().width,
|
|
||||||
height: img.getSize().height,
|
|
||||||
imgUrl
|
|
||||||
})
|
|
||||||
}
|
|
||||||
toggleWindow(bounds)
|
|
||||||
setTimeout(() => {
|
|
||||||
window.webContents.send('clipboardFiles', obj)
|
|
||||||
}, 0)
|
|
||||||
} else {
|
|
||||||
if (window) {
|
|
||||||
window.hide()
|
|
||||||
}
|
|
||||||
if (settingWindow === null) {
|
|
||||||
createSettingWindow()
|
|
||||||
settingWindow.show()
|
|
||||||
} else {
|
|
||||||
settingWindow.show()
|
|
||||||
settingWindow.focus()
|
|
||||||
}
|
|
||||||
if (miniWindow) {
|
|
||||||
miniWindow.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
tray.on('drag-enter', () => {
|
|
||||||
tray.setImage(`${__static}/upload.png`)
|
|
||||||
})
|
|
||||||
|
|
||||||
tray.on('drag-end', () => {
|
|
||||||
tray.setImage(`${__static}/menubar.png`)
|
|
||||||
})
|
|
||||||
|
|
||||||
tray.on('drop-files', async (event, files) => {
|
|
||||||
const pasteStyle = db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
const imgs = await new Uploader(files, window.webContents).upload()
|
|
||||||
if (imgs !== false) {
|
|
||||||
for (let i in imgs) {
|
|
||||||
clipboard.writeText(pasteTemplate(pasteStyle, imgs[i]))
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传成功',
|
|
||||||
body: imgs[i].imgUrl,
|
|
||||||
icon: files[i]
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
notification.show()
|
|
||||||
}, i * 100)
|
|
||||||
db.read().get('uploaded').insert(imgs[i]).write()
|
|
||||||
}
|
|
||||||
window.webContents.send('dragFiles', imgs)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// toggleWindow()
|
|
||||||
}
|
|
||||||
|
|
||||||
const createWindow = () => {
|
|
||||||
if (process.platform !== 'darwin' && process.platform !== 'win32') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
window = new BrowserWindow({
|
|
||||||
height: 350,
|
|
||||||
width: 196, // 196
|
|
||||||
show: false,
|
|
||||||
frame: false,
|
|
||||||
fullscreenable: false,
|
|
||||||
resizable: false,
|
|
||||||
transparent: true,
|
|
||||||
vibrancy: 'ultra-dark',
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
window.loadURL(winURL)
|
|
||||||
|
|
||||||
window.on('closed', () => {
|
|
||||||
window = null
|
|
||||||
})
|
|
||||||
|
|
||||||
window.on('blur', () => {
|
|
||||||
window.hide()
|
|
||||||
})
|
|
||||||
return window
|
|
||||||
}
|
|
||||||
|
|
||||||
const createMiniWidow = () => {
|
|
||||||
if (miniWindow) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let obj = {
|
|
||||||
height: 64,
|
|
||||||
width: 64,
|
|
||||||
show: process.platform === 'linux',
|
|
||||||
frame: false,
|
|
||||||
fullscreenable: false,
|
|
||||||
skipTaskbar: true,
|
|
||||||
resizable: false,
|
|
||||||
transparent: process.platform !== 'linux',
|
|
||||||
icon: `${__static}/logo.png`,
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (db.read().get('settings.miniWindowOntop').value()) {
|
|
||||||
obj.alwaysOnTop = true
|
|
||||||
}
|
|
||||||
|
|
||||||
miniWindow = new BrowserWindow(obj)
|
|
||||||
|
|
||||||
miniWindow.loadURL(miniWinURL)
|
|
||||||
|
|
||||||
miniWindow.on('closed', () => {
|
|
||||||
miniWindow = null
|
|
||||||
})
|
|
||||||
return miniWindow
|
|
||||||
}
|
|
||||||
|
|
||||||
const createSettingWindow = () => {
|
|
||||||
const options = {
|
|
||||||
height: 450,
|
|
||||||
width: 800,
|
|
||||||
show: false,
|
|
||||||
frame: true,
|
|
||||||
center: true,
|
|
||||||
fullscreenable: false,
|
|
||||||
resizable: false,
|
|
||||||
title: 'PicGo',
|
|
||||||
vibrancy: 'ultra-dark',
|
|
||||||
transparent: true,
|
|
||||||
titleBarStyle: 'hidden',
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false,
|
|
||||||
webSecurity: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
options.show = false
|
|
||||||
options.frame = false
|
|
||||||
options.backgroundColor = '#3f3c37'
|
|
||||||
options.transparent = false
|
|
||||||
options.icon = `${__static}/logo.png`
|
|
||||||
}
|
|
||||||
settingWindow = new BrowserWindow(options)
|
|
||||||
|
|
||||||
settingWindow.loadURL(settingWinURL)
|
|
||||||
|
|
||||||
settingWindow.on('closed', () => {
|
|
||||||
settingWindow = null
|
|
||||||
if (process.platform === 'linux') {
|
|
||||||
app.quit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
createMenu()
|
|
||||||
createMiniWidow()
|
|
||||||
return settingWindow
|
|
||||||
}
|
|
||||||
|
|
||||||
const createMenu = () => {
|
|
||||||
if (process.env.NODE_ENV !== 'development') {
|
|
||||||
const template = [{
|
|
||||||
label: 'Edit',
|
|
||||||
submenu: [
|
|
||||||
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
|
|
||||||
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
|
|
||||||
{ type: 'separator' },
|
|
||||||
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
|
|
||||||
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
|
|
||||||
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
|
|
||||||
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' },
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
accelerator: 'CmdOrCtrl+Q',
|
|
||||||
click () {
|
|
||||||
app.quit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
menu = Menu.buildFromTemplate(template)
|
|
||||||
Menu.setApplicationMenu(menu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleWindow = (bounds) => {
|
|
||||||
if (window.isVisible()) {
|
|
||||||
window.hide()
|
|
||||||
} else {
|
|
||||||
showWindow(bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const showWindow = (bounds) => {
|
|
||||||
window.setPosition(bounds.x - 98 + 11, bounds.y, false)
|
|
||||||
window.webContents.send('updateFiles')
|
|
||||||
window.show()
|
|
||||||
window.focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadClipboardFiles = async () => {
|
|
||||||
let win
|
|
||||||
if (miniWindow.isVisible()) {
|
|
||||||
win = miniWindow
|
|
||||||
} else {
|
|
||||||
win = settingWindow || window || createSettingWindow()
|
|
||||||
}
|
|
||||||
let img = await new Uploader(undefined, win.webContents).upload()
|
|
||||||
if (img !== false) {
|
|
||||||
if (img.length > 0) {
|
|
||||||
const pasteStyle = db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
clipboard.writeText(pasteTemplate(pasteStyle, img[0]))
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传成功',
|
|
||||||
body: img[0].imgUrl,
|
|
||||||
icon: img[0].imgUrl
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
db.read().get('uploaded').insert(img[0]).write()
|
|
||||||
window.webContents.send('clipboardFiles', [])
|
|
||||||
window.webContents.send('uploadFiles', img)
|
|
||||||
if (settingWindow) {
|
|
||||||
settingWindow.webContents.send('updateGallery')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传不成功',
|
|
||||||
body: '你剪贴板最新的一条记录不是图片哦'
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadChoosedFiles = async (webContents, files) => {
|
|
||||||
const input = files.map(item => item.path)
|
|
||||||
const imgs = await new Uploader(input, webContents).upload()
|
|
||||||
if (imgs !== false) {
|
|
||||||
const pasteStyle = db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
let pasteText = ''
|
|
||||||
for (let i in imgs) {
|
|
||||||
pasteText += pasteTemplate(pasteStyle, imgs[i]) + '\r\n'
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传成功',
|
|
||||||
body: imgs[i].imgUrl,
|
|
||||||
icon: files[i].path
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
notification.show()
|
|
||||||
}, i * 100)
|
|
||||||
db.read().get('uploaded').insert(imgs[i]).write()
|
|
||||||
}
|
|
||||||
clipboard.writeText(pasteText)
|
|
||||||
window.webContents.send('uploadFiles', imgs)
|
|
||||||
if (settingWindow) {
|
|
||||||
settingWindow.webContents.send('updateGallery')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
picgoCoreIPC(app, ipcMain)
|
|
||||||
|
|
||||||
// from macOS tray
|
|
||||||
ipcMain.on('uploadClipboardFiles', async (evt, file) => {
|
|
||||||
const img = await new Uploader(undefined, window.webContents).upload()
|
|
||||||
if (img !== false) {
|
|
||||||
const pasteStyle = db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
clipboard.writeText(pasteTemplate(pasteStyle, img[0]))
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传成功',
|
|
||||||
body: img[0].imgUrl,
|
|
||||||
// icon: file[0]
|
|
||||||
icon: img[0].imgUrl
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
db.read().get('uploaded').insert(img[0]).write()
|
|
||||||
window.webContents.send('clipboardFiles', [])
|
|
||||||
if (settingWindow) {
|
|
||||||
settingWindow.webContents.send('updateGallery')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.webContents.send('uploadFiles')
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('uploadClipboardFilesFromUploadPage', () => {
|
|
||||||
uploadClipboardFiles()
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('uploadChoosedFiles', async (evt, files) => {
|
|
||||||
return uploadChoosedFiles(evt.sender, files)
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('updateShortKey', (evt, oldKey) => {
|
|
||||||
globalShortcut.unregisterAll()
|
|
||||||
for (let key in oldKey) {
|
|
||||||
globalShortcut.register(db.read().get('settings.shortKey').value()[key], () => {
|
|
||||||
return shortKeyHash[key]()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '操作成功',
|
|
||||||
body: '你的快捷键已经修改成功'
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('updateCustomLink', (evt, oldLink) => {
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '操作成功',
|
|
||||||
body: '你的自定义链接格式已经修改成功'
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('autoStart', (evt, val) => {
|
|
||||||
app.setLoginItemSettings({
|
|
||||||
openAtLogin: val
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('openSettingWindow', (evt) => {
|
|
||||||
if (!settingWindow) {
|
|
||||||
createSettingWindow()
|
|
||||||
} else {
|
|
||||||
settingWindow.show()
|
|
||||||
}
|
|
||||||
miniWindow.hide()
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('openMiniWindow', (evt) => {
|
|
||||||
if (!miniWindow) {
|
|
||||||
createMiniWidow()
|
|
||||||
}
|
|
||||||
miniWindow.show()
|
|
||||||
miniWindow.focus()
|
|
||||||
settingWindow.hide()
|
|
||||||
})
|
|
||||||
|
|
||||||
// from mini window
|
|
||||||
ipcMain.on('syncPicBed', (evt) => {
|
|
||||||
if (settingWindow) {
|
|
||||||
settingWindow.webContents.send('syncPicBed')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.on('getPicBeds', (evt) => {
|
|
||||||
const picBeds = getPicBeds(app)
|
|
||||||
evt.sender.send('getPicBeds', picBeds)
|
|
||||||
evt.returnValue = picBeds
|
|
||||||
})
|
|
||||||
|
|
||||||
const shortKeyHash = {
|
|
||||||
upload: uploadClipboardFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
const gotTheLock = app.requestSingleInstanceLock()
|
|
||||||
|
|
||||||
if (!gotTheLock) {
|
|
||||||
app.quit()
|
|
||||||
} else {
|
|
||||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
|
||||||
let files = getUploadFiles(commandLine, workingDirectory)
|
|
||||||
if (files === null || files.length > 0) { // 如果有文件列表作为参数,说明是命令行启动
|
|
||||||
if (files === null) {
|
|
||||||
uploadClipboardFiles()
|
|
||||||
} else {
|
|
||||||
let win
|
|
||||||
if (miniWindow && miniWindow.isVisible()) {
|
|
||||||
win = miniWindow
|
|
||||||
} else {
|
|
||||||
win = settingWindow || window || createSettingWindow()
|
|
||||||
}
|
|
||||||
uploadChoosedFiles(win.webContents, files)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (settingWindow) {
|
|
||||||
if (settingWindow.isMinimized()) {
|
|
||||||
settingWindow.restore()
|
|
||||||
}
|
|
||||||
settingWindow.focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
app.setAppUserModelId(pkg.build.appId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.XDG_CURRENT_DESKTOP && process.env.XDG_CURRENT_DESKTOP.includes('Unity')) {
|
|
||||||
process.env.XDG_CURRENT_DESKTOP = 'Unity'
|
|
||||||
}
|
|
||||||
|
|
||||||
app.on('ready', () => {
|
|
||||||
createWindow()
|
|
||||||
createSettingWindow()
|
|
||||||
if (process.platform === 'darwin' || process.platform === 'win32') {
|
|
||||||
createTray()
|
|
||||||
}
|
|
||||||
db.read().set('needReload', false).write()
|
|
||||||
updateChecker()
|
|
||||||
|
|
||||||
globalShortcut.register(db.read().get('settings.shortKey.upload').value(), () => {
|
|
||||||
uploadClipboardFiles()
|
|
||||||
})
|
|
||||||
if (process.env.NODE_ENV !== 'development') {
|
|
||||||
let files = getUploadFiles()
|
|
||||||
if (files === null || files.length > 0) { // 如果有文件列表作为参数,说明是命令行启动
|
|
||||||
if (files === null) {
|
|
||||||
uploadClipboardFiles()
|
|
||||||
} else {
|
|
||||||
let win
|
|
||||||
if (miniWindow && miniWindow.isVisible()) {
|
|
||||||
win = miniWindow
|
|
||||||
} else {
|
|
||||||
win = settingWindow || window || createSettingWindow()
|
|
||||||
}
|
|
||||||
uploadChoosedFiles(win.webContents, files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
app.quit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
app.on('activate', () => {
|
|
||||||
if (window === null) {
|
|
||||||
createWindow()
|
|
||||||
}
|
|
||||||
if (settingWindow === null) {
|
|
||||||
createSettingWindow()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
app.on('will-quit', () => {
|
|
||||||
globalShortcut.unregisterAll()
|
|
||||||
})
|
|
||||||
|
|
||||||
app.setLoginItemSettings({
|
|
||||||
openAtLogin: db.read().get('settings.autoStart').value() || false
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto Updater
|
|
||||||
*
|
|
||||||
* Uncomment the following code below and install `electron-updater` to
|
|
||||||
* support auto updating. Code Signing with a valid certificate is required.
|
|
||||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
|
|
||||||
*/
|
|
||||||
|
|
||||||
// import { autoUpdater } from 'electron-updater'
|
|
||||||
|
|
||||||
// autoUpdater.on('update-downloaded', () => {
|
|
||||||
// autoUpdater.quitAndInstall()
|
|
||||||
// })
|
|
||||||
|
|
||||||
// app.on('ready', () => {
|
|
||||||
// if (process.env.NODE_ENV === 'production') {
|
|
||||||
// autoUpdater.checkForUpdates()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import DB from '#/datastore'
|
||||||
|
// from v2.1.2
|
||||||
|
const updateShortKeyFromVersion212 = (db: typeof DB, shortKeyConfig: IShortKeyConfigs | IOldShortKeyConfigs) => {
|
||||||
|
let needUpgrade = false
|
||||||
|
if (shortKeyConfig.upload) {
|
||||||
|
needUpgrade = true
|
||||||
|
// @ts-ignore
|
||||||
|
shortKeyConfig['picgo:upload'] = {
|
||||||
|
enable: true,
|
||||||
|
key: shortKeyConfig.upload,
|
||||||
|
name: 'upload',
|
||||||
|
label: '快捷上传'
|
||||||
|
}
|
||||||
|
delete shortKeyConfig.upload
|
||||||
|
}
|
||||||
|
if (needUpgrade) {
|
||||||
|
db.set('settings.shortKey', shortKeyConfig)
|
||||||
|
return shortKeyConfig
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
updateShortKeyFromVersion212
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import http from 'http'
|
||||||
|
import routers from './routerManager'
|
||||||
|
import {
|
||||||
|
handleResponse
|
||||||
|
} from './utils'
|
||||||
|
import picgo from '~/main/apis/picgo'
|
||||||
|
import logger from '~/main/utils/logger'
|
||||||
|
|
||||||
|
class Server {
|
||||||
|
private httpServer: http.Server
|
||||||
|
private config: IServerConfig
|
||||||
|
constructor () {
|
||||||
|
let config = picgo.getConfig('settings.server')
|
||||||
|
const result = this.checkIfConfigIsValid(config)
|
||||||
|
if (result) {
|
||||||
|
this.config = config
|
||||||
|
} else {
|
||||||
|
config = {
|
||||||
|
port: 36677,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
enable: true
|
||||||
|
}
|
||||||
|
this.config = config
|
||||||
|
picgo.saveConfig({
|
||||||
|
'settings.server': config
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.httpServer = http.createServer(this.handleRequest)
|
||||||
|
}
|
||||||
|
private checkIfConfigIsValid (config: IObj | undefined) {
|
||||||
|
if (config && config.port && config.host && (config.enable !== undefined)) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
|
||||||
|
if (request.method === 'POST') {
|
||||||
|
if (!routers.getHandler(request.url!)) {
|
||||||
|
handleResponse({
|
||||||
|
response,
|
||||||
|
statusCode: 404,
|
||||||
|
header: {},
|
||||||
|
body: {
|
||||||
|
success: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let body: string = ''
|
||||||
|
let postObj: IObj
|
||||||
|
request.on('data', chunk => {
|
||||||
|
body += chunk
|
||||||
|
})
|
||||||
|
request.on('end', () => {
|
||||||
|
try {
|
||||||
|
postObj = (body === '') ? {} : JSON.parse(body)
|
||||||
|
} catch (err) {
|
||||||
|
return handleResponse({
|
||||||
|
response,
|
||||||
|
body: {
|
||||||
|
success: false,
|
||||||
|
message: 'Not sending data in JSON format'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handler = routers.getHandler(request.url!)
|
||||||
|
handler!({
|
||||||
|
...postObj,
|
||||||
|
response
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response.statusCode = 404
|
||||||
|
response.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private listen = (port: number) => {
|
||||||
|
logger.info(`[PicGo Server] is listening at ${port}`)
|
||||||
|
this.httpServer.listen(port, this.config.host).on('error', (err: ErrnoException) => {
|
||||||
|
if (err.errno === 'EADDRINUSE') {
|
||||||
|
logger.warn(`[PicGo Server] ${port} is busy, trying with port ${port + 1}`)
|
||||||
|
this.config.port += 1
|
||||||
|
picgo.saveConfig({
|
||||||
|
'settings.server': this.config
|
||||||
|
})
|
||||||
|
this.listen(this.config.port)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
startup () {
|
||||||
|
if (this.config.enable) {
|
||||||
|
this.listen(this.config.port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shutdown () {
|
||||||
|
this.httpServer.close()
|
||||||
|
logger.info('[PicGo Server] shutdown')
|
||||||
|
}
|
||||||
|
restart () {
|
||||||
|
this.config = picgo.getConfig('settings.server')
|
||||||
|
this.shutdown()
|
||||||
|
this.startup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Server()
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
class Router {
|
||||||
|
private router = new Map<string, routeHandler>()
|
||||||
|
|
||||||
|
get (url: string, callback: routeHandler): void {
|
||||||
|
this.router.set(url, callback)
|
||||||
|
}
|
||||||
|
post (url: string, callback: routeHandler): void {
|
||||||
|
this.router.set(url, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
getHandler (url: string) {
|
||||||
|
if (this.router.has(url)) {
|
||||||
|
return this.router.get(url)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Router()
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import router from './router'
|
||||||
|
import {
|
||||||
|
uploadWithClipboardFiles,
|
||||||
|
uploadWithFiles
|
||||||
|
} from '~/main/apis/bus/index'
|
||||||
|
import {
|
||||||
|
handleResponse
|
||||||
|
} from './utils'
|
||||||
|
import logger from '../utils/logger'
|
||||||
|
|
||||||
|
router.get('/upload', async ({
|
||||||
|
response,
|
||||||
|
list = []
|
||||||
|
} : {
|
||||||
|
response: IHttpResponse,
|
||||||
|
list?: string[]
|
||||||
|
}): Promise<void> => {
|
||||||
|
try {
|
||||||
|
if (list.length === 0) {
|
||||||
|
// upload with clipboard
|
||||||
|
const res = await uploadWithClipboardFiles()
|
||||||
|
if (res.success) {
|
||||||
|
handleResponse({
|
||||||
|
response,
|
||||||
|
body: {
|
||||||
|
success: true,
|
||||||
|
result: [res.result]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
handleResponse({
|
||||||
|
response
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// upload with files
|
||||||
|
const pathList = list.map(item => {
|
||||||
|
return {
|
||||||
|
path: item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const res = await uploadWithFiles(pathList)
|
||||||
|
if (res.success) {
|
||||||
|
handleResponse({
|
||||||
|
response,
|
||||||
|
body: {
|
||||||
|
success: true,
|
||||||
|
result: res.result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
handleResponse({
|
||||||
|
response
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err)
|
||||||
|
handleResponse({
|
||||||
|
response,
|
||||||
|
body: {
|
||||||
|
success: false,
|
||||||
|
message: err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export const handleResponse = ({
|
||||||
|
response,
|
||||||
|
statusCode = 200,
|
||||||
|
header = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body = {
|
||||||
|
success: false
|
||||||
|
}
|
||||||
|
} : {
|
||||||
|
response: IHttpResponse,
|
||||||
|
statusCode?: number,
|
||||||
|
header?: IObj,
|
||||||
|
body?: any
|
||||||
|
}) => {
|
||||||
|
response.writeHead(statusCode, header)
|
||||||
|
response.write(JSON.stringify(body))
|
||||||
|
response.end()
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import fs from 'fs-extra'
|
|
||||||
import path from 'path'
|
|
||||||
import os from 'os'
|
|
||||||
if (process.env.NODE_ENV !== 'development') {
|
|
||||||
global.__static = path.join(__dirname, '/static').replace(/\\/g, '\\\\')
|
|
||||||
}
|
|
||||||
if (process.env.DEBUG_ENV === 'debug') {
|
|
||||||
global.__static = path.join(__dirname, '../../../static').replace(/\\/g, '\\\\')
|
|
||||||
}
|
|
||||||
function beforeOpen () {
|
|
||||||
const dest = `${os.homedir}/Library/Services/Upload pictures with PicGo.workflow`
|
|
||||||
if (fs.existsSync(dest)) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
fs.copySync(path.join(__static, 'Upload pictures with PicGo.workflow'), dest)
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default beforeOpen
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import fs from 'fs-extra'
|
||||||
|
import path from 'path'
|
||||||
|
import os from 'os'
|
||||||
|
import { remote, app } from 'electron'
|
||||||
|
|
||||||
|
const APP = process.type === 'renderer' ? remote.app : app
|
||||||
|
const STORE_PATH = APP.getPath('userData')
|
||||||
|
|
||||||
|
function beforeOpen () {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
resolveMacWorkFlow()
|
||||||
|
}
|
||||||
|
resolveClipboardImageGenerator()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* macOS 右键菜单
|
||||||
|
*/
|
||||||
|
function resolveMacWorkFlow () {
|
||||||
|
const dest = `${os.homedir}/Library/Services/Upload pictures with PicGo.workflow`
|
||||||
|
if (fs.existsSync(dest)) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
fs.copySync(path.join(__static, 'Upload pictures with PicGo.workflow'), dest)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化剪贴板生成图片的脚本
|
||||||
|
*/
|
||||||
|
function resolveClipboardImageGenerator () {
|
||||||
|
let clipboardFiles = getClipboardFiles()
|
||||||
|
if (!fs.pathExistsSync(path.join(STORE_PATH, 'windows10.ps1'))) {
|
||||||
|
clipboardFiles.forEach(item => {
|
||||||
|
fs.copyFileSync(item.origin, item.dest)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
clipboardFiles.forEach(item => {
|
||||||
|
diffFilesAndUpdate(item.origin, item.dest)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function diffFilesAndUpdate (filePath1: string, filePath2: string) {
|
||||||
|
let file1 = fs.readFileSync(filePath1)
|
||||||
|
let file2 = fs.readFileSync(filePath2)
|
||||||
|
|
||||||
|
if (!file1.equals(file2)) {
|
||||||
|
fs.copyFileSync(filePath1, filePath2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getClipboardFiles () {
|
||||||
|
let files = [
|
||||||
|
'/linux.sh',
|
||||||
|
'/mac.applescript',
|
||||||
|
'/windows.ps1',
|
||||||
|
'/windows10.ps1'
|
||||||
|
]
|
||||||
|
|
||||||
|
return files.map(item => {
|
||||||
|
return {
|
||||||
|
origin: path.join(__static, item),
|
||||||
|
dest: path.join(STORE_PATH, item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default beforeOpen
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { EventEmitter } from 'events'
|
||||||
|
|
||||||
|
const bus = new EventEmitter()
|
||||||
|
|
||||||
|
export default bus
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import path from 'path'
|
|
||||||
import db from '../../datastore'
|
|
||||||
// eslint-disable-next-line
|
|
||||||
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
|
||||||
|
|
||||||
const getPicBeds = (app) => {
|
|
||||||
const PicGo = requireFunc('picgo')
|
|
||||||
const STORE_PATH = app.getPath('userData')
|
|
||||||
const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
|
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
|
||||||
const picBedTypes = picgo.helper.uploader.getIdList()
|
|
||||||
const picBedFromDB = db.read().get('picBed.list').value() || []
|
|
||||||
const picBeds = picBedTypes.map(item => {
|
|
||||||
const visible = picBedFromDB.find(i => i.type === item) // object or undefined
|
|
||||||
return {
|
|
||||||
type: item,
|
|
||||||
name: picgo.helper.uploader.get(item).name || item,
|
|
||||||
visible: visible ? visible.visible : true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
picgo.cmd.program.removeAllListeners()
|
|
||||||
return picBeds
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
getPicBeds
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import picgo from '../apis/picgo'
|
||||||
|
|
||||||
|
const getPicBeds = () => {
|
||||||
|
const picBedTypes = picgo.helper.uploader.getIdList()
|
||||||
|
const picBedFromDB = picgo.getConfig('picBed.list') || []
|
||||||
|
const picBeds = picBedTypes.map((item: string) => {
|
||||||
|
const visible = picBedFromDB.find((i: IPicBedType) => i.type === item) // object or undefined
|
||||||
|
return {
|
||||||
|
type: item,
|
||||||
|
name: picgo.helper.uploader.get(item).name || item,
|
||||||
|
visible: visible ? visible.visible : true
|
||||||
|
}
|
||||||
|
}) as IPicBedType[]
|
||||||
|
return picBeds
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getPicBeds
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
import {
|
|
||||||
dialog,
|
|
||||||
BrowserWindow,
|
|
||||||
clipboard,
|
|
||||||
Notification
|
|
||||||
} from 'electron'
|
|
||||||
import db from '../../datastore'
|
|
||||||
import Uploader from './uploader'
|
|
||||||
import pasteTemplate from './pasteTemplate'
|
|
||||||
const WEBCONTENTS = Symbol('WEBCONTENTS')
|
|
||||||
const IPCMAIN = Symbol('IPCMAIN')
|
|
||||||
const PICGO = Symbol('PICGO')
|
|
||||||
|
|
||||||
class GuiApi {
|
|
||||||
constructor (ipcMain, webcontents, picgo) {
|
|
||||||
this[WEBCONTENTS] = webcontents
|
|
||||||
this[IPCMAIN] = ipcMain
|
|
||||||
this[PICGO] = picgo
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* for plugin showInputBox
|
|
||||||
* @param {object} options
|
|
||||||
* return type is string or ''
|
|
||||||
*/
|
|
||||||
showInputBox (options) {
|
|
||||||
if (options === undefined) {
|
|
||||||
options = {
|
|
||||||
title: '',
|
|
||||||
placeholder: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this[WEBCONTENTS].send('showInputBox', options)
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this[IPCMAIN].once('showInputBox', (event, value) => {
|
|
||||||
resolve(value)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* for plugin show file explorer
|
|
||||||
* @param {object} options
|
|
||||||
*/
|
|
||||||
showFileExplorer (options) {
|
|
||||||
if (options === undefined) {
|
|
||||||
options = {}
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
dialog.showOpenDialog(BrowserWindow.fromWebContents(this[WEBCONTENTS]), options, filename => {
|
|
||||||
resolve(filename)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* for plugin to upload file
|
|
||||||
* @param {array} input
|
|
||||||
*/
|
|
||||||
async upload (input) {
|
|
||||||
const imgs = await new Uploader(input, this[WEBCONTENTS], this[PICGO]).upload()
|
|
||||||
if (imgs !== false) {
|
|
||||||
const pasteStyle = db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
let pasteText = ''
|
|
||||||
for (let i in imgs) {
|
|
||||||
pasteText += pasteTemplate(pasteStyle, imgs[i]) + '\r\n'
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传成功',
|
|
||||||
body: imgs[i].imgUrl,
|
|
||||||
icon: imgs[i].imgUrl
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
notification.show()
|
|
||||||
}, i * 100)
|
|
||||||
db.read().get('uploaded').insert(imgs[i]).write()
|
|
||||||
}
|
|
||||||
clipboard.writeText(pasteText)
|
|
||||||
this[WEBCONTENTS].send('uploadFiles', imgs)
|
|
||||||
this[WEBCONTENTS].send('updateGallery')
|
|
||||||
return imgs
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For notification
|
|
||||||
* @param {Object} options
|
|
||||||
*/
|
|
||||||
showNotification (options = {
|
|
||||||
title: '',
|
|
||||||
body: ''
|
|
||||||
}) {
|
|
||||||
const notification = new Notification({
|
|
||||||
title: options.title,
|
|
||||||
body: options.body
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {Object} options
|
|
||||||
*/
|
|
||||||
showMessageBox (options = {
|
|
||||||
title: '',
|
|
||||||
message: '',
|
|
||||||
type: 'info',
|
|
||||||
buttons: ['Yes', 'No']
|
|
||||||
}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
dialog.showMessageBox(
|
|
||||||
BrowserWindow.fromWebContents(this[WEBCONTENTS]),
|
|
||||||
options,
|
|
||||||
(result, checkboxChecked) => {
|
|
||||||
resolve({
|
|
||||||
result,
|
|
||||||
checkboxChecked
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GuiApi
|
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
|
type ClipboardFileObject = {
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
type Result = ClipboardFileObject[]
|
||||||
const getUploadFiles = (argv = process.argv, cwd = process.cwd()) => {
|
const getUploadFiles = (argv = process.argv, cwd = process.cwd()) => {
|
||||||
let files = argv.slice(1)
|
let files = argv.slice(1)
|
||||||
if (files.length > 0 && files[0] === 'upload') {
|
if (files.length > 0 && files[0] === 'upload') {
|
||||||
@@ -7,7 +11,7 @@ const getUploadFiles = (argv = process.argv, cwd = process.cwd()) => {
|
|||||||
return null // for uploading images in clipboard
|
return null // for uploading images in clipboard
|
||||||
} else if (files.length > 1) {
|
} else if (files.length > 1) {
|
||||||
files = argv.slice(1)
|
files = argv.slice(1)
|
||||||
let result = []
|
let result: Result = []
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
result = files.map(item => {
|
result = files.map(item => {
|
||||||
if (path.isAbsolute(item)) {
|
if (path.isAbsolute(item)) {
|
||||||
@@ -24,7 +28,7 @@ const getUploadFiles = (argv = process.argv, cwd = process.cwd()) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).filter(item => item !== null)
|
}).filter(item => item !== null) as Result
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import chalk from 'chalk'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
import path from 'path'
|
||||||
|
import util from 'util'
|
||||||
|
import db from '#/datastore'
|
||||||
|
import { app } from 'electron'
|
||||||
|
import { IChalkType } from '#/types/enum'
|
||||||
|
const baseDir = app.getPath('userData')
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
private level = {
|
||||||
|
success: IChalkType.success,
|
||||||
|
info: IChalkType.info,
|
||||||
|
warn: IChalkType.warn,
|
||||||
|
error: IChalkType.error
|
||||||
|
}
|
||||||
|
protected handleLog (type: ILogType, msg: ILoggerType): ILoggerType {
|
||||||
|
// if configPath is invalid then this.ctx.config === undefined
|
||||||
|
// if not then check config.silent
|
||||||
|
const log = chalk[this.level[type]](`[PicGo ${type.toUpperCase()}]:`)
|
||||||
|
console.log(log, msg)
|
||||||
|
process.nextTick(() => {
|
||||||
|
this.handleWriteLog(type, msg)
|
||||||
|
})
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
protected handleWriteLog (type: string, msg: ILoggerType): void {
|
||||||
|
try {
|
||||||
|
const logLevel = db.get('settings.logLevel')
|
||||||
|
const logPath = db.get('settings.logPath') || path.join(baseDir, './picgo.log')
|
||||||
|
if (this.checkLogLevel(type, logLevel)) {
|
||||||
|
const picgoLog = fs.createWriteStream(logPath, { flags: 'a', encoding: 'utf8' })
|
||||||
|
let log = `${dayjs().format('YYYY-MM-DD HH:mm:ss')} [PicGo ${type.toUpperCase()}] ${msg}`
|
||||||
|
const logger = new console.Console(picgoLog)
|
||||||
|
if (typeof msg === 'object' && type === 'error') {
|
||||||
|
log += `\n------Error Stack Begin------\n${util.format(msg.stack)}\n-------Error Stack End-------`
|
||||||
|
}
|
||||||
|
logger.log(log)
|
||||||
|
picgoLog.destroy()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected checkLogLevel (type: string, level: undefined | string | string[]): boolean {
|
||||||
|
if (level === undefined || level === 'all') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (Array.isArray(level)) {
|
||||||
|
return level.some((item: string) => (item === type || item === 'all'))
|
||||||
|
} else {
|
||||||
|
return type === level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
success (msg: ILoggerType): ILoggerType {
|
||||||
|
return this.handleLog('success', msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
info (msg: ILoggerType): ILoggerType {
|
||||||
|
return this.handleLog('info', msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
error (msg: ILoggerType): ILoggerType {
|
||||||
|
return this.handleLog('error', msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
warn (msg: ILoggerType): ILoggerType {
|
||||||
|
return this.handleLog('warn', msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Logger()
|
||||||
@@ -1,15 +1,38 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import GuiApi from './guiApi'
|
import GuiApi from '../apis/gui'
|
||||||
import { dialog, shell } from 'electron'
|
import {
|
||||||
|
dialog,
|
||||||
|
shell,
|
||||||
|
IpcMain,
|
||||||
|
IpcMainEvent,
|
||||||
|
App,
|
||||||
|
ipcMain,
|
||||||
|
app
|
||||||
|
} from 'electron'
|
||||||
|
import PicGoCore from '~/universal/types/picgo'
|
||||||
|
import { IPicGoHelperType } from '#/types/enum'
|
||||||
|
import shortKeyHandler from '../apis/shortKey/shortKeyHandler'
|
||||||
|
import picgo from '~/main/apis/picgo'
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
||||||
const PicGo = requireFunc('picgo')
|
// const PluginHandler = requireFunc('picgo/dist/lib/PluginHandler').default
|
||||||
const PluginHandler = requireFunc('picgo/dist/lib/PluginHandler').default
|
const STORE_PATH = app.getPath('userData')
|
||||||
|
// const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
|
||||||
|
|
||||||
|
type PicGoNotice = {
|
||||||
|
title: string,
|
||||||
|
body: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GuiMenuItem {
|
||||||
|
label: string
|
||||||
|
handle: (arg0: PicGoCore, arg1: GuiApi) => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
// get uploader or transformer config
|
// get uploader or transformer config
|
||||||
const getConfig = (name, type, ctx) => {
|
const getConfig = (name: string, type: IPicGoHelperType, ctx: PicGoCore) => {
|
||||||
let config = []
|
let config: any[] = []
|
||||||
if (name === '') {
|
if (name === '') {
|
||||||
return config
|
return config
|
||||||
} else {
|
} else {
|
||||||
@@ -23,7 +46,7 @@ const getConfig = (name, type, ctx) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleConfigWithFunction = config => {
|
const handleConfigWithFunction = (config: any[]) => {
|
||||||
for (let i in config) {
|
for (let i in config) {
|
||||||
if (typeof config[i].default === 'function') {
|
if (typeof config[i].default === 'function') {
|
||||||
config[i].default = config[i].default()
|
config[i].default = config[i].default()
|
||||||
@@ -35,9 +58,8 @@ const handleConfigWithFunction = config => {
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleGetPluginList = (ipcMain, STORE_PATH, CONFIG_PATH) => {
|
const handleGetPluginList = () => {
|
||||||
ipcMain.on('getPluginList', event => {
|
ipcMain.on('getPluginList', (event: IpcMainEvent) => {
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
|
||||||
const pluginList = picgo.pluginLoader.getList()
|
const pluginList = picgo.pluginLoader.getList()
|
||||||
const list = []
|
const list = []
|
||||||
for (let i in pluginList) {
|
for (let i in pluginList) {
|
||||||
@@ -56,7 +78,7 @@ const handleGetPluginList = (ipcMain, STORE_PATH, CONFIG_PATH) => {
|
|||||||
gui = true
|
gui = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const obj = {
|
const obj: IPicGoPlugin = {
|
||||||
name: pluginList[i].replace(/picgo-plugin-/, ''),
|
name: pluginList[i].replace(/picgo-plugin-/, ''),
|
||||||
author: pluginPKG.author.name || pluginPKG.author,
|
author: pluginPKG.author.name || pluginPKG.author,
|
||||||
description: pluginPKG.description,
|
description: pluginPKG.description,
|
||||||
@@ -70,11 +92,11 @@ const handleGetPluginList = (ipcMain, STORE_PATH, CONFIG_PATH) => {
|
|||||||
},
|
},
|
||||||
uploader: {
|
uploader: {
|
||||||
name: uploaderName,
|
name: uploaderName,
|
||||||
config: handleConfigWithFunction(getConfig(uploaderName, 'uploader', picgo))
|
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader, picgo))
|
||||||
},
|
},
|
||||||
transformer: {
|
transformer: {
|
||||||
name: transformerName,
|
name: transformerName,
|
||||||
config: handleConfigWithFunction(getConfig(uploaderName, 'transformer', picgo))
|
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer, picgo))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
|
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
|
||||||
@@ -89,48 +111,49 @@ const handleGetPluginList = (ipcMain, STORE_PATH, CONFIG_PATH) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePluginInstall = (ipcMain, CONFIG_PATH) => {
|
const handlePluginInstall = () => {
|
||||||
ipcMain.on('installPlugin', async (event, msg) => {
|
ipcMain.on('installPlugin', async (event: IpcMainEvent, msg: string) => {
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
picgo.once('installSuccess', (notice: PicGoNotice) => {
|
||||||
const pluginHandler = new PluginHandler(picgo)
|
|
||||||
picgo.on('installSuccess', notice => {
|
|
||||||
event.sender.send('installSuccess', notice.body[0].replace(/picgo-plugin-/, ''))
|
event.sender.send('installSuccess', notice.body[0].replace(/picgo-plugin-/, ''))
|
||||||
|
shortKeyHandler.registerPluginShortKey(notice.body[0])
|
||||||
|
picgo.removeAllListeners('installFailed')
|
||||||
})
|
})
|
||||||
picgo.on('failed', () => {
|
picgo.once('installFailed', () => {
|
||||||
handleNPMError()
|
handleNPMError()
|
||||||
|
picgo.removeAllListeners('installSuccess')
|
||||||
})
|
})
|
||||||
await pluginHandler.uninstall([msg])
|
await picgo.pluginHandler.install([msg])
|
||||||
pluginHandler.install([msg])
|
|
||||||
picgo.cmd.program.removeAllListeners()
|
picgo.cmd.program.removeAllListeners()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePluginUninstall = (ipcMain, CONFIG_PATH) => {
|
const handlePluginUninstall = () => {
|
||||||
ipcMain.on('uninstallPlugin', async (event, msg) => {
|
ipcMain.on('uninstallPlugin', async (event: IpcMainEvent, msg: string) => {
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
picgo.once('uninstallSuccess', (notice: PicGoNotice) => {
|
||||||
const pluginHandler = new PluginHandler(picgo)
|
|
||||||
picgo.on('uninstallSuccess', notice => {
|
|
||||||
event.sender.send('uninstallSuccess', notice.body[0].replace(/picgo-plugin-/, ''))
|
event.sender.send('uninstallSuccess', notice.body[0].replace(/picgo-plugin-/, ''))
|
||||||
|
shortKeyHandler.unregisterPluginShortKey(notice.body[0])
|
||||||
|
picgo.removeAllListeners('uninstallFailed')
|
||||||
})
|
})
|
||||||
picgo.on('failed', () => {
|
picgo.once('uninstallFailed', () => {
|
||||||
handleNPMError()
|
handleNPMError()
|
||||||
|
picgo.removeAllListeners('uninstallSuccess')
|
||||||
})
|
})
|
||||||
await pluginHandler.uninstall([msg])
|
await picgo.pluginHandler.uninstall([msg])
|
||||||
picgo.cmd.program.removeAllListeners()
|
picgo.cmd.program.removeAllListeners()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePluginUpdate = (ipcMain, CONFIG_PATH) => {
|
const handlePluginUpdate = () => {
|
||||||
ipcMain.on('updatePlugin', async (event, msg) => {
|
ipcMain.on('updatePlugin', async (event: IpcMainEvent, msg: string) => {
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
picgo.once('updateSuccess', (notice: { body: string[], title: string }) => {
|
||||||
const pluginHandler = new PluginHandler(picgo)
|
|
||||||
picgo.on('updateSuccess', notice => {
|
|
||||||
event.sender.send('updateSuccess', notice.body[0].replace(/picgo-plugin-/, ''))
|
event.sender.send('updateSuccess', notice.body[0].replace(/picgo-plugin-/, ''))
|
||||||
|
picgo.removeAllListeners('updateFailed')
|
||||||
})
|
})
|
||||||
picgo.on('failed', () => {
|
picgo.once('updateFailed', () => {
|
||||||
handleNPMError()
|
handleNPMError()
|
||||||
|
picgo.removeAllListeners('updateSuccess')
|
||||||
})
|
})
|
||||||
await pluginHandler.update([msg])
|
await picgo.pluginHandler.update([msg])
|
||||||
picgo.cmd.program.removeAllListeners()
|
picgo.cmd.program.removeAllListeners()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -140,16 +163,15 @@ const handleNPMError = () => {
|
|||||||
title: '发生错误',
|
title: '发生错误',
|
||||||
message: '请安装Node.js并重启PicGo再继续操作',
|
message: '请安装Node.js并重启PicGo再继续操作',
|
||||||
buttons: ['Yes']
|
buttons: ['Yes']
|
||||||
}, (res) => {
|
}).then((res) => {
|
||||||
if (res === 0) {
|
if (res.response === 0) {
|
||||||
shell.openExternal('https://nodejs.org/')
|
shell.openExternal('https://nodejs.org/')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleGetPicBedConfig = (ipcMain, CONFIG_PATH) => {
|
const handleGetPicBedConfig = () => {
|
||||||
ipcMain.on('getPicBedConfig', (event, type) => {
|
ipcMain.on('getPicBedConfig', (event: IpcMainEvent, type: string) => {
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
|
||||||
const name = picgo.helper.uploader.get(type).name || type
|
const name = picgo.helper.uploader.get(type).name || type
|
||||||
if (picgo.helper.uploader.get(type).config) {
|
if (picgo.helper.uploader.get(type).config) {
|
||||||
const config = handleConfigWithFunction(picgo.helper.uploader.get(type).config(picgo))
|
const config = handleConfigWithFunction(picgo.helper.uploader.get(type).config(picgo))
|
||||||
@@ -161,13 +183,12 @@ const handleGetPicBedConfig = (ipcMain, CONFIG_PATH) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePluginActions = (ipcMain, CONFIG_PATH) => {
|
const handlePluginActions = () => {
|
||||||
ipcMain.on('pluginActions', (event, name, label) => {
|
ipcMain.on('pluginActions', (event: IpcMainEvent, name: string, label: string) => {
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
|
||||||
const plugin = picgo.pluginLoader.getPlugin(`picgo-plugin-${name}`)
|
const plugin = picgo.pluginLoader.getPlugin(`picgo-plugin-${name}`)
|
||||||
const guiApi = new GuiApi(ipcMain, event.sender, picgo)
|
const guiApi = new GuiApi()
|
||||||
if (plugin.guiMenu && plugin.guiMenu(picgo).length > 0) {
|
if (plugin.guiMenu && plugin.guiMenu(picgo).length > 0) {
|
||||||
const menu = plugin.guiMenu(picgo)
|
const menu: GuiMenuItem[] = plugin.guiMenu(picgo)
|
||||||
menu.forEach(item => {
|
menu.forEach(item => {
|
||||||
if (item.label === label) {
|
if (item.label === label) {
|
||||||
item.handle(picgo, guiApi)
|
item.handle(picgo, guiApi)
|
||||||
@@ -177,24 +198,28 @@ const handlePluginActions = (ipcMain, CONFIG_PATH) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRemoveFiles = (ipcMain, CONFIG_PATH) => {
|
const handleRemoveFiles = () => {
|
||||||
ipcMain.on('removeFiles', (event, files) => {
|
ipcMain.on('removeFiles', (event: IpcMainEvent, files: ImgInfo[]) => {
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
const guiApi = new GuiApi()
|
||||||
const guiApi = new GuiApi(ipcMain, event.sender, picgo)
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
picgo.emit('remove', files, guiApi)
|
picgo.emit('remove', files, guiApi)
|
||||||
}, 500)
|
}, 500)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (app, ipcMain) => {
|
const handlePicGoSaveData = () => {
|
||||||
const STORE_PATH = app.getPath('userData')
|
ipcMain.on('picgoSaveData', (event: IpcMainEvent, data: IObj) => {
|
||||||
const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
|
picgo.saveConfig(data)
|
||||||
handleGetPluginList(ipcMain, STORE_PATH, CONFIG_PATH)
|
})
|
||||||
handlePluginInstall(ipcMain, CONFIG_PATH)
|
}
|
||||||
handlePluginUninstall(ipcMain, CONFIG_PATH)
|
|
||||||
handlePluginUpdate(ipcMain, CONFIG_PATH)
|
export default () => {
|
||||||
handleGetPicBedConfig(ipcMain, CONFIG_PATH)
|
handleGetPluginList()
|
||||||
handlePluginActions(ipcMain, CONFIG_PATH)
|
handlePluginInstall()
|
||||||
handleRemoveFiles(ipcMain, CONFIG_PATH)
|
handlePluginUninstall()
|
||||||
|
handlePluginUpdate()
|
||||||
|
handleGetPicBedConfig()
|
||||||
|
handlePluginActions()
|
||||||
|
handleRemoveFiles()
|
||||||
|
handlePicGoSaveData()
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,26 @@
|
|||||||
import { dialog, shell } from 'electron'
|
import { dialog, shell } from 'electron'
|
||||||
import db from '../../datastore'
|
import db from '#/datastore'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import pkg from '../../../package.json'
|
import pkg from 'root/package.json'
|
||||||
const version = pkg.version
|
const version = pkg.version
|
||||||
const release = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
|
let release = 'https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo/package.json'
|
||||||
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
|
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
|
||||||
|
|
||||||
const checkVersion = async () => {
|
const checkVersion = async () => {
|
||||||
let showTip = db.read().get('settings.showUpdateTip').value()
|
let showTip = db.get('settings.showUpdateTip')
|
||||||
if (showTip === undefined) {
|
if (showTip === undefined) {
|
||||||
db.read().set('settings.showUpdateTip', true).write()
|
db.set('settings.showUpdateTip', true)
|
||||||
showTip = true
|
showTip = true
|
||||||
}
|
}
|
||||||
if (showTip) {
|
if (showTip) {
|
||||||
const res = await axios.get(release)
|
let res: any
|
||||||
|
try {
|
||||||
|
res = await axios.get(release)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
const latest = res.data.name
|
const latest = res.data.version
|
||||||
const result = compareVersion2Update(version, latest)
|
const result = compareVersion2Update(version, latest)
|
||||||
if (result) {
|
if (result) {
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
@@ -25,11 +30,11 @@ const checkVersion = async () => {
|
|||||||
message: `发现新版本${latest},更新了很多功能,是否去下载最新的版本?`,
|
message: `发现新版本${latest},更新了很多功能,是否去下载最新的版本?`,
|
||||||
checkboxLabel: '以后不再提醒',
|
checkboxLabel: '以后不再提醒',
|
||||||
checkboxChecked: false
|
checkboxChecked: false
|
||||||
}, (res, checkboxChecked) => {
|
}).then(res => {
|
||||||
if (res === 0) { // if selected yes
|
if (res.response === 0) { // if selected yes
|
||||||
shell.openExternal(downloadUrl)
|
shell.openExternal(downloadUrl)
|
||||||
}
|
}
|
||||||
db.read().set('settings.showUpdateTip', !checkboxChecked).write()
|
db.set('settings.showUpdateTip', !res.checkboxChecked)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -41,7 +46,7 @@ const checkVersion = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if true -> update else return false
|
// if true -> update else return false
|
||||||
const compareVersion2Update = (current, latest) => {
|
const compareVersion2Update = (current: string, latest: string) => {
|
||||||
const currentVersion = current.split('.').map(item => parseInt(item))
|
const currentVersion = current.split('.').map(item => parseInt(item))
|
||||||
const latestVersion = latest.split('.').map(item => parseInt(item))
|
const latestVersion = latest.split('.').map(item => parseInt(item))
|
||||||
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
import {
|
|
||||||
app,
|
|
||||||
Notification,
|
|
||||||
BrowserWindow,
|
|
||||||
ipcMain
|
|
||||||
} from 'electron'
|
|
||||||
import path from 'path'
|
|
||||||
import dayjs from 'dayjs'
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
|
||||||
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
|
||||||
const PicGo = requireFunc('picgo')
|
|
||||||
const STORE_PATH = app.getPath('userData')
|
|
||||||
const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
|
|
||||||
const renameURL = process.env.NODE_ENV === 'development' ? `http://localhost:9080/#rename-page` : `file://${__dirname}/index.html#rename-page`
|
|
||||||
|
|
||||||
const createRenameWindow = (win) => {
|
|
||||||
let options = {
|
|
||||||
height: 175,
|
|
||||||
width: 300,
|
|
||||||
show: true,
|
|
||||||
fullscreenable: false,
|
|
||||||
resizable: false,
|
|
||||||
vibrancy: 'ultra-dark',
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
options.show = true
|
|
||||||
options.backgroundColor = '#3f3c37'
|
|
||||||
options.autoHideMenuBar = true
|
|
||||||
options.transparent = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const window = new BrowserWindow(options)
|
|
||||||
window.loadURL(renameURL)
|
|
||||||
// check if this window is visible
|
|
||||||
if (win.isVisible()) {
|
|
||||||
// bounds: { x: 821, y: 75, width: 800, height: 450 }
|
|
||||||
const bounds = win.getBounds()
|
|
||||||
const positionX = bounds.x + bounds.width / 2 - 150
|
|
||||||
let positionY
|
|
||||||
// if is the settingWindow
|
|
||||||
if (bounds.height > 400) {
|
|
||||||
positionY = bounds.y + bounds.height / 2 - 88
|
|
||||||
} else { // if is the miniWindow
|
|
||||||
positionY = bounds.y + bounds.height / 2
|
|
||||||
}
|
|
||||||
window.setPosition(positionX, positionY, false)
|
|
||||||
}
|
|
||||||
return window
|
|
||||||
}
|
|
||||||
|
|
||||||
const waitForShow = (webcontent) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
webcontent.on('dom-ready', () => {
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const waitForRename = (window, id) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
ipcMain.once(`rename${id}`, (evt, newName) => {
|
|
||||||
resolve(newName)
|
|
||||||
window.hide()
|
|
||||||
})
|
|
||||||
window.on('close', () => {
|
|
||||||
resolve(null)
|
|
||||||
ipcMain.removeAllListeners(`rename${id}`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
class Uploader {
|
|
||||||
constructor (img, webContents, picgo = undefined) {
|
|
||||||
this.img = img
|
|
||||||
this.webContents = webContents
|
|
||||||
this.picgo = picgo
|
|
||||||
}
|
|
||||||
|
|
||||||
upload () {
|
|
||||||
const win = BrowserWindow.fromWebContents(this.webContents)
|
|
||||||
const picgo = this.picgo || new PicGo(CONFIG_PATH)
|
|
||||||
picgo.config.debug = true
|
|
||||||
// for picgo-core
|
|
||||||
picgo.config.PICGO_ENV = 'GUI'
|
|
||||||
let input = this.img
|
|
||||||
|
|
||||||
picgo.helper.beforeUploadPlugins.register('renameFn', {
|
|
||||||
handle: async ctx => {
|
|
||||||
const rename = picgo.getConfig('settings.rename')
|
|
||||||
const autoRename = picgo.getConfig('settings.autoRename')
|
|
||||||
await Promise.all(ctx.output.map(async (item, index) => {
|
|
||||||
let name
|
|
||||||
let fileName
|
|
||||||
if (autoRename) {
|
|
||||||
fileName = dayjs().add(index, 'second').format('YYYYMMDDHHmmss') + item.extname
|
|
||||||
} else {
|
|
||||||
fileName = item.fileName
|
|
||||||
}
|
|
||||||
if (rename) {
|
|
||||||
const window = createRenameWindow(win)
|
|
||||||
await waitForShow(window.webContents)
|
|
||||||
window.webContents.send('rename', fileName, window.webContents.id)
|
|
||||||
name = await waitForRename(window, window.webContents.id)
|
|
||||||
}
|
|
||||||
item.fileName = name || fileName
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
picgo.on('beforeTransform', ctx => {
|
|
||||||
if (ctx.getConfig('settings.uploadNotification')) {
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传进度',
|
|
||||||
body: '正在上传'
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
picgo.upload(input)
|
|
||||||
|
|
||||||
picgo.on('notification', message => {
|
|
||||||
const notification = new Notification(message)
|
|
||||||
notification.show()
|
|
||||||
})
|
|
||||||
|
|
||||||
picgo.on('uploadProgress', progress => {
|
|
||||||
this.webContents.send('uploadProgress', progress)
|
|
||||||
})
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
picgo.on('finished', ctx => {
|
|
||||||
if (ctx.output.every(item => item.imgUrl)) {
|
|
||||||
resolve(ctx.output)
|
|
||||||
} else {
|
|
||||||
resolve(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
picgo.on('failed', ctx => {
|
|
||||||
const notification = new Notification({
|
|
||||||
title: '上传失败',
|
|
||||||
body: '请检查配置和上传的文件是否符合要求'
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
resolve(false)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Uploader
|
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'picgo'
|
name: 'picgo'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus">
|
<style lang="stylus">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 32 KiB |
@@ -21,13 +21,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
if (this.type === this.$db.get('picBed.current').value()) {
|
if (this.type === this.$db.get('picBed.current')) {
|
||||||
this.value = true
|
this.value = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
choosePicBed (val) {
|
choosePicBed (val) {
|
||||||
this.$db.set('picBed.current', this.type)
|
this.letPicGoSaveData({
|
||||||
|
'picBed.current': this.type
|
||||||
|
})
|
||||||
this.$emit('update:choosed', this.type)
|
this.$emit('update:choosed', this.type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-for="(item, index) in configList"
|
v-for="(item, index) in configList"
|
||||||
:label="item.name"
|
:label="item.alias || item.name"
|
||||||
:required="item.required"
|
:required="item.required"
|
||||||
:prop="item.name"
|
:prop="item.name"
|
||||||
:key="item.name + index"
|
:key="item.name + index"
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
:placeholder="item.message || item.name"
|
:placeholder="item.message || item.name"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="(choice, idx) in item.choices"
|
v-for="choice in item.choices"
|
||||||
:label="choice.name || choice.value || choice"
|
:label="choice.name || choice.value || choice"
|
||||||
:key="choice.name || choice.value || choice"
|
:key="choice.name || choice.value || choice"
|
||||||
:value="choice.value || choice"
|
:value="choice.value || choice"
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
collapse-tags
|
collapse-tags
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="(choice, idx) in item.choices"
|
v-for="choice in item.choices"
|
||||||
:label="choice.name || choice.value || choice"
|
:label="choice.name || choice.value || choice"
|
||||||
:key="choice.value || choice"
|
:key="choice.value || choice"
|
||||||
:value="choice.value || choice"
|
:value="choice.value || choice"
|
||||||
@@ -58,68 +58,63 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
Vue,
|
||||||
|
Prop,
|
||||||
|
Watch
|
||||||
|
} from 'vue-property-decorator'
|
||||||
import { cloneDeep, union } from 'lodash'
|
import { cloneDeep, union } from 'lodash'
|
||||||
export default {
|
|
||||||
name: 'config-form',
|
@Component({
|
||||||
props: {
|
name: 'config-form'
|
||||||
config: Array,
|
})
|
||||||
type: String,
|
export default class extends Vue {
|
||||||
id: {
|
@Prop() private config!: any[]
|
||||||
type: String,
|
@Prop() readonly type!: string
|
||||||
default: ''
|
@Prop() readonly id!: string
|
||||||
}
|
configList = []
|
||||||
},
|
ruleForm = {}
|
||||||
data () {
|
@Watch('config', {
|
||||||
return {
|
deep: true,
|
||||||
configList: [],
|
immediate: true
|
||||||
ruleForm: {}
|
})
|
||||||
}
|
handleConfigChange (val: any) {
|
||||||
},
|
this.ruleForm = Object.assign({}, {})
|
||||||
created () {
|
const config = this.$db.get(`picBed.${this.id}`)
|
||||||
},
|
if (val.length > 0) {
|
||||||
watch: {
|
this.configList = cloneDeep(val).map((item: any) => {
|
||||||
config: {
|
let defaultValue = item.default !== undefined
|
||||||
deep: true,
|
? item.default : item.type === 'checkbox'
|
||||||
handler (val) {
|
? [] : null
|
||||||
this.ruleForm = Object.assign({}, {})
|
if (item.type === 'checkbox') {
|
||||||
const config = this.$db.read().get(`picBed.${this.id}`).value()
|
const defaults = item.choices.filter((i: any) => {
|
||||||
if (val.length > 0) {
|
return i.checked
|
||||||
this.configList = cloneDeep(val).map(item => {
|
}).map((i: any) => i.value)
|
||||||
let defaultValue = item.default !== undefined
|
defaultValue = union(defaultValue, defaults)
|
||||||
? item.default : item.type === 'checkbox'
|
|
||||||
? [] : null
|
|
||||||
if (item.type === 'checkbox') {
|
|
||||||
const defaults = item.choices.filter(i => {
|
|
||||||
return i.checked
|
|
||||||
}).map(i => i.value)
|
|
||||||
defaultValue = union(defaultValue, defaults)
|
|
||||||
}
|
|
||||||
if (config && config[item.name] !== undefined) {
|
|
||||||
defaultValue = config[item.name]
|
|
||||||
}
|
|
||||||
this.$set(this.ruleForm, item.name, defaultValue)
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
if (config && config[item.name] !== undefined) {
|
||||||
immediate: true
|
defaultValue = config[item.name]
|
||||||
}
|
}
|
||||||
},
|
this.$set(this.ruleForm, item.name, defaultValue)
|
||||||
methods: {
|
return item
|
||||||
async validate () {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.$refs.form.validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
resolve(this.ruleForm)
|
|
||||||
} else {
|
|
||||||
resolve(false)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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>
|
</script>
|
||||||
<style lang='stylus'>
|
<style lang='stylus'>
|
||||||
|
|||||||
@@ -91,29 +91,6 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog
|
|
||||||
title="修改快捷键"
|
|
||||||
:visible.sync="keyBindingVisible"
|
|
||||||
>
|
|
||||||
<el-form
|
|
||||||
label-width="80px"
|
|
||||||
>
|
|
||||||
<el-form-item
|
|
||||||
label="快捷上传"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
class="align-center"
|
|
||||||
@keydown.native.prevent="keyDetect('upload', $event)"
|
|
||||||
v-model="shortKey.upload"
|
|
||||||
:autofocus="true"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<span slot="footer">
|
|
||||||
<el-button @click="cancelKeyBinding">取消</el-button>
|
|
||||||
<el-button type="primary" @click="confirmKeyBinding">确定</el-button>
|
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
title="自定义链接格式"
|
title="自定义链接格式"
|
||||||
:visible.sync="customLinkVisible"
|
:visible.sync="customLinkVisible"
|
||||||
@@ -159,167 +136,160 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import pkg from 'root/package.json'
|
import pkg from 'root/package.json'
|
||||||
import keyDetect from 'utils/key-binding'
|
import keyDetect from '@/utils/key-binding'
|
||||||
import { remote } from 'electron'
|
import { remote, ipcRenderer, IpcRendererEvent } from 'electron'
|
||||||
import db from '~/datastore'
|
import db from '#/datastore'
|
||||||
import mixin from '@/utils/mixin'
|
import mixin from '@/utils/mixin'
|
||||||
const { Menu, dialog, BrowserWindow } = remote
|
const { Menu, dialog, BrowserWindow } = remote
|
||||||
export default {
|
const customLinkRule = (rule: string, value: string, callback: (arg0?: Error) => void) => {
|
||||||
|
if (!/\$url/.test(value)) {
|
||||||
|
return callback(new Error('必须含有$url'))
|
||||||
|
} else {
|
||||||
|
return callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Component({
|
||||||
name: 'setting-page',
|
name: 'setting-page',
|
||||||
mixins: [mixin],
|
mixins: [mixin]
|
||||||
data () {
|
})
|
||||||
const customLinkRule = (rule, value, callback) => {
|
export default class extends Vue {
|
||||||
if (!/\$url/.test(value)) {
|
version = process.env.NODE_ENV === 'production' ? pkg.version : 'Dev'
|
||||||
return callback(new Error('必须含有$url'))
|
defaultActive = 'upload'
|
||||||
} else {
|
menu: Electron.Menu | null = null
|
||||||
return callback()
|
visible = false
|
||||||
}
|
keyBindingVisible = false
|
||||||
}
|
customLinkVisible = false
|
||||||
return {
|
customLink = {
|
||||||
version: process.env.NODE_ENV === 'production' ? pkg.version : 'Dev',
|
value: db.get('customLink') || '$url'
|
||||||
defaultActive: 'upload',
|
}
|
||||||
menu: null,
|
rules = {
|
||||||
visible: false,
|
value: [
|
||||||
keyBindingVisible: false,
|
{ validator: customLinkRule, trigger: 'blur' }
|
||||||
customLinkVisible: false,
|
]
|
||||||
customLink: {
|
}
|
||||||
value: db.read().get('customLink').value() || '$url'
|
os = ''
|
||||||
},
|
shortKey: IShortKeyMap = {
|
||||||
rules: {
|
upload: db.get('shortKey.upload')
|
||||||
value: [
|
}
|
||||||
{ validator: customLinkRule, trigger: 'blur' }
|
picBed: IPicBedType[] = []
|
||||||
]
|
// for showInputBox
|
||||||
},
|
showInputBoxVisible = false
|
||||||
os: '',
|
inputBoxValue = ''
|
||||||
shortKey: {
|
inputBoxOptions = {
|
||||||
upload: db.read().get('shortKey.upload').value()
|
title: '',
|
||||||
},
|
placeholder: ''
|
||||||
picBed: [],
|
}
|
||||||
// for showInputBox
|
|
||||||
showInputBoxVisible: false,
|
|
||||||
inputBoxValue: '',
|
|
||||||
inputBoxOptions: {
|
|
||||||
title: '',
|
|
||||||
placeholder: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
this.os = process.platform
|
this.os = process.platform
|
||||||
this.buildMenu()
|
this.buildMenu()
|
||||||
this.$electron.ipcRenderer.send('getPicBeds')
|
ipcRenderer.send('getPicBeds')
|
||||||
this.$electron.ipcRenderer.on('getPicBeds', this.getPicBeds)
|
ipcRenderer.on('getPicBeds', this.getPicBeds)
|
||||||
this.$electron.ipcRenderer.on('showInputBox', (evt, options) => {
|
ipcRenderer.on('showInputBox', (evt: IpcRendererEvent, options: IShowInputBoxOption) => {
|
||||||
this.inputBoxValue = ''
|
this.inputBoxValue = ''
|
||||||
this.inputBoxOptions.title = options.title || ''
|
this.inputBoxOptions.title = options.title || ''
|
||||||
this.inputBoxOptions.placeholder = options.placeholder || ''
|
this.inputBoxOptions.placeholder = options.placeholder || ''
|
||||||
this.showInputBoxVisible = true
|
this.showInputBoxVisible = true
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
methods: {
|
handleSelect (index: string) {
|
||||||
handleSelect (index) {
|
const type = index.match(/picbeds-/)
|
||||||
const type = index.match(/picbeds-/)
|
if (type === null) {
|
||||||
if (type === null) {
|
this.$router.push({
|
||||||
|
name: index
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const picBed = index.replace(/picbeds-/, '')
|
||||||
|
if (this.$builtInPicBed.includes(picBed)) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: index
|
name: picBed
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const picBed = index.replace(/picbeds-/, '')
|
this.$router.push({
|
||||||
if (this.$builtInPicBed.includes(picBed)) {
|
name: 'others',
|
||||||
this.$router.push({
|
params: {
|
||||||
name: picBed
|
type: picBed
|
||||||
})
|
}
|
||||||
} else {
|
})
|
||||||
this.$router.push({
|
}
|
||||||
name: 'others',
|
}
|
||||||
params: {
|
}
|
||||||
type: picBed
|
minimizeWindow () {
|
||||||
}
|
const window = BrowserWindow.getFocusedWindow()
|
||||||
|
window!.minimize()
|
||||||
|
}
|
||||||
|
closeWindow () {
|
||||||
|
const window = BrowserWindow.getFocusedWindow()
|
||||||
|
window!.close()
|
||||||
|
}
|
||||||
|
buildMenu () {
|
||||||
|
const _this = this
|
||||||
|
const template = [
|
||||||
|
{
|
||||||
|
label: '关于',
|
||||||
|
click () {
|
||||||
|
dialog.showMessageBox({
|
||||||
|
title: 'PicGo',
|
||||||
|
message: 'PicGo',
|
||||||
|
detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '赞助PicGo',
|
||||||
|
click () {
|
||||||
|
_this.visible = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
minimizeWindow () {
|
this.menu = Menu.buildFromTemplate(template)
|
||||||
const window = BrowserWindow.getFocusedWindow()
|
}
|
||||||
window.minimize()
|
openDialog () {
|
||||||
},
|
// this.menu!.popup(remote.getCurrentWindow())
|
||||||
closeWindow () {
|
this.menu!.popup()
|
||||||
const window = BrowserWindow.getFocusedWindow()
|
}
|
||||||
window.close()
|
keyDetect (type: string, event: KeyboardEvent) {
|
||||||
},
|
this.shortKey[type] = keyDetect(event).join('+')
|
||||||
buildMenu () {
|
}
|
||||||
const _this = this
|
cancelKeyBinding () {
|
||||||
const template = [
|
this.keyBindingVisible = false
|
||||||
{
|
this.shortKey = db.get('shortKey')
|
||||||
label: '关于',
|
}
|
||||||
click () {
|
cancelCustomLink () {
|
||||||
dialog.showMessageBox({
|
this.customLinkVisible = false
|
||||||
title: 'PicGo',
|
this.customLink.value = db.get('customLink') || '$url'
|
||||||
message: 'PicGo',
|
}
|
||||||
detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`
|
confirmCustomLink () {
|
||||||
})
|
// @ts-ignore
|
||||||
}
|
this.$refs.customLink.validate((valid: boolean) => {
|
||||||
},
|
if (valid) {
|
||||||
{
|
db.set('customLink', this.customLink.value)
|
||||||
label: '赞助PicGo',
|
this.customLinkVisible = false
|
||||||
click () {
|
ipcRenderer.send('updateCustomLink')
|
||||||
_this.visible = true
|
} else {
|
||||||
}
|
return false
|
||||||
}
|
}
|
||||||
]
|
})
|
||||||
this.menu = Menu.buildFromTemplate(template)
|
}
|
||||||
},
|
openMiniWindow () {
|
||||||
openDialog () {
|
ipcRenderer.send('openMiniWindow')
|
||||||
this.menu.popup(remote.getCurrentWindow())
|
}
|
||||||
},
|
getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
|
||||||
keyDetect (type, event) {
|
this.picBed = picBeds
|
||||||
this.shortKey[type] = keyDetect(event).join('+')
|
}
|
||||||
},
|
handleInputBoxClose () {
|
||||||
cancelKeyBinding () {
|
ipcRenderer.send('showInputBox', this.inputBoxValue)
|
||||||
this.keyBindingVisible = false
|
}
|
||||||
this.shortKey = db.read().get('shortKey').value()
|
beforeRouteEnter (to: any, from: any, next: any) {
|
||||||
},
|
next((vm: this) => {
|
||||||
confirmKeyBinding () {
|
|
||||||
const oldKey = db.read().get('shortKey').value()
|
|
||||||
db.read().set('shortKey', this.shortKey).write()
|
|
||||||
this.keyBindingVisible = false
|
|
||||||
this.$electron.ipcRenderer.send('updateShortKey', oldKey)
|
|
||||||
},
|
|
||||||
cancelCustomLink () {
|
|
||||||
this.customLinkVisible = false
|
|
||||||
this.customLink.value = db.read().get('customLink').value() || '$url'
|
|
||||||
},
|
|
||||||
confirmCustomLink () {
|
|
||||||
this.$refs.customLink.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
db.read().set('customLink', this.customLink.value).write()
|
|
||||||
this.customLinkVisible = false
|
|
||||||
this.$electron.ipcRenderer.send('updateCustomLink')
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
openMiniWindow () {
|
|
||||||
this.$electron.ipcRenderer.send('openMiniWindow')
|
|
||||||
},
|
|
||||||
getPicBeds (event, picBeds) {
|
|
||||||
this.picBed = picBeds
|
|
||||||
},
|
|
||||||
handleInputBoxClose () {
|
|
||||||
this.$electron.ipcRenderer.send('showInputBox', this.inputBoxValue)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeRouteEnter: (to, from, next) => {
|
|
||||||
next(vm => {
|
|
||||||
vm.defaultActive = to.name
|
vm.defaultActive = to.name
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
||||||
this.$electron.ipcRenderer.removeAllListeners('showInputBox')
|
ipcRenderer.removeAllListeners('showInputBox')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -364,12 +334,12 @@ $darwinBg = transparentify(#172426, #000, 0.7)
|
|||||||
position absolute
|
position absolute
|
||||||
top 2px
|
top 2px
|
||||||
right 4px
|
right 4px
|
||||||
width 60px
|
|
||||||
z-index 10000
|
z-index 10000
|
||||||
-webkit-app-region no-drag
|
-webkit-app-region no-drag
|
||||||
i
|
i
|
||||||
cursor pointer
|
cursor pointer
|
||||||
font-size 16px
|
font-size 16px
|
||||||
|
margin-left 5px
|
||||||
.el-icon-minus
|
.el-icon-minus
|
||||||
&:hover
|
&:hover
|
||||||
color #409EFF
|
color #409EFF
|
||||||
|
|||||||
@@ -102,258 +102,263 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
// @ts-ignore
|
||||||
import gallerys from 'vue-gallery'
|
import gallerys from 'vue-gallery'
|
||||||
import pasteStyle from '~/main/utils/pasteTemplate'
|
import pasteStyle from '#/utils/pasteTemplate'
|
||||||
export default {
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
|
import {
|
||||||
|
ipcRenderer,
|
||||||
|
clipboard,
|
||||||
|
IpcRendererEvent
|
||||||
|
} from 'electron'
|
||||||
|
@Component({
|
||||||
name: 'gallery',
|
name: 'gallery',
|
||||||
components: {
|
components: {
|
||||||
gallerys
|
gallerys
|
||||||
},
|
}
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
images: [],
|
images: ImgInfo[] = []
|
||||||
idx: null,
|
idx: null | number = null
|
||||||
options: {
|
options = {
|
||||||
titleProperty: 'fileName',
|
titleProperty: 'fileName',
|
||||||
urlProperty: 'imgUrl',
|
urlProperty: 'imgUrl',
|
||||||
closeOnSlideClick: true
|
closeOnSlideClick: true
|
||||||
},
|
}
|
||||||
dialogVisible: false,
|
dialogVisible = false
|
||||||
imgInfo: {
|
imgInfo = {
|
||||||
id: null,
|
id: null,
|
||||||
imgUrl: ''
|
imgUrl: ''
|
||||||
},
|
}
|
||||||
choosedList: {},
|
choosedList: IObjT<boolean> = {}
|
||||||
choosedPicBed: [],
|
choosedPicBed: string[] = []
|
||||||
searchText: '',
|
searchText = ''
|
||||||
handleBarActive: false,
|
handleBarActive = false
|
||||||
pasteStyle: '',
|
pasteStyle = ''
|
||||||
pasteStyleMap: {
|
pasteStyleMap = {
|
||||||
Markdown: 'markdown',
|
Markdown: 'markdown',
|
||||||
HTML: 'HTML',
|
HTML: 'HTML',
|
||||||
URL: 'URL',
|
URL: 'URL',
|
||||||
UBB: 'UBB',
|
UBB: 'UBB',
|
||||||
Custom: 'Custom'
|
Custom: 'Custom'
|
||||||
},
|
}
|
||||||
picBed: []
|
picBed: IPicBedType[] = []
|
||||||
}
|
beforeRouteEnter (to: any, from: any, next: any) {
|
||||||
},
|
next((vm: any) => {
|
||||||
beforeRouteEnter (to, from, next) {
|
|
||||||
next(vm => {
|
|
||||||
vm.getGallery()
|
vm.getGallery()
|
||||||
vm.getPasteStyle()
|
vm.getPasteStyle()
|
||||||
vm.getPicBeds()
|
vm.getPicBeds()
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
created () {
|
created () {
|
||||||
this.$electron.ipcRenderer.on('updateGallery', (event) => {
|
ipcRenderer.on('updateGallery', (event: IpcRendererEvent) => {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.filterList = this.getGallery()
|
this.filterList = this.getGallery()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.send('getPicBeds')
|
ipcRenderer.send('getPicBeds')
|
||||||
this.$electron.ipcRenderer.on('getPicBeds', this.getPicBeds)
|
ipcRenderer.on('getPicBeds', this.getPicBeds)
|
||||||
},
|
}
|
||||||
computed: {
|
get filterList () {
|
||||||
filterList: {
|
return this.getGallery()
|
||||||
get () {
|
}
|
||||||
return this.getGallery()
|
set filterList (val) {
|
||||||
},
|
this.images = val
|
||||||
set (val) {
|
}
|
||||||
return this.val
|
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
|
||||||
|
} 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
|
||||||
methods: {
|
}
|
||||||
getPicBeds (event, picBeds) {
|
zoomImage (index: number) {
|
||||||
this.picBed = picBeds
|
this.idx = index
|
||||||
},
|
this.changeZIndexForGallery(true)
|
||||||
getGallery () {
|
}
|
||||||
if (this.choosedPicBed.length > 0) {
|
changeZIndexForGallery (isOpen: boolean) {
|
||||||
let arr = []
|
if (isOpen) {
|
||||||
this.choosedPicBed.forEach(item => {
|
// @ts-ignore
|
||||||
let obj = {
|
document.querySelector('.main-content.el-row').style.zIndex = 101
|
||||||
type: item
|
} else {
|
||||||
}
|
// @ts-ignore
|
||||||
if (this.searchText) {
|
document.querySelector('.main-content.el-row').style.zIndex = 10
|
||||||
obj.fileName = this.searchText
|
}
|
||||||
}
|
}
|
||||||
arr = arr.concat(this.$db.read().get('uploaded').filter(obj => {
|
handleClose () {
|
||||||
return obj.fileName.indexOf(this.searchText) !== -1 && obj.type === item
|
this.idx = null
|
||||||
}).reverse().value())
|
this.changeZIndexForGallery(false)
|
||||||
})
|
}
|
||||||
this.images = arr
|
copy (item: ImgInfo) {
|
||||||
} else {
|
const style = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||||
if (this.searchText) {
|
const copyLink = pasteStyle(style, item)
|
||||||
let data = this.$db.read().get('uploaded')
|
const obj = {
|
||||||
.filter(item => {
|
title: '复制链接成功',
|
||||||
return item.fileName.indexOf(this.searchText) !== -1
|
body: copyLink,
|
||||||
}).reverse().value()
|
icon: item.url || item.imgUrl
|
||||||
this.images = data
|
}
|
||||||
} else {
|
const myNotification = new Notification(obj.title, obj)
|
||||||
this.images = this.$db.read().get('uploaded').slice().reverse().value()
|
clipboard.writeText(copyLink)
|
||||||
}
|
myNotification.onclick = () => {
|
||||||
}
|
return true
|
||||||
return this.images
|
}
|
||||||
},
|
}
|
||||||
zoomImage (index) {
|
remove (id: string) {
|
||||||
this.idx = index
|
this.$confirm('此操作将把该图片移出相册, 是否继续?', '提示', {
|
||||||
this.changeZIndexForGallery(true)
|
confirmButtonText: '确定',
|
||||||
},
|
cancelButtonText: '取消',
|
||||||
changeZIndexForGallery (isOpen) {
|
type: 'warning'
|
||||||
if (isOpen) {
|
}).then(() => {
|
||||||
document.querySelector('.main-content.el-row').style.zIndex = 101
|
const file = this.$db.getById('uploaded', id)
|
||||||
} else {
|
this.$db.removeById('uploaded', id)
|
||||||
document.querySelector('.main-content.el-row').style.zIndex = 10
|
ipcRenderer.send('removeFiles', [file])
|
||||||
}
|
|
||||||
},
|
|
||||||
handleClose () {
|
|
||||||
this.idx = null
|
|
||||||
this.changeZIndexForGallery(false)
|
|
||||||
},
|
|
||||||
copy (item) {
|
|
||||||
const style = this.$db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
const copyLink = pasteStyle(style, item)
|
|
||||||
const obj = {
|
const obj = {
|
||||||
title: '复制链接成功',
|
title: '操作结果',
|
||||||
body: copyLink,
|
body: '删除成功'
|
||||||
icon: item.url || item.imgUrl
|
|
||||||
}
|
}
|
||||||
const myNotification = new window.Notification(obj.title, obj)
|
const myNotification = new Notification(obj.title, obj)
|
||||||
this.$electron.clipboard.writeText(copyLink)
|
|
||||||
myNotification.onclick = () => {
|
myNotification.onclick = () => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
},
|
this.getGallery()
|
||||||
remove (id) {
|
}).catch((e) => {
|
||||||
this.$confirm('此操作将把该图片移出相册, 是否继续?', '提示', {
|
console.log(e)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
openDialog (item: ImgInfo) {
|
||||||
|
this.imgInfo.id = item.id
|
||||||
|
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()
|
||||||
|
const obj = {
|
||||||
|
title: '修改图片URL成功',
|
||||||
|
body: this.imgInfo.imgUrl,
|
||||||
|
icon: this.imgInfo.imgUrl
|
||||||
|
}
|
||||||
|
const myNotification = new Notification(obj.title, obj)
|
||||||
|
myNotification.onclick = () => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
this.dialogVisible = false
|
||||||
|
this.getGallery()
|
||||||
|
}
|
||||||
|
choosePicBed (type: string) {
|
||||||
|
let idx = this.choosedPicBed.indexOf(type)
|
||||||
|
if (idx !== -1) {
|
||||||
|
this.choosedPicBed.splice(idx, 1)
|
||||||
|
} else {
|
||||||
|
this.choosedPicBed.push(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cleanSearch () {
|
||||||
|
this.searchText = ''
|
||||||
|
}
|
||||||
|
isMultiple (obj: IObj) {
|
||||||
|
return Object.values(obj).some(item => item)
|
||||||
|
}
|
||||||
|
multiRemove () {
|
||||||
|
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
||||||
|
if (Object.values(this.choosedList).some(item => item)) {
|
||||||
|
this.$confirm('将删除刚才选中的图片,是否继续?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
const file = this.$db.read().get('uploaded').getById(id).value()
|
let files: ImgInfo[] = []
|
||||||
this.$db.read().get('uploaded').removeById(id).write()
|
Object.keys(this.choosedList).forEach(key => {
|
||||||
this.$electron.ipcRenderer.send('removeFiles', [file])
|
if (this.choosedList[key]) {
|
||||||
|
const file = this.$db.getById('uploaded', key)
|
||||||
|
files.push(file)
|
||||||
|
this.$db.removeById('uploaded', key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.choosedList = {}
|
||||||
|
this.getGallery()
|
||||||
const obj = {
|
const obj = {
|
||||||
title: '操作结果',
|
title: '操作结果',
|
||||||
body: '删除成功'
|
body: '删除成功'
|
||||||
}
|
}
|
||||||
const myNotification = new window.Notification(obj.title, obj)
|
ipcRenderer.send('removeFiles', files)
|
||||||
|
const myNotification = new Notification(obj.title, obj)
|
||||||
myNotification.onclick = () => {
|
myNotification.onclick = () => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
this.getGallery()
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
openDialog (item) {
|
}
|
||||||
this.imgInfo.id = item.id
|
multiCopy () {
|
||||||
this.imgInfo.imgUrl = item.imgUrl
|
if (Object.values(this.choosedList).some(item => item)) {
|
||||||
this.dialogVisible = true
|
let copyString = ''
|
||||||
},
|
const style = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||||
confirmModify () {
|
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
||||||
this.$db.read().get('uploaded')
|
Object.keys(this.choosedList).forEach(key => {
|
||||||
.getById(this.imgInfo.id)
|
if (this.choosedList[key]) {
|
||||||
.assign({imgUrl: this.imgInfo.imgUrl})
|
const item = this.$db.getById('uploaded', key)
|
||||||
.write()
|
copyString += pasteStyle(style, item) + '\n'
|
||||||
|
this.choosedList[key] = false
|
||||||
|
}
|
||||||
|
})
|
||||||
const obj = {
|
const obj = {
|
||||||
title: '修改图片URL成功',
|
title: '批量复制链接成功',
|
||||||
body: this.imgInfo.imgUrl,
|
body: copyString
|
||||||
icon: this.imgInfo.imgUrl
|
|
||||||
}
|
}
|
||||||
const myNotification = new window.Notification(obj.title, obj)
|
const myNotification = new Notification(obj.title, obj)
|
||||||
|
clipboard.writeText(copyString)
|
||||||
myNotification.onclick = () => {
|
myNotification.onclick = () => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
this.dialogVisible = false
|
|
||||||
this.getGallery()
|
|
||||||
},
|
|
||||||
choosePicBed (type) {
|
|
||||||
let idx = this.choosedPicBed.indexOf(type)
|
|
||||||
if (idx !== -1) {
|
|
||||||
this.choosedPicBed.splice(idx, 1)
|
|
||||||
} else {
|
|
||||||
this.choosedPicBed.push(type)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cleanSearch () {
|
|
||||||
this.searchText = ''
|
|
||||||
},
|
|
||||||
isMultiple (obj) {
|
|
||||||
return Object.values(obj).some(item => item)
|
|
||||||
},
|
|
||||||
multiRemove () {
|
|
||||||
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
|
||||||
if (Object.values(this.choosedList).some(item => item)) {
|
|
||||||
this.$confirm('将删除刚才选中的图片,是否继续?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
let files = []
|
|
||||||
Object.keys(this.choosedList).forEach(key => {
|
|
||||||
if (this.choosedList[key]) {
|
|
||||||
const file = this.$db.read().get('uploaded').getById(key).value()
|
|
||||||
files.push(file)
|
|
||||||
this.$db.read().get('uploaded').removeById(key).write()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.choosedList = {}
|
|
||||||
this.getGallery()
|
|
||||||
const obj = {
|
|
||||||
title: '操作结果',
|
|
||||||
body: '删除成功'
|
|
||||||
}
|
|
||||||
this.$electron.ipcRenderer.send('removeFiles', files)
|
|
||||||
const myNotification = new window.Notification(obj.title, obj)
|
|
||||||
myNotification.onclick = () => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
multiCopy () {
|
|
||||||
if (Object.values(this.choosedList).some(item => item)) {
|
|
||||||
let copyString = ''
|
|
||||||
const style = this.$db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
// choosedList -> { [id]: true or false }; true means choosed. false means not choosed.
|
|
||||||
Object.keys(this.choosedList).forEach(key => {
|
|
||||||
if (this.choosedList[key]) {
|
|
||||||
const item = this.$db.read().get('uploaded').getById(key).value()
|
|
||||||
copyString += pasteStyle(style, item) + '\n'
|
|
||||||
this.choosedList[key] = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const obj = {
|
|
||||||
title: '批量复制链接成功',
|
|
||||||
body: copyString
|
|
||||||
}
|
|
||||||
const myNotification = new window.Notification(obj.title, obj)
|
|
||||||
this.$electron.clipboard.writeText(copyString)
|
|
||||||
myNotification.onclick = () => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleHandleBar () {
|
|
||||||
this.handleBarActive = !this.handleBarActive
|
|
||||||
},
|
|
||||||
getPasteStyle () {
|
|
||||||
this.pasteStyle = this.$db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
},
|
|
||||||
handlePasteStyleChange (val) {
|
|
||||||
this.$db.read().set('settings.pasteStyle', val)
|
|
||||||
.write()
|
|
||||||
this.pasteStyle = val
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
toggleHandleBar () {
|
||||||
|
this.handleBarActive = !this.handleBarActive
|
||||||
|
}
|
||||||
|
getPasteStyle () {
|
||||||
|
this.pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||||
|
}
|
||||||
|
handlePasteStyleChange (val: string) {
|
||||||
|
this.$db.set('settings.pasteStyle', val)
|
||||||
|
this.pasteStyle = val
|
||||||
|
}
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeAllListeners('updateGallery')
|
ipcRenderer.removeAllListeners('updateGallery')
|
||||||
this.$electron.ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -15,31 +15,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
import mixin from '@/utils/mixin'
|
import mixin from '@/utils/mixin'
|
||||||
export default {
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||||
|
import {
|
||||||
|
ipcRenderer,
|
||||||
|
IpcRendererEvent,
|
||||||
|
remote
|
||||||
|
} from 'electron'
|
||||||
|
import path from 'path'
|
||||||
|
@Component({
|
||||||
name: 'mini-page',
|
name: 'mini-page',
|
||||||
mixins: [mixin],
|
mixins: [mixin]
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
logo: 'static/squareLogo.png',
|
logo = require('../assets/squareLogo.png')
|
||||||
dragover: false,
|
dragover = false
|
||||||
progress: 0,
|
progress = 0
|
||||||
showProgress: false,
|
showProgress = false
|
||||||
showError: false,
|
showError = false
|
||||||
dragging: false,
|
dragging = false
|
||||||
wX: '',
|
wX: number = -1
|
||||||
wY: '',
|
wY: number = -1
|
||||||
screenX: '',
|
screenX: number = -1
|
||||||
screenY: '',
|
screenY: number = -1
|
||||||
menu: null,
|
menu: Electron.Menu | null = null
|
||||||
os: '',
|
os = ''
|
||||||
picBed: []
|
picBed: IPicBedType[] = []
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
this.os = process.platform
|
this.os = process.platform
|
||||||
this.$electron.ipcRenderer.on('uploadProgress', (event, progress) => {
|
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, progress: number) => {
|
||||||
if (progress !== -1) {
|
if (progress !== -1) {
|
||||||
this.showProgress = true
|
this.showProgress = true
|
||||||
this.progress = progress
|
this.progress = progress
|
||||||
@@ -49,140 +54,145 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.getPicBeds()
|
this.getPicBeds()
|
||||||
},
|
}
|
||||||
mounted () {
|
mounted () {
|
||||||
window.addEventListener('mousedown', this.handleMouseDown, false)
|
window.addEventListener('mousedown', this.handleMouseDown, false)
|
||||||
window.addEventListener('mousemove', this.handleMouseMove, false)
|
window.addEventListener('mousemove', this.handleMouseMove, false)
|
||||||
window.addEventListener('mouseup', this.handleMouseUp, false)
|
window.addEventListener('mouseup', this.handleMouseUp, false)
|
||||||
},
|
}
|
||||||
watch: {
|
|
||||||
progress (val) {
|
@Watch('progress')
|
||||||
if (val === 100) {
|
onProgressChange (val: number) {
|
||||||
setTimeout(() => {
|
if (val === 100) {
|
||||||
this.showProgress = false
|
setTimeout(() => {
|
||||||
this.showError = false
|
this.showProgress = false
|
||||||
}, 1000)
|
this.showError = false
|
||||||
setTimeout(() => {
|
}, 1000)
|
||||||
this.progress = 0
|
setTimeout(() => {
|
||||||
}, 1200)
|
this.progress = 0
|
||||||
|
}, 1200)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getPicBeds () {
|
||||||
|
this.picBed = ipcRenderer.sendSync('getPicBeds')
|
||||||
|
this.buildMenu()
|
||||||
|
}
|
||||||
|
onDrop (e: DragEvent) {
|
||||||
|
this.dragover = false
|
||||||
|
this.ipcSendFiles(e.dataTransfer!.files)
|
||||||
|
}
|
||||||
|
openUploadWindow () {
|
||||||
|
// @ts-ignore
|
||||||
|
document.getElementById('file-uploader').click()
|
||||||
|
}
|
||||||
|
onChange (e: any) {
|
||||||
|
this.ipcSendFiles(e.target.files)
|
||||||
|
// @ts-ignore
|
||||||
|
document.getElementById('file-uploader').value = ''
|
||||||
|
}
|
||||||
|
ipcSendFiles (files: FileList) {
|
||||||
|
let sendFiles: IFileWithPath[] = []
|
||||||
|
Array.from(files).forEach((item, index) => {
|
||||||
|
let obj = {
|
||||||
|
name: item.name,
|
||||||
|
path: item.path
|
||||||
|
}
|
||||||
|
sendFiles.push(obj)
|
||||||
|
})
|
||||||
|
ipcRenderer.send('uploadChoosedFiles', sendFiles)
|
||||||
|
}
|
||||||
|
handleMouseDown (e: MouseEvent) {
|
||||||
|
this.dragging = true
|
||||||
|
this.wX = e.pageX
|
||||||
|
this.wY = e.pageY
|
||||||
|
this.screenX = e.screenX
|
||||||
|
this.screenY = e.screenY
|
||||||
|
}
|
||||||
|
handleMouseMove (e: MouseEvent) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
if (this.dragging) {
|
||||||
|
const xLoc = e.screenX - this.wX
|
||||||
|
const yLoc = e.screenY - this.wY
|
||||||
|
remote.BrowserWindow.getFocusedWindow()!.setBounds({
|
||||||
|
x: xLoc,
|
||||||
|
y: yLoc,
|
||||||
|
width: 64,
|
||||||
|
height: 64
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleMouseUp (e: MouseEvent) {
|
||||||
|
this.dragging = false
|
||||||
|
if (this.screenX === e.screenX && this.screenY === e.screenY) {
|
||||||
|
if (e.button === 0) { // left mouse
|
||||||
|
this.openUploadWindow()
|
||||||
|
} else {
|
||||||
|
this.getPicBeds()
|
||||||
|
this.openContextMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
methods: {
|
openContextMenu () {
|
||||||
getPicBeds () {
|
this.menu!.popup()
|
||||||
this.picBed = this.$electron.ipcRenderer.sendSync('getPicBeds')
|
}
|
||||||
this.buildMenu()
|
buildMenu () {
|
||||||
},
|
const _this = this
|
||||||
onDrop (e) {
|
const submenu = this.picBed.filter(item => item.visible).map(item => {
|
||||||
this.dragover = false
|
return {
|
||||||
this.ipcSendFiles(e.dataTransfer.files)
|
label: item.name,
|
||||||
},
|
type: 'radio',
|
||||||
openUploadWindow () {
|
checked: this.$db.get('picBed.current') === item.type,
|
||||||
document.getElementById('file-uploader').click()
|
click () {
|
||||||
},
|
_this.letPicGoSaveData({
|
||||||
onChange (e) {
|
'picBed.current': item.type
|
||||||
this.ipcSendFiles(e.target.files)
|
})
|
||||||
document.getElementById('file-uploader').value = ''
|
ipcRenderer.send('syncPicBed')
|
||||||
},
|
|
||||||
ipcSendFiles (files) {
|
|
||||||
let sendFiles = []
|
|
||||||
Array.from(files).forEach((item, index) => {
|
|
||||||
let obj = {
|
|
||||||
name: item.name,
|
|
||||||
path: item.path
|
|
||||||
}
|
|
||||||
sendFiles.push(obj)
|
|
||||||
})
|
|
||||||
this.$electron.ipcRenderer.send('uploadChoosedFiles', sendFiles)
|
|
||||||
},
|
|
||||||
handleMouseDown (e) {
|
|
||||||
this.dragging = true
|
|
||||||
this.wX = e.pageX
|
|
||||||
this.wY = e.pageY
|
|
||||||
this.screenX = e.screenX
|
|
||||||
this.screenY = e.screenY
|
|
||||||
},
|
|
||||||
handleMouseMove (e) {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
if (this.dragging) {
|
|
||||||
const xLoc = e.screenX - this.wX
|
|
||||||
const yLoc = e.screenY - this.wY
|
|
||||||
this.$electron.remote.BrowserWindow.getFocusedWindow().setBounds({
|
|
||||||
x: xLoc,
|
|
||||||
y: yLoc,
|
|
||||||
width: 64,
|
|
||||||
height: 64
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleMouseUp (e) {
|
|
||||||
this.dragging = false
|
|
||||||
if (this.screenX === e.screenX && this.screenY === e.screenY) {
|
|
||||||
if (e.button === 0) { // left mouse
|
|
||||||
this.openUploadWindow()
|
|
||||||
} else {
|
|
||||||
this.getPicBeds()
|
|
||||||
this.openContextMenu()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
openContextMenu () {
|
const template = [
|
||||||
this.menu.popup(this.$electron.remote.getCurrentWindow())
|
{
|
||||||
},
|
label: '打开详细窗口',
|
||||||
buildMenu () {
|
click () {
|
||||||
const _this = this
|
ipcRenderer.send('openSettingWindow')
|
||||||
const submenu = this.picBed.map(item => {
|
|
||||||
return {
|
|
||||||
label: item.name,
|
|
||||||
type: 'radio',
|
|
||||||
checked: this.$db.read().get('picBed.current').value() === item.type,
|
|
||||||
click () {
|
|
||||||
_this.$db.read().set('picBed.current', item.type).write()
|
|
||||||
_this.$electron.ipcRenderer.send('syncPicBed')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
const template = [
|
{
|
||||||
{
|
label: '选择默认图床',
|
||||||
label: '打开详细窗口',
|
type: 'submenu',
|
||||||
click () {
|
submenu
|
||||||
_this.$electron.ipcRenderer.send('openSettingWindow')
|
},
|
||||||
}
|
{
|
||||||
},
|
label: '剪贴板图片上传',
|
||||||
{
|
click () {
|
||||||
label: '选择默认图床',
|
ipcRenderer.send('uploadClipboardFilesFromUploadPage')
|
||||||
type: 'submenu',
|
|
||||||
submenu
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '剪贴板图片上传',
|
|
||||||
click () {
|
|
||||||
_this.$electron.ipcRenderer.send('uploadClipboardFilesFromUploadPage')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '最小化窗口',
|
|
||||||
role: 'minimize'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '重启应用',
|
|
||||||
click () {
|
|
||||||
_this.$electron.remote.app.relaunch()
|
|
||||||
_this.$electron.remote.app.exit(0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: 'quit',
|
|
||||||
label: '退出'
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
this.menu = this.$electron.remote.Menu.buildFromTemplate(template)
|
{
|
||||||
}
|
label: '隐藏窗口',
|
||||||
},
|
click () {
|
||||||
|
remote.BrowserWindow.getFocusedWindow()!.hide()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '重启应用',
|
||||||
|
click () {
|
||||||
|
remote.app.relaunch()
|
||||||
|
remote.app.exit(0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'quit',
|
||||||
|
label: '退出'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
// @ts-ignore
|
||||||
|
this.menu = remote.Menu.buildFromTemplate(template)
|
||||||
|
}
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeAllListeners('uploadProgress')
|
ipcRenderer.removeAllListeners('uploadProgress')
|
||||||
this.$electron.ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
||||||
window.removeEventListener('mousedown', this.handleMouseDown, false)
|
window.removeEventListener('mousedown', this.handleMouseDown, false)
|
||||||
window.removeEventListener('mousemove', this.handleMouseMove, false)
|
window.removeEventListener('mousemove', this.handleMouseMove, false)
|
||||||
window.removeEventListener('mouseup', this.handleMouseUp, false)
|
window.removeEventListener('mouseup', this.handleMouseUp, false)
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
<el-button type="primary" round size="mini" @click="openLogSetting">点击设置</el-button>
|
<el-button type="primary" round size="mini" @click="openLogSetting">点击设置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="修改上传快捷键"
|
label="修改快捷键"
|
||||||
>
|
>
|
||||||
<el-button type="primary" round size="mini" @click="keyBindingVisible = true">点击设置</el-button>
|
<el-button type="primary" round size="mini" @click="goShortCutPage">点击设置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="自定义链接格式"
|
label="自定义链接格式"
|
||||||
@@ -36,6 +36,11 @@
|
|||||||
>
|
>
|
||||||
<el-button type="primary" round size="mini" @click="proxyVisible = true">点击设置</el-button>
|
<el-button type="primary" round size="mini" @click="proxyVisible = true">点击设置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="设置Server"
|
||||||
|
>
|
||||||
|
<el-button type="primary" round size="mini" @click="serverVisible = true">点击设置</el-button>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="检查更新"
|
label="检查更新"
|
||||||
>
|
>
|
||||||
@@ -120,30 +125,6 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-dialog
|
|
||||||
title="修改上传快捷键"
|
|
||||||
:visible.sync="keyBindingVisible"
|
|
||||||
:modal-append-to-body="false"
|
|
||||||
>
|
|
||||||
<el-form
|
|
||||||
label-width="80px"
|
|
||||||
>
|
|
||||||
<el-form-item
|
|
||||||
label="快捷上传"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
class="align-center"
|
|
||||||
@keydown.native.prevent="keyDetect('upload', $event)"
|
|
||||||
v-model="shortKey.upload"
|
|
||||||
:autofocus="true"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<span slot="footer">
|
|
||||||
<el-button @click="cancelKeyBinding" round>取消</el-button>
|
|
||||||
<el-button type="primary" @click="confirmKeyBinding" round>确定</el-button>
|
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
title="自定义链接格式"
|
title="自定义链接格式"
|
||||||
:visible.sync="customLinkVisible"
|
:visible.sync="customLinkVisible"
|
||||||
@@ -263,34 +244,287 @@
|
|||||||
<el-button type="primary" @click="confirmLogLevelSetting" round>确定</el-button>
|
<el-button type="primary" @click="confirmLogLevelSetting" round>确定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
class="server-dialog"
|
||||||
|
width="60%"
|
||||||
|
title="设置PicGo-Server"
|
||||||
|
:visible.sync="serverVisible"
|
||||||
|
:modal-append-to-body="false"
|
||||||
|
>
|
||||||
|
<div class="notice-text">
|
||||||
|
如果你不知道Server的作用,请阅读文档,或者不用修改配置。
|
||||||
|
</div>
|
||||||
|
<el-form
|
||||||
|
label-position="right"
|
||||||
|
label-width="120px"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="是否开启Server"
|
||||||
|
>
|
||||||
|
<el-switch
|
||||||
|
v-model="server.enable"
|
||||||
|
active-text="开"
|
||||||
|
inactive-text="关"
|
||||||
|
></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<template v-if="server.enable">
|
||||||
|
<el-form-item
|
||||||
|
label="设置监听地址"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
type="input"
|
||||||
|
v-model="server.host"
|
||||||
|
placeholder="推荐默认地址:127.0.0.1"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="设置监听端口"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
type="number"
|
||||||
|
v-model="server.port"
|
||||||
|
placeholder="推荐默认端口:36677"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button @click="cancelServerSetting" round>取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmServerSetting" round>确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
import keyDetect from 'utils/key-binding'
|
import keyDetect from '@/utils/key-binding'
|
||||||
import pkg from 'root/package.json'
|
import pkg from 'root/package.json'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import {
|
||||||
|
ipcRenderer,
|
||||||
|
remote
|
||||||
|
} from 'electron'
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
|
import db from '#/datastore'
|
||||||
const release = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
|
const release = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
|
||||||
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
|
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
|
||||||
export default {
|
const customLinkRule = (rule: string, value: string, callback: (arg0?: Error) => void) => {
|
||||||
name: 'picgo-setting',
|
if (!/\$url/.test(value)) {
|
||||||
computed: {
|
return callback(new Error('必须含有$url'))
|
||||||
needUpdate () {
|
} else {
|
||||||
if (this.latestVersion) {
|
return callback()
|
||||||
return this.compareVersion2Update(this.version, this.latestVersion)
|
}
|
||||||
|
}
|
||||||
|
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'),
|
||||||
|
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
|
||||||
|
}
|
||||||
|
picBed: IPicBedType[] = []
|
||||||
|
logFileVisible = false
|
||||||
|
keyBindingVisible = false
|
||||||
|
customLinkVisible = false
|
||||||
|
checkUpdateVisible = false
|
||||||
|
serverVisible = false
|
||||||
|
proxyVisible = false
|
||||||
|
customLink = {
|
||||||
|
value: db.get('settings.customLink') || '$url'
|
||||||
|
}
|
||||||
|
shortKey: IShortKeyMap = {
|
||||||
|
upload: db.get('settings.shortKey.upload')
|
||||||
|
}
|
||||||
|
proxy = db.get('picBed.proxy') || ''
|
||||||
|
rules = {
|
||||||
|
value: [
|
||||||
|
{ validator: customLinkRule, trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
logLevel = {
|
||||||
|
all: '全部-All',
|
||||||
|
success: '成功-Success',
|
||||||
|
error: '错误-Error',
|
||||||
|
info: '普通-Info',
|
||||||
|
warn: '提醒-Warn',
|
||||||
|
none: '不记录日志-None'
|
||||||
|
}
|
||||||
|
server = db.get('settings.server') || {
|
||||||
|
port: 36677,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
enable: true
|
||||||
|
}
|
||||||
|
version = pkg.version
|
||||||
|
latestVersion = ''
|
||||||
|
os = ''
|
||||||
|
|
||||||
|
get needUpdate () {
|
||||||
|
if (this.latestVersion) {
|
||||||
|
return this.compareVersion2Update(this.version, this.latestVersion)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
created () {
|
||||||
|
this.os = process.platform
|
||||||
|
ipcRenderer.send('getPicBeds')
|
||||||
|
ipcRenderer.on('getPicBeds', this.getPicBeds)
|
||||||
|
}
|
||||||
|
getPicBeds (event: Event, picBeds: IPicBedType[]) {
|
||||||
|
this.picBed = picBeds
|
||||||
|
this.form.showPicBedList = this.picBed.map(item => {
|
||||||
|
if (item.visible) {
|
||||||
|
return item.name
|
||||||
|
}
|
||||||
|
}) 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)
|
||||||
|
}
|
||||||
|
openLogSetting () {
|
||||||
|
this.logFileVisible = true
|
||||||
|
}
|
||||||
|
keyDetect (type: string, event: KeyboardEvent) {
|
||||||
|
this.shortKey[type] = keyDetect(event).join('+')
|
||||||
|
}
|
||||||
|
cancelCustomLink () {
|
||||||
|
this.customLinkVisible = false
|
||||||
|
this.customLink.value = db.get('settings.customLink') || '$url'
|
||||||
|
}
|
||||||
|
confirmCustomLink () {
|
||||||
|
// @ts-ignore
|
||||||
|
this.$refs.customLink.validate((valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
db.set('settings.customLink', this.customLink.value)
|
||||||
|
this.customLinkVisible = false
|
||||||
|
ipcRenderer.send('updateCustomLink')
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
cancelProxy () {
|
||||||
|
this.proxyVisible = false
|
||||||
|
this.proxy = db.get('picBed.proxy') || undefined
|
||||||
|
}
|
||||||
|
confirmProxy () {
|
||||||
|
this.proxyVisible = false
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'picBed.proxy': this.proxy
|
||||||
|
})
|
||||||
|
const successNotification = new Notification('设置代理', {
|
||||||
|
body: '设置成功'
|
||||||
|
})
|
||||||
|
successNotification.onclick = () => {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
data () {
|
updateHelperChange (val: boolean) {
|
||||||
const customLinkRule = (rule, value, callback) => {
|
db.set('settings.showUpdateTip', val)
|
||||||
if (!/\$url/.test(value)) {
|
}
|
||||||
return callback(new Error('必须含有$url'))
|
handleShowPicBedListChange (val: string[]) {
|
||||||
|
const list = this.picBed.map(item => {
|
||||||
|
if (!val.includes(item.name)) {
|
||||||
|
item.visible = false
|
||||||
} else {
|
} else {
|
||||||
return callback()
|
item.visible = true
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'picBed.list': list
|
||||||
|
})
|
||||||
|
ipcRenderer.send('getPicBeds')
|
||||||
|
}
|
||||||
|
handleAutoStartChange (val: boolean) {
|
||||||
|
db.set('settings.autoStart', val)
|
||||||
|
ipcRenderer.send('autoStart', val)
|
||||||
|
}
|
||||||
|
handleRename (val: boolean) {
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'settings.rename': val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handleAutoRename (val: boolean) {
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'settings.autoRename': val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
compareVersion2Update (current: string, latest: string) {
|
||||||
|
const currentVersion = current.split('.').map(item => parseInt(item))
|
||||||
|
const latestVersion = latest.split('.').map(item => parseInt(item))
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
if (currentVersion[i] < latestVersion[i]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (currentVersion[i] > latestVersion[i]) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let logLevel = this.$db.read().get('settings.logLevel').value()
|
return false
|
||||||
|
}
|
||||||
|
checkUpdate () {
|
||||||
|
this.checkUpdateVisible = true
|
||||||
|
this.$http.get(release)
|
||||||
|
.then(res => {
|
||||||
|
this.latestVersion = res.data.name
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
confirmCheckVersion () {
|
||||||
|
if (this.needUpdate) {
|
||||||
|
remote.shell.openExternal(downloadUrl)
|
||||||
|
}
|
||||||
|
this.checkUpdateVisible = false
|
||||||
|
}
|
||||||
|
cancelCheckVersion () {
|
||||||
|
this.checkUpdateVisible = false
|
||||||
|
}
|
||||||
|
handleUploadNotification (val: boolean) {
|
||||||
|
db.set('settings.uploadNotification', val)
|
||||||
|
}
|
||||||
|
handleMiniWindowOntop (val: boolean) {
|
||||||
|
db.set('settings.miniWindowOntop', val)
|
||||||
|
this.$message.info('需要重启生效')
|
||||||
|
}
|
||||||
|
confirmLogLevelSetting () {
|
||||||
|
if (this.form.logLevel.length === 0) {
|
||||||
|
return this.$message.error('请选择日志记录等级')
|
||||||
|
}
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'settings.logLevel': this.form.logLevel
|
||||||
|
})
|
||||||
|
const successNotification = new Notification('设置日志', {
|
||||||
|
body: '设置成功'
|
||||||
|
})
|
||||||
|
successNotification.onclick = () => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
this.logFileVisible = false
|
||||||
|
}
|
||||||
|
cancelLogLevelSetting () {
|
||||||
|
this.logFileVisible = false
|
||||||
|
let logLevel = db.get('settings.logLevel')
|
||||||
if (!Array.isArray(logLevel)) {
|
if (!Array.isArray(logLevel)) {
|
||||||
if (logLevel && logLevel.length > 0) {
|
if (logLevel && logLevel.length > 0) {
|
||||||
logLevel = [logLevel]
|
logLevel = [logLevel]
|
||||||
@@ -298,228 +532,57 @@ export default {
|
|||||||
logLevel = ['all']
|
logLevel = ['all']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
this.form.logLevel = logLevel
|
||||||
form: {
|
}
|
||||||
updateHelper: this.$db.read().get('settings.showUpdateTip').value(),
|
confirmServerSetting () {
|
||||||
showPicBedList: [],
|
this.letPicGoSaveData({
|
||||||
autoStart: this.$db.read().get('settings.autoStart').value() || false,
|
'settings.server': this.server
|
||||||
rename: this.$db.read().get('settings.rename').value() || false,
|
})
|
||||||
autoRename: this.$db.read().get('settings.autoRename').value() || false,
|
const successNotification = new Notification('设置PicGo-Server', {
|
||||||
uploadNotification: this.$db.read().get('settings.uploadNotification').value() || false,
|
body: '设置成功'
|
||||||
miniWindowOntop: this.$db.read().get('settings.miniWindowOntop').value() || false,
|
})
|
||||||
logLevel
|
successNotification.onclick = () => {
|
||||||
},
|
return true
|
||||||
picBed: [],
|
|
||||||
logFileVisible: false,
|
|
||||||
keyBindingVisible: false,
|
|
||||||
customLinkVisible: false,
|
|
||||||
checkUpdateVisible: false,
|
|
||||||
proxyVisible: false,
|
|
||||||
customLink: {
|
|
||||||
value: this.$db.read().get('settings.customLink').value() || '$url'
|
|
||||||
},
|
|
||||||
shortKey: {
|
|
||||||
upload: this.$db.read().get('settings.shortKey.upload').value()
|
|
||||||
},
|
|
||||||
proxy: this.$db.read().get('picBed.proxy').value() || undefined,
|
|
||||||
rules: {
|
|
||||||
value: [
|
|
||||||
{ validator: customLinkRule, trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
logLevel: {
|
|
||||||
all: '全部-All',
|
|
||||||
success: '成功-Success',
|
|
||||||
error: '错误-Error',
|
|
||||||
info: '普通-Info',
|
|
||||||
warn: '提醒-Warn',
|
|
||||||
none: '不记录日志-None'
|
|
||||||
},
|
|
||||||
version: pkg.version,
|
|
||||||
latestVersion: '',
|
|
||||||
os: ''
|
|
||||||
}
|
}
|
||||||
},
|
this.serverVisible = false
|
||||||
created () {
|
ipcRenderer.send('updateServer')
|
||||||
this.os = process.platform
|
}
|
||||||
this.$electron.ipcRenderer.send('getPicBeds')
|
cancelServerSetting () {
|
||||||
this.$electron.ipcRenderer.on('getPicBeds', this.getPicBeds)
|
this.serverVisible = false
|
||||||
},
|
this.server = db.get('settings.server') || {
|
||||||
methods: {
|
port: 36677,
|
||||||
getPicBeds (event, picBeds) {
|
host: '127.0.0.1',
|
||||||
this.picBed = picBeds
|
enable: true
|
||||||
this.form.showPicBedList = this.picBed.map(item => {
|
}
|
||||||
if (item.visible) {
|
}
|
||||||
return item.name
|
handleLevelDisabled (val: string) {
|
||||||
}
|
let currentLevel = val
|
||||||
})
|
let flagLevel
|
||||||
},
|
let result = this.form.logLevel.some(item => {
|
||||||
openFile (file) {
|
if (item === 'all' || item === 'none') {
|
||||||
const { app, shell } = this.$electron.remote
|
flagLevel = item
|
||||||
const STORE_PATH = app.getPath('userData')
|
}
|
||||||
const FILE = path.join(STORE_PATH, `/${file}`)
|
return (item === 'all' || item === 'none')
|
||||||
shell.openItem(FILE)
|
})
|
||||||
},
|
if (result) {
|
||||||
openLogSetting () {
|
if (currentLevel !== flagLevel) {
|
||||||
this.logFileVisible = true
|
|
||||||
},
|
|
||||||
keyDetect (type, event) {
|
|
||||||
this.shortKey[type] = keyDetect(event).join('+')
|
|
||||||
},
|
|
||||||
cancelKeyBinding () {
|
|
||||||
this.keyBindingVisible = false
|
|
||||||
this.shortKey = this.$db.read().get('settings.shortKey').value()
|
|
||||||
},
|
|
||||||
confirmKeyBinding () {
|
|
||||||
const oldKey = this.$db.read().get('settings.shortKey').value()
|
|
||||||
this.$db.read().set('settings.shortKey', this.shortKey).write()
|
|
||||||
this.keyBindingVisible = false
|
|
||||||
this.$electron.ipcRenderer.send('updateShortKey', oldKey)
|
|
||||||
},
|
|
||||||
cancelCustomLink () {
|
|
||||||
this.customLinkVisible = false
|
|
||||||
this.customLink.value = this.$db.read().get('settings.customLink').value() || '$url'
|
|
||||||
},
|
|
||||||
confirmCustomLink () {
|
|
||||||
this.$refs.customLink.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.$db.read().set('settings.customLink', this.customLink.value).write()
|
|
||||||
this.customLinkVisible = false
|
|
||||||
this.$electron.ipcRenderer.send('updateCustomLink')
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
cancelProxy () {
|
|
||||||
this.proxyVisible = false
|
|
||||||
this.proxy = this.$db.read().get('picBed.proxy').value() || undefined
|
|
||||||
},
|
|
||||||
confirmProxy () {
|
|
||||||
this.proxyVisible = false
|
|
||||||
this.$db.read().set('picBed.proxy', this.proxy).write()
|
|
||||||
const successNotification = new window.Notification('设置代理', {
|
|
||||||
body: '设置成功'
|
|
||||||
})
|
|
||||||
successNotification.onclick = () => {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
},
|
} else if (this.form.logLevel.length > 0) {
|
||||||
updateHelperChange (val) {
|
if (val === 'all' || val === 'none') {
|
||||||
this.$db.read().set('settings.showUpdateTip', val).write()
|
|
||||||
},
|
|
||||||
handleShowPicBedListChange (val) {
|
|
||||||
const list = this.picBed.map(item => {
|
|
||||||
if (!val.includes(item.name)) {
|
|
||||||
item.visible = false
|
|
||||||
} else {
|
|
||||||
item.visible = true
|
|
||||||
}
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
this.$db.read().set('picBed.list', list).write()
|
|
||||||
this.$electron.ipcRenderer.send('getPicBeds')
|
|
||||||
},
|
|
||||||
handleAutoStartChange (val) {
|
|
||||||
this.$db.read().set('settings.autoStart', val).write()
|
|
||||||
this.$electron.ipcRenderer.send('autoStart', val)
|
|
||||||
},
|
|
||||||
handleRename (val) {
|
|
||||||
this.$db.read().set('settings.rename', val).write()
|
|
||||||
},
|
|
||||||
handleAutoRename (val) {
|
|
||||||
this.$db.read().set('settings.autoRename', val).write()
|
|
||||||
},
|
|
||||||
compareVersion2Update (current, latest) {
|
|
||||||
const currentVersion = current.split('.').map(item => parseInt(item))
|
|
||||||
const latestVersion = latest.split('.').map(item => parseInt(item))
|
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
if (currentVersion[i] < latestVersion[i]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (currentVersion[i] > latestVersion[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
checkUpdate () {
|
|
||||||
this.checkUpdateVisible = true
|
|
||||||
this.$http.get(release)
|
|
||||||
.then(res => {
|
|
||||||
this.latestVersion = res.data.name
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
confirmCheckVersion () {
|
|
||||||
if (this.needUpdate) {
|
|
||||||
this.$electron.remote.shell.openExternal(downloadUrl)
|
|
||||||
}
|
|
||||||
this.checkUpdateVisible = false
|
|
||||||
},
|
|
||||||
cancelCheckVersion () {
|
|
||||||
this.checkUpdateVisible = false
|
|
||||||
},
|
|
||||||
handleUploadNotification (val) {
|
|
||||||
this.$db.read().set('settings.uploadNotification', val).write()
|
|
||||||
},
|
|
||||||
handleMiniWindowOntop (val) {
|
|
||||||
this.$db.read().set('settings.miniWindowOntop', val).write()
|
|
||||||
this.$message('需要重启生效')
|
|
||||||
},
|
|
||||||
confirmLogLevelSetting () {
|
|
||||||
if (this.form.logLevel.length === 0) {
|
|
||||||
return this.$message.error('请选择日志记录等级')
|
|
||||||
}
|
|
||||||
this.$db.read().set('settings.logLevel', this.form.logLevel).write()
|
|
||||||
const successNotification = new window.Notification('设置日志', {
|
|
||||||
body: '设置成功'
|
|
||||||
})
|
|
||||||
successNotification.onclick = () => {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
this.logFileVisible = false
|
|
||||||
},
|
|
||||||
cancelLogLevelSetting () {
|
|
||||||
this.logFileVisible = false
|
|
||||||
let logLevel = this.$db.read().get('settings.logLevel').value()
|
|
||||||
if (!Array.isArray(logLevel)) {
|
|
||||||
if (logLevel && logLevel.length > 0) {
|
|
||||||
logLevel = [logLevel]
|
|
||||||
} else {
|
|
||||||
logLevel = ['all']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.form.logLevel = logLevel
|
|
||||||
},
|
|
||||||
handleLevelDisabled (val) {
|
|
||||||
let currentLevel = val
|
|
||||||
let flagLevel
|
|
||||||
let result = this.form.logLevel.some(item => {
|
|
||||||
if (item === 'all' || item === 'none') {
|
|
||||||
flagLevel = item
|
|
||||||
}
|
|
||||||
return (item === 'all' || item === 'none')
|
|
||||||
})
|
|
||||||
if (result) {
|
|
||||||
if (currentLevel !== flagLevel) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if (this.form.logLevel.length > 0) {
|
|
||||||
if (val === 'all' || val === 'none') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
goConfigPage () {
|
|
||||||
this.$electron.remote.shell.openExternal('https://picgo.github.io/PicGo-Doc/zh/guide/config.html#picgo设置')
|
|
||||||
}
|
}
|
||||||
},
|
return false
|
||||||
|
}
|
||||||
|
goConfigPage () {
|
||||||
|
remote.shell.openExternal('https://picgo.github.io/PicGo-Doc/zh/guide/config.html#picgo设置')
|
||||||
|
}
|
||||||
|
goShortCutPage () {
|
||||||
|
this.$router.push('shortKey')
|
||||||
|
}
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -576,4 +639,11 @@ export default {
|
|||||||
margin-left 0
|
margin-left 0
|
||||||
.confirm-button
|
.confirm-button
|
||||||
width 100%
|
width 100%
|
||||||
|
.server-dialog
|
||||||
|
.notice-text
|
||||||
|
color: #49B1F5
|
||||||
|
.el-dialog__body
|
||||||
|
padding-top: 0
|
||||||
|
.el-form-item
|
||||||
|
margin-bottom: 10px
|
||||||
</style>
|
</style>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<div class="plugin-item" :class="{ 'darwin': os === 'darwin' }">
|
<div class="plugin-item" :class="{ 'darwin': os === 'darwin' }">
|
||||||
<div class="cli-only-badge" v-if="!item.gui" title="CLI only">CLI</div>
|
<div class="cli-only-badge" v-if="!item.gui" title="CLI only">CLI</div>
|
||||||
<img class="plugin-item__logo" :src="item.logo"
|
<img class="plugin-item__logo" :src="item.logo"
|
||||||
onerror="this.src='static/roundLogo.png'"
|
:onerror="defaultLogo"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="plugin-item__content"
|
class="plugin-item__content"
|
||||||
@@ -93,58 +93,76 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
import ConfigForm from '@/components/ConfigForm'
|
import {
|
||||||
|
Component,
|
||||||
|
Vue,
|
||||||
|
Watch
|
||||||
|
} from 'vue-property-decorator'
|
||||||
|
import ConfigForm from '@/components/ConfigForm.vue'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
export default {
|
import {
|
||||||
|
ipcRenderer,
|
||||||
|
remote,
|
||||||
|
IpcRendererEvent
|
||||||
|
} from 'electron'
|
||||||
|
const { Menu } = remote
|
||||||
|
|
||||||
|
@Component({
|
||||||
name: 'plugin',
|
name: 'plugin',
|
||||||
components: {
|
components: {
|
||||||
ConfigForm
|
ConfigForm
|
||||||
},
|
}
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
searchText: '',
|
searchText = ''
|
||||||
pluginList: [],
|
pluginList: IPicGoPlugin[] = []
|
||||||
menu: null,
|
menu: Electron.Menu | null = null
|
||||||
config: [],
|
config: any[] = []
|
||||||
currentType: '',
|
currentType = ''
|
||||||
configName: '',
|
configName = ''
|
||||||
dialogVisible: false,
|
dialogVisible = false
|
||||||
pluginNameList: [],
|
pluginNameList: string[] = []
|
||||||
loading: true,
|
loading = true
|
||||||
needReload: false,
|
needReload = false
|
||||||
id: '',
|
id = ''
|
||||||
os: ''
|
os = ''
|
||||||
|
defaultLogo: string = 'this.src="https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@dev/public/roundLogo.png"'
|
||||||
|
get npmSearchText () {
|
||||||
|
return this.searchText.match('picgo-plugin-')
|
||||||
|
? this.searchText
|
||||||
|
: this.searchText !== ''
|
||||||
|
? `picgo-plugin-${this.searchText}`
|
||||||
|
: this.searchText
|
||||||
|
}
|
||||||
|
@Watch('npmSearchText')
|
||||||
|
onNpmSearchTextChange (val: string) {
|
||||||
|
if (val) {
|
||||||
|
this.loading = true
|
||||||
|
this.pluginList = []
|
||||||
|
this.getSearchResult(val)
|
||||||
|
} else {
|
||||||
|
this.getPluginList()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
computed: {
|
@Watch('dialogVisible')
|
||||||
npmSearchText () {
|
onDialogVisible (val: boolean) {
|
||||||
return this.searchText.match('picgo-plugin-')
|
if (val) {
|
||||||
? this.searchText
|
// @ts-ignore
|
||||||
: this.searchText !== ''
|
document.querySelector('.main-content.el-row').style.zIndex = 101
|
||||||
? `picgo-plugin-${this.searchText}`
|
} else {
|
||||||
: this.searchText
|
// @ts-ignore
|
||||||
|
document.querySelector('.main-content.el-row').style.zIndex = 10
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
watch: {
|
|
||||||
npmSearchText (val) {
|
|
||||||
if (val) {
|
|
||||||
this.loading = true
|
|
||||||
this.pluginList = []
|
|
||||||
this.getSearchResult(val)
|
|
||||||
} else {
|
|
||||||
this.getPluginList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
this.os = process.platform
|
this.os = process.platform
|
||||||
this.$electron.ipcRenderer.on('pluginList', (evt, list) => {
|
ipcRenderer.on('pluginList', (evt: IpcRendererEvent, list: IPicGoPlugin[]) => {
|
||||||
this.pluginList = list
|
this.pluginList = list
|
||||||
this.pluginNameList = list.map(item => item.name)
|
this.pluginNameList = list.map(item => item.name)
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.on('installSuccess', (evt, plugin) => {
|
ipcRenderer.on('installSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.pluginList.forEach(item => {
|
this.pluginList.forEach(item => {
|
||||||
if (item.name === plugin) {
|
if (item.name === plugin) {
|
||||||
@@ -153,7 +171,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.on('updateSuccess', (evt, plugin) => {
|
ipcRenderer.on('updateSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.pluginList.forEach(item => {
|
this.pluginList.forEach(item => {
|
||||||
if (item.name === plugin) {
|
if (item.name === plugin) {
|
||||||
@@ -165,7 +183,7 @@ export default {
|
|||||||
this.handleReload()
|
this.handleReload()
|
||||||
this.getPluginList()
|
this.getPluginList()
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.on('uninstallSuccess', (evt, plugin) => {
|
ipcRenderer.on('uninstallSuccess', (evt: IpcRendererEvent, plugin: string) => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.pluginList = this.pluginList.filter(item => {
|
this.pluginList = this.pluginList.filter(item => {
|
||||||
if (item.name === plugin) { // restore Uploader & Transformer after uninstalling
|
if (item.name === plugin) { // restore Uploader & Transformer after uninstalling
|
||||||
@@ -183,242 +201,267 @@ export default {
|
|||||||
})
|
})
|
||||||
this.getPluginList()
|
this.getPluginList()
|
||||||
this.getSearchResult = debounce(this.getSearchResult, 50)
|
this.getSearchResult = debounce(this.getSearchResult, 50)
|
||||||
this.needReload = this.$db.read().get('needReload').value()
|
this.needReload = this.$db.get('needReload')
|
||||||
},
|
}
|
||||||
methods: {
|
buildContextMenu (plugin: IPicGoPlugin) {
|
||||||
buildContextMenu (plugin) {
|
const _this = this
|
||||||
const _this = this
|
let menu = [{
|
||||||
let menu = [{
|
label: '启用插件',
|
||||||
label: '启用插件',
|
enabled: !plugin.enabled,
|
||||||
enabled: !plugin.enabled,
|
click () {
|
||||||
click () {
|
_this.letPicGoSaveData({
|
||||||
_this.$db.read().set(`picgoPlugins.picgo-plugin-${plugin.name}`, true).write()
|
[`picgoPlugins.picgo-plugin-${plugin.name}`]: true
|
||||||
plugin.enabled = true
|
})
|
||||||
_this.getPicBeds()
|
plugin.enabled = true
|
||||||
|
_this.getPicBeds()
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: '禁用插件',
|
||||||
|
enabled: plugin.enabled,
|
||||||
|
click () {
|
||||||
|
_this.letPicGoSaveData({
|
||||||
|
[`picgoPlugins.picgo-plugin-${plugin.name}`]: false
|
||||||
|
})
|
||||||
|
plugin.enabled = false
|
||||||
|
_this.getPicBeds()
|
||||||
|
if (plugin.config.transformer.name) {
|
||||||
|
_this.handleRestoreState('transformer', plugin.config.transformer.name)
|
||||||
}
|
}
|
||||||
}, {
|
if (plugin.config.uploader.name) {
|
||||||
label: '禁用插件',
|
_this.handleRestoreState('uploader', plugin.config.uploader.name)
|
||||||
enabled: plugin.enabled,
|
|
||||||
click () {
|
|
||||||
_this.$db.read().set(`picgoPlugins.picgo-plugin-${plugin.name}`, false).write()
|
|
||||||
plugin.enabled = false
|
|
||||||
_this.getPicBeds()
|
|
||||||
if (plugin.config.transformer.name) {
|
|
||||||
_this.handleRestoreState('transformer', plugin.config.transformer.name)
|
|
||||||
}
|
|
||||||
if (plugin.config.uploader.name) {
|
|
||||||
_this.handleRestoreState('uploader', plugin.config.uploader.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
label: '卸载插件',
|
|
||||||
click () {
|
|
||||||
_this.uninstallPlugin(plugin.name)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
label: '更新插件',
|
|
||||||
click () {
|
|
||||||
_this.updatePlugin(plugin.name)
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
for (let i in plugin.config) {
|
|
||||||
if (plugin.config[i].config.length > 0) {
|
|
||||||
const obj = {
|
|
||||||
label: `配置${i} - ${plugin.config[i].name}`,
|
|
||||||
click () {
|
|
||||||
_this.currentType = i
|
|
||||||
_this.configName = plugin.config[i].name
|
|
||||||
_this.dialogVisible = true
|
|
||||||
_this.config = plugin.config[i].config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu.push(obj)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
// handle transformer
|
label: '卸载插件',
|
||||||
if (plugin.config.transformer.name) {
|
click () {
|
||||||
let currentTransformer = this.$db.read().get('picBed.transformer').value() || 'path'
|
_this.uninstallPlugin(plugin.name)
|
||||||
let pluginTransformer = plugin.config.transformer.name
|
}
|
||||||
|
}, {
|
||||||
|
label: '更新插件',
|
||||||
|
click () {
|
||||||
|
_this.updatePlugin(plugin.name)
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
for (let i in plugin.config) {
|
||||||
|
if (plugin.config[i].config.length > 0) {
|
||||||
const obj = {
|
const obj = {
|
||||||
label: `${currentTransformer === pluginTransformer ? '禁用' : '启用'}transformer - ${plugin.config.transformer.name}`,
|
label: `配置${i} - ${plugin.config[i].name}`,
|
||||||
click () {
|
click () {
|
||||||
_this.toggleTransformer(plugin.config.transformer.name)
|
_this.currentType = i
|
||||||
|
_this.configName = plugin.config[i].name
|
||||||
|
_this.dialogVisible = true
|
||||||
|
_this.config = plugin.config[i].config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
menu.push(obj)
|
menu.push(obj)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// plugin custom menus
|
// handle transformer
|
||||||
if (plugin.guiMenu) {
|
if (plugin.config.transformer.name) {
|
||||||
|
let currentTransformer = this.$db.get('picBed.transformer') || 'path'
|
||||||
|
let pluginTransformer = plugin.config.transformer.name
|
||||||
|
const obj = {
|
||||||
|
label: `${currentTransformer === pluginTransformer ? '禁用' : '启用'}transformer - ${plugin.config.transformer.name}`,
|
||||||
|
click () {
|
||||||
|
_this.toggleTransformer(plugin.config.transformer.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu.push(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// plugin custom menus
|
||||||
|
if (plugin.guiMenu) {
|
||||||
|
menu.push({
|
||||||
|
// @ts-ignore
|
||||||
|
type: 'separator'
|
||||||
|
})
|
||||||
|
for (let i of plugin.guiMenu) {
|
||||||
menu.push({
|
menu.push({
|
||||||
type: 'separator'
|
label: i.label,
|
||||||
|
click () {
|
||||||
|
ipcRenderer.send('pluginActions', plugin.name, i.label)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
for (let i of plugin.guiMenu) {
|
|
||||||
menu.push({
|
|
||||||
label: i.label,
|
|
||||||
click () {
|
|
||||||
_this.$electron.ipcRenderer.send('pluginActions', plugin.name, i.label)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.menu = this.$electron.remote.Menu.buildFromTemplate(menu)
|
this.menu = Menu.buildFromTemplate(menu)
|
||||||
this.menu.popup(this.$electron.remote.getCurrentWindow())
|
this.menu.popup()
|
||||||
},
|
}
|
||||||
getPluginList () {
|
getPluginList () {
|
||||||
this.$electron.ipcRenderer.send('getPluginList')
|
ipcRenderer.send('getPluginList')
|
||||||
},
|
}
|
||||||
getPicBeds () {
|
getPicBeds () {
|
||||||
this.$electron.ipcRenderer.send('getPicBeds')
|
ipcRenderer.send('getPicBeds')
|
||||||
},
|
}
|
||||||
installPlugin (item) {
|
installPlugin (item: IPicGoPlugin) {
|
||||||
if (!item.gui) {
|
if (!item.gui) {
|
||||||
this.$confirm('该插件未对可视化界面进行优化, 是否继续安装?', '提示', {
|
this.$confirm('该插件未对可视化界面进行优化, 是否继续安装?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
item.ing = true
|
item.ing = true
|
||||||
this.$electron.ipcRenderer.send('installPlugin', item.name)
|
ipcRenderer.send('installPlugin', item.name)
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
console.log('Install canceled')
|
console.log('Install canceled')
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
item.ing = true
|
||||||
|
ipcRenderer.send('installPlugin', item.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uninstallPlugin (val: string) {
|
||||||
|
this.pluginList.forEach(item => {
|
||||||
|
if (item.name === val) {
|
||||||
item.ing = true
|
item.ing = true
|
||||||
this.$electron.ipcRenderer.send('installPlugin', item.name)
|
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
uninstallPlugin (val) {
|
ipcRenderer.send('uninstallPlugin', val)
|
||||||
this.pluginList.forEach(item => {
|
}
|
||||||
if (item.name === val) {
|
updatePlugin (val: string) {
|
||||||
item.ing = true
|
this.pluginList.forEach(item => {
|
||||||
}
|
if (item.name === val) {
|
||||||
|
item.ing = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ipcRenderer.send('updatePlugin', val)
|
||||||
|
}
|
||||||
|
reloadApp () {
|
||||||
|
remote.app.relaunch()
|
||||||
|
remote.app.exit(0)
|
||||||
|
}
|
||||||
|
handleReload () {
|
||||||
|
this.$db.set('needReload', true)
|
||||||
|
this.needReload = true
|
||||||
|
const successNotification = new Notification('更新成功', {
|
||||||
|
body: '请点击此通知重启应用以生效'
|
||||||
|
})
|
||||||
|
successNotification.onclick = () => {
|
||||||
|
this.reloadApp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cleanSearch () {
|
||||||
|
this.searchText = ''
|
||||||
|
}
|
||||||
|
toggleTransformer (transformer: string) {
|
||||||
|
let currentTransformer = this.$db.get('picBed.transformer') || 'path'
|
||||||
|
if (currentTransformer === transformer) {
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'picBed.transformer': 'path'
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.send('uninstallPlugin', val)
|
} else {
|
||||||
},
|
this.letPicGoSaveData({
|
||||||
updatePlugin (val) {
|
'picBed.transformer': transformer
|
||||||
this.pluginList.forEach(item => {
|
|
||||||
if (item.name === val) {
|
|
||||||
item.ing = true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.send('updatePlugin', val)
|
}
|
||||||
},
|
}
|
||||||
reloadApp () {
|
async handleConfirmConfig () {
|
||||||
this.$electron.remote.app.relaunch()
|
// @ts-ignore
|
||||||
this.$electron.remote.app.exit(0)
|
const result = await this.$refs.configForm.validate()
|
||||||
},
|
if (result !== false) {
|
||||||
handleReload () {
|
switch (this.currentType) {
|
||||||
this.$db.read().set('needReload', true).write()
|
case 'plugin':
|
||||||
this.needReload = true
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('更新成功', {
|
[`picgo-plugin-${this.configName}`]: result
|
||||||
body: '请点击此通知重启应用以生效'
|
})
|
||||||
|
break
|
||||||
|
case 'uploader':
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
[`picBed.${this.configName}`]: result
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'transformer':
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
[`transformer.${this.configName}`]: result
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
const successNotification = new Notification('设置结果', {
|
||||||
|
body: '设置成功'
|
||||||
})
|
})
|
||||||
successNotification.onclick = () => {
|
successNotification.onclick = () => {
|
||||||
this.reloadApp()
|
return true
|
||||||
}
|
}
|
||||||
},
|
this.dialogVisible = false
|
||||||
cleanSearch () {
|
this.getPluginList()
|
||||||
this.searchText = ''
|
}
|
||||||
},
|
}
|
||||||
toggleTransformer (transformer) {
|
getSearchResult (val: string) {
|
||||||
let currentTransformer = this.$db.read().get('picBed.transformer').value() || 'path'
|
// this.$http.get(`https://api.npms.io/v2/search?q=${val}`)
|
||||||
if (currentTransformer === transformer) {
|
this.$http.get(`https://registry.npmjs.com/-/v1/search?text=${val}`)
|
||||||
this.$db.read().set('picBed.transformer', 'path').write()
|
.then((res: INPMSearchResult) => {
|
||||||
} else {
|
this.pluginList = res.data.objects
|
||||||
this.$db.read().set('picBed.transformer', transformer).write()
|
.filter((item:INPMSearchResultObject) => {
|
||||||
}
|
return item.package.name.includes('picgo-plugin-')
|
||||||
},
|
})
|
||||||
async handleConfirmConfig () {
|
.map((item: INPMSearchResultObject) => {
|
||||||
const result = await this.$refs.configForm.validate()
|
|
||||||
if (result !== false) {
|
|
||||||
switch (this.currentType) {
|
|
||||||
case 'plugin':
|
|
||||||
this.$db.read().set(`picgo-plugin-${this.configName}`, result).write()
|
|
||||||
break
|
|
||||||
case 'uploader':
|
|
||||||
this.$db.read().set(`picBed.${this.configName}`, result).write()
|
|
||||||
break
|
|
||||||
case 'transformer':
|
|
||||||
this.$db.read().set(`transformer.${this.configName}`, result).write()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
const successNotification = new window.Notification('设置结果', {
|
|
||||||
body: '设置成功'
|
|
||||||
})
|
|
||||||
successNotification.onclick = () => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
this.dialogVisible = false
|
|
||||||
this.getPluginList()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getSearchResult: function (val) {
|
|
||||||
// this.$http.get(`https://api.npms.io/v2/search?q=${val}`)
|
|
||||||
this.$http.get(`https://registry.npmjs.com/-/v1/search?text=${val}`)
|
|
||||||
.then(res => {
|
|
||||||
this.pluginList = res.data.objects.map(item => {
|
|
||||||
return this.handleSearchResult(item)
|
return this.handleSearchResult(item)
|
||||||
})
|
})
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
handleSearchResult (item) {
|
handleSearchResult (item: INPMSearchResultObject) {
|
||||||
const name = item.package.name.replace(/picgo-plugin-/, '')
|
const name = item.package.name.replace(/picgo-plugin-/, '')
|
||||||
let gui = false
|
let gui = false
|
||||||
if (item.package.keywords && item.package.keywords.length > 0) {
|
if (item.package.keywords && item.package.keywords.length > 0) {
|
||||||
if (item.package.keywords.includes('picgo-gui-plugin')) {
|
if (item.package.keywords.includes('picgo-gui-plugin')) {
|
||||||
gui = true
|
gui = true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
name: name,
|
|
||||||
author: item.package.author.name,
|
|
||||||
description: item.package.description,
|
|
||||||
logo: `https://cdn.jsdelivr.net/npm/${item.package.name}/logo.png`,
|
|
||||||
config: {},
|
|
||||||
homepage: item.package.links ? item.package.links.homepage : '',
|
|
||||||
hasInstall: this.pluginNameList.some(plugin => plugin === item.package.name.replace(/picgo-plugin-/, '')),
|
|
||||||
version: item.package.version,
|
|
||||||
gui,
|
|
||||||
ing: false // installing or uninstalling
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// restore Uploader & Transformer
|
|
||||||
handleRestoreState (item, name) {
|
|
||||||
if (item === 'uploader') {
|
|
||||||
const current = this.$db.read().get('picBed.current').value()
|
|
||||||
if (current === name) {
|
|
||||||
this.$db.read().set('picBed.current', 'smms').write()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (item === 'transformer') {
|
|
||||||
const current = this.$db.read().get('picBed.transformer').value()
|
|
||||||
if (current === name) {
|
|
||||||
this.$db.read().set('picBed.transformer', 'path').write()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openHomepage (url) {
|
|
||||||
if (url) {
|
|
||||||
this.$electron.remote.shell.openExternal(url)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
goAwesomeList () {
|
|
||||||
this.$electron.remote.shell.openExternal('https://github.com/PicGo/Awesome-PicGo')
|
|
||||||
}
|
}
|
||||||
},
|
return {
|
||||||
|
name: name,
|
||||||
|
author: item.package.author.name,
|
||||||
|
description: item.package.description,
|
||||||
|
logo: `https://cdn.jsdelivr.net/npm/${item.package.name}/logo.png`,
|
||||||
|
config: {},
|
||||||
|
homepage: item.package.links ? item.package.links.homepage : '',
|
||||||
|
hasInstall: this.pluginNameList.some(plugin => plugin === item.package.name.replace(/picgo-plugin-/, '')),
|
||||||
|
version: item.package.version,
|
||||||
|
gui,
|
||||||
|
ing: false // installing or uninstalling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// restore Uploader & Transformer
|
||||||
|
handleRestoreState (item: string, name: string) {
|
||||||
|
if (item === 'uploader') {
|
||||||
|
const current = this.$db.get('picBed.current')
|
||||||
|
if (current === name) {
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'picBed.current': 'smms'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item === 'transformer') {
|
||||||
|
const current = this.$db.get('picBed.transformer')
|
||||||
|
if (current === name) {
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'picBed.transformer': 'path'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openHomepage (url: string) {
|
||||||
|
if (url) {
|
||||||
|
remote.shell.openExternal(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goAwesomeList () {
|
||||||
|
remote.shell.openExternal('https://github.com/PicGo/Awesome-PicGo')
|
||||||
|
}
|
||||||
|
letPicGoSaveData (data: IObj) {
|
||||||
|
ipcRenderer.send('picgoSaveData', data)
|
||||||
|
}
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeAllListeners('pluginList')
|
ipcRenderer.removeAllListeners('pluginList')
|
||||||
this.$electron.ipcRenderer.removeAllListeners('installSuccess')
|
ipcRenderer.removeAllListeners('installSuccess')
|
||||||
this.$electron.ipcRenderer.removeAllListeners('uninstallSuccess')
|
ipcRenderer.removeAllListeners('uninstallSuccess')
|
||||||
this.$electron.ipcRenderer.removeAllListeners('updateSuccess')
|
ipcRenderer.removeAllListeners('updateSuccess')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -21,33 +21,34 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import mixin from '@/utils/mixin'
|
import mixin from '@/utils/mixin'
|
||||||
export default {
|
import {
|
||||||
|
ipcRenderer,
|
||||||
|
IpcRendererEvent
|
||||||
|
} from 'electron'
|
||||||
|
@Component({
|
||||||
name: 'rename-page',
|
name: 'rename-page',
|
||||||
mixins: [mixin],
|
mixins: [mixin]
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
fileName: '',
|
fileName: string = ''
|
||||||
id: null
|
id: string | null = null
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
this.$electron.ipcRenderer.on('rename', (event, name, id) => {
|
ipcRenderer.on('rename', (event: IpcRendererEvent, name: string, id: string) => {
|
||||||
this.fileName = name
|
this.fileName = name
|
||||||
this.id = id
|
this.id = id
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
methods: {
|
confirmName () {
|
||||||
confirmName () {
|
ipcRenderer.send(`rename${this.id}`, this.fileName)
|
||||||
this.$electron.ipcRenderer.send(`rename${this.id}`, this.fileName)
|
}
|
||||||
},
|
cancel () {
|
||||||
cancel () {
|
ipcRenderer.send(`rename${this.id}`, null)
|
||||||
this.$electron.ipcRenderer.send(`rename${this.id}`, null)
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeAllListeners('rename')
|
ipcRenderer.removeAllListeners('rename')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
<template>
|
||||||
|
<div id="shortcut-page">
|
||||||
|
<div class="view-title">
|
||||||
|
快捷键设置
|
||||||
|
</div>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="20" :offset="2">
|
||||||
|
<el-table
|
||||||
|
:data="list"
|
||||||
|
size="mini"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
label="快捷键名称"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ scope.row.label ? scope.row.label : scope.row.name }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
width="160px"
|
||||||
|
label="快捷键绑定"
|
||||||
|
prop="key"
|
||||||
|
>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="状态"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag
|
||||||
|
size="mini"
|
||||||
|
:type="scope.row.enable ? 'success' : 'danger'"
|
||||||
|
>
|
||||||
|
{{ scope.row.enable ? '已启用' : '已禁用' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="来源"
|
||||||
|
width="100px"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ calcOriginShowName(scope.row.from) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="操作"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
@click="toggleEnable(scope.row)"
|
||||||
|
size="mini"
|
||||||
|
:class="{
|
||||||
|
disabled: scope.row.enable
|
||||||
|
}"
|
||||||
|
type="text">
|
||||||
|
{{ scope.row.enable ? '禁用' : '启用' }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
class="edit"
|
||||||
|
size="mini"
|
||||||
|
@click="openKeyBindingDialog(scope.row, scope.$index)"
|
||||||
|
type="text">
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-dialog
|
||||||
|
title="修改上传快捷键"
|
||||||
|
:visible.sync="keyBindingVisible"
|
||||||
|
:modal-append-to-body="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
label-position="top"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="快捷上传"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
class="align-center"
|
||||||
|
@keydown.native.prevent="keyDetect($event)"
|
||||||
|
v-model="shortKey"
|
||||||
|
:autofocus="true"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button @click="cancelKeyBinding" round>取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmKeyBinding" round>确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||||
|
import keyDetect from '@/utils/key-binding'
|
||||||
|
import { ipcRenderer, IpcRendererEvent } from 'electron'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
name: 'shortkey-page'
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
list: IShortKeyConfig[] = []
|
||||||
|
keyBindingVisible = false
|
||||||
|
command = ''
|
||||||
|
shortKey = ''
|
||||||
|
currentIndex = 0
|
||||||
|
created () {
|
||||||
|
const shortKeyConfig = this.$db.get('settings.shortKey') as IShortKeyConfigs
|
||||||
|
this.list = Object.keys(shortKeyConfig).map(item => {
|
||||||
|
return {
|
||||||
|
...shortKeyConfig[item],
|
||||||
|
from: this.calcOrigin(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@Watch('keyBindingVisible')
|
||||||
|
onKeyBindingVisibleChange (val: boolean) {
|
||||||
|
ipcRenderer.send('toggleShortKeyModifiedMode', val)
|
||||||
|
}
|
||||||
|
calcOrigin (item: string) {
|
||||||
|
const [origin] = item.split(':')
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
calcOriginShowName (item: string) {
|
||||||
|
return item.replace('picgo-plugin-', '')
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
this.command = `${config.from}:${config.name}`
|
||||||
|
this.shortKey = this.$db.get(`settings.shortKey.${this.command}.key`)
|
||||||
|
this.currentIndex = index
|
||||||
|
this.keyBindingVisible = true
|
||||||
|
}
|
||||||
|
cancelKeyBinding () {
|
||||||
|
this.keyBindingVisible = false
|
||||||
|
this.shortKey = this.$db.get(`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}`)
|
||||||
|
const config = Object.assign({}, this.list[this.currentIndex])
|
||||||
|
config.key = this.shortKey
|
||||||
|
ipcRenderer.send('updateShortKey', config, oldKey, config.from)
|
||||||
|
ipcRenderer.once('updateShortKeyResponse', (evt: IpcRendererEvent, result) => {
|
||||||
|
if (result) {
|
||||||
|
this.keyBindingVisible = false
|
||||||
|
this.list[this.currentIndex].key = this.shortKey
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
beforeDestroy () {
|
||||||
|
ipcRenderer.send('toggleShortKeyModifiedMode', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang='stylus'>
|
||||||
|
#shortcut-page
|
||||||
|
.el-dialog__body
|
||||||
|
padding 10px 20px
|
||||||
|
.el-form-item
|
||||||
|
margin-bottom 0
|
||||||
|
.el-button
|
||||||
|
&.disabled
|
||||||
|
color: #F56C6C
|
||||||
|
&.edit
|
||||||
|
color: #67C23A
|
||||||
|
.el-table
|
||||||
|
background-color: transparent
|
||||||
|
color #ddd
|
||||||
|
thead
|
||||||
|
color #bbb
|
||||||
|
th,tr
|
||||||
|
background-color: transparent
|
||||||
|
&__body
|
||||||
|
tr.el-table__row--striped
|
||||||
|
td
|
||||||
|
background transparent
|
||||||
|
&--enable-row-hover
|
||||||
|
.el-table__body
|
||||||
|
tr:hover
|
||||||
|
&>td
|
||||||
|
background #333
|
||||||
|
</style>
|
||||||
@@ -25,92 +25,91 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import mixin from '@/utils/mixin'
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import pasteTemplate from '~/main/utils/pasteTemplate'
|
import mixin from '@/utils/mixin'
|
||||||
export default {
|
import pasteTemplate from '#/utils/pasteTemplate'
|
||||||
name: 'tray-page',
|
import { ipcRenderer, clipboard } from 'electron'
|
||||||
mixins: [mixin],
|
@Component({
|
||||||
data () {
|
name: 'tray-page',
|
||||||
return {
|
mixins: [mixin]
|
||||||
files: [],
|
})
|
||||||
notification: {
|
export default class extends Vue {
|
||||||
title: '复制链接成功',
|
files = []
|
||||||
body: '',
|
notification = {
|
||||||
icon: ''
|
title: '复制链接成功',
|
||||||
},
|
body: '',
|
||||||
clipboardFiles: [],
|
icon: ''
|
||||||
uploadFlag: false
|
}
|
||||||
}
|
clipboardFiles: ImgInfo[] = []
|
||||||
},
|
uploadFlag = false
|
||||||
computed: {
|
get reverseList () {
|
||||||
reverseList () {
|
return this.files.slice().reverse()
|
||||||
return this.files.slice().reverse()
|
}
|
||||||
}
|
getData () {
|
||||||
},
|
// @ts-ignore
|
||||||
mounted () {
|
this.files = this.$db.read().get('uploaded').slice().reverse().slice(0, 5).value()
|
||||||
this.disableDragFile()
|
}
|
||||||
this.getData()
|
copyTheLink (item: ImgInfo) {
|
||||||
this.$electron.ipcRenderer.on('dragFiles', (event, files) => {
|
this.notification.body = item.imgUrl!
|
||||||
files.forEach(item => {
|
this.notification.icon = item.imgUrl!
|
||||||
this.$db.read().get('uploaded').insert(item).write()
|
const myNotification = new Notification(this.notification.title, this.notification)
|
||||||
})
|
const pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||||
this.files = this.$db.read().get('uploaded').slice().reverse().slice(0, 5).value()
|
clipboard.writeText(pasteTemplate(pasteStyle, item))
|
||||||
})
|
myNotification.onclick = () => {
|
||||||
this.$electron.ipcRenderer.on('clipboardFiles', (event, files) => {
|
return true
|
||||||
this.clipboardFiles = files
|
|
||||||
})
|
|
||||||
this.$electron.ipcRenderer.on('uploadFiles', (event) => {
|
|
||||||
this.files = this.$db.read().get('uploaded').slice().reverse().slice(0, 5).value()
|
|
||||||
console.log(this.files)
|
|
||||||
this.uploadFlag = false
|
|
||||||
})
|
|
||||||
this.$electron.ipcRenderer.on('updateFiles', (event) => {
|
|
||||||
this.getData()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
this.$electron.ipcRenderer.removeAllListeners('dragFiles')
|
|
||||||
this.$electron.ipcRenderer.removeAllListeners('clipboardFiles')
|
|
||||||
this.$electron.ipcRenderer.removeAllListeners('uploadClipboardFiles')
|
|
||||||
this.$electron.ipcRenderer.removeAllListeners('updateFiles')
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getData () {
|
|
||||||
this.files = this.$db.read().get('uploaded').slice().reverse().slice(0, 5).value()
|
|
||||||
},
|
|
||||||
copyTheLink (item) {
|
|
||||||
this.notification.body = item.imgUrl
|
|
||||||
this.notification.icon = item.imgUrl
|
|
||||||
const myNotification = new window.Notification(this.notification.title, this.notification)
|
|
||||||
const pasteStyle = this.$db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
this.$electron.clipboard.writeText(pasteTemplate(pasteStyle, item))
|
|
||||||
myNotification.onclick = () => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
calcHeight (width, height) {
|
|
||||||
return height * 160 / width
|
|
||||||
},
|
|
||||||
disableDragFile () {
|
|
||||||
window.addEventListener('dragover', (e) => {
|
|
||||||
e = e || event
|
|
||||||
e.preventDefault()
|
|
||||||
}, false)
|
|
||||||
window.addEventListener('drop', (e) => {
|
|
||||||
e = e || event
|
|
||||||
e.preventDefault()
|
|
||||||
}, false)
|
|
||||||
},
|
|
||||||
uploadClipboardFiles () {
|
|
||||||
if (this.uploadFlag) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.uploadFlag = true
|
|
||||||
this.$electron.ipcRenderer.send('uploadClipboardFiles')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
calcHeight (width: number, height: number): number {
|
||||||
|
return height * 160 / width
|
||||||
|
}
|
||||||
|
disableDragFile () {
|
||||||
|
window.addEventListener('dragover', (e) => {
|
||||||
|
e = e || event
|
||||||
|
e.preventDefault()
|
||||||
|
}, false)
|
||||||
|
window.addEventListener('drop', (e) => {
|
||||||
|
e = e || event
|
||||||
|
e.preventDefault()
|
||||||
|
}, false)
|
||||||
|
}
|
||||||
|
uploadClipboardFiles () {
|
||||||
|
if (this.uploadFlag) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.uploadFlag = true
|
||||||
|
ipcRenderer.send('uploadClipboardFiles')
|
||||||
|
}
|
||||||
|
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('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()
|
||||||
|
console.log(this.files)
|
||||||
|
this.uploadFlag = false
|
||||||
|
})
|
||||||
|
ipcRenderer.on('updateFiles', (event: Event) => {
|
||||||
|
this.getData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
beforeDestroy () {
|
||||||
|
ipcRenderer.removeAllListeners('dragFiles')
|
||||||
|
ipcRenderer.removeAllListeners('clipboardFiles')
|
||||||
|
ipcRenderer.removeAllListeners('uploadClipboardFiles')
|
||||||
|
ipcRenderer.removeAllListeners('updateFiles')
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus">
|
<style lang="stylus">
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
:show-text="false"
|
:show-text="false"
|
||||||
class="upload-progress"
|
class="upload-progress"
|
||||||
:class="{ 'show': showProgress }"
|
:class="{ 'show': showProgress }"
|
||||||
:status="showError ? 'exception' : 'text'"
|
:status="showError ? 'exception' : undefined"
|
||||||
></el-progress>
|
></el-progress>
|
||||||
<div class="paste-style">
|
<div class="paste-style">
|
||||||
<div class="el-col-16">
|
<div class="el-col-16">
|
||||||
@@ -55,23 +55,28 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
export default {
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
||||||
name: 'upload',
|
import {
|
||||||
data () {
|
ipcRenderer,
|
||||||
return {
|
IpcRendererEvent,
|
||||||
dragover: false,
|
remote
|
||||||
progress: 0,
|
} from 'electron'
|
||||||
showProgress: false,
|
const { Menu } = remote
|
||||||
showError: false,
|
@Component({
|
||||||
pasteStyle: '',
|
name: 'upload'
|
||||||
picBed: [],
|
})
|
||||||
picBedName: '',
|
export default class extends Vue {
|
||||||
menu: null
|
dragover = false
|
||||||
}
|
progress = 0
|
||||||
},
|
showProgress = false
|
||||||
|
showError = false
|
||||||
|
pasteStyle = ''
|
||||||
|
picBed: IPicBedType[] = []
|
||||||
|
picBedName = ''
|
||||||
|
menu: Electron.Menu | null= null
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$electron.ipcRenderer.on('uploadProgress', (event, progress) => {
|
ipcRenderer.on('uploadProgress', (event: IpcRendererEvent, progress: number) => {
|
||||||
if (progress !== -1) {
|
if (progress !== -1) {
|
||||||
this.showProgress = true
|
this.showProgress = true
|
||||||
this.progress = progress
|
this.progress = progress
|
||||||
@@ -82,94 +87,94 @@ export default {
|
|||||||
})
|
})
|
||||||
this.getPasteStyle()
|
this.getPasteStyle()
|
||||||
this.getDefaultPicBed()
|
this.getDefaultPicBed()
|
||||||
this.$electron.ipcRenderer.on('syncPicBed', () => {
|
ipcRenderer.on('syncPicBed', () => {
|
||||||
this.getDefaultPicBed()
|
this.getDefaultPicBed()
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.send('getPicBeds')
|
ipcRenderer.send('getPicBeds')
|
||||||
this.$electron.ipcRenderer.on('getPicBeds', this.getPicBeds)
|
ipcRenderer.on('getPicBeds', this.getPicBeds)
|
||||||
},
|
}
|
||||||
watch: {
|
@Watch('progress')
|
||||||
progress (val) {
|
onProgressChange (val: number) {
|
||||||
if (val === 100) {
|
if (val === 100) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.showProgress = false
|
this.showProgress = false
|
||||||
this.showError = false
|
this.showError = false
|
||||||
}, 1000)
|
}, 1000)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.progress = 0
|
this.progress = 0
|
||||||
}, 1200)
|
}, 1200)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeAllListeners('uploadProgress')
|
ipcRenderer.removeAllListeners('uploadProgress')
|
||||||
this.$electron.ipcRenderer.removeAllListeners('syncPicBed')
|
ipcRenderer.removeAllListeners('syncPicBed')
|
||||||
this.$electron.ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
ipcRenderer.removeListener('getPicBeds', this.getPicBeds)
|
||||||
},
|
}
|
||||||
methods: {
|
onDrop (e: DragEvent) {
|
||||||
onDrop (e) {
|
this.dragover = false
|
||||||
this.dragover = false
|
this.ipcSendFiles(e.dataTransfer!.files)
|
||||||
this.ipcSendFiles(e.dataTransfer.files)
|
}
|
||||||
},
|
openUplodWindow () {
|
||||||
openUplodWindow () {
|
document.getElementById('file-uploader')!.click()
|
||||||
document.getElementById('file-uploader').click()
|
}
|
||||||
},
|
onChange (e: any) {
|
||||||
onChange (e) {
|
this.ipcSendFiles(e.target.files);
|
||||||
this.ipcSendFiles(e.target.files)
|
(document.getElementById('file-uploader') as HTMLInputElement).value = ''
|
||||||
document.getElementById('file-uploader').value = ''
|
}
|
||||||
},
|
ipcSendFiles (files: FileList) {
|
||||||
ipcSendFiles (files) {
|
let sendFiles: IFileWithPath[] = []
|
||||||
let sendFiles = []
|
Array.from(files).forEach((item, index) => {
|
||||||
Array.from(files).forEach((item, index) => {
|
let obj = {
|
||||||
let obj = {
|
name: item.name,
|
||||||
name: item.name,
|
path: item.path
|
||||||
path: item.path
|
}
|
||||||
|
sendFiles.push(obj)
|
||||||
|
})
|
||||||
|
ipcRenderer.send('uploadChoosedFiles', sendFiles)
|
||||||
|
}
|
||||||
|
getPasteStyle () {
|
||||||
|
this.pasteStyle = this.$db.get('settings.pasteStyle') || 'markdown'
|
||||||
|
}
|
||||||
|
handlePasteStyleChange (val: string) {
|
||||||
|
this.$db.set('settings.pasteStyle', val)
|
||||||
|
}
|
||||||
|
uploadClipboardFiles () {
|
||||||
|
ipcRenderer.send('uploadClipboardFilesFromUploadPage')
|
||||||
|
}
|
||||||
|
getDefaultPicBed () {
|
||||||
|
const current: string = this.$db.get('picBed.current')
|
||||||
|
this.picBed.forEach(item => {
|
||||||
|
if (item.type === current) {
|
||||||
|
this.picBedName = item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getPicBeds (event: Event, picBeds: IPicBedType[]) {
|
||||||
|
this.picBed = picBeds
|
||||||
|
this.getDefaultPicBed()
|
||||||
|
}
|
||||||
|
handleChangePicBed () {
|
||||||
|
this.buildMenu()
|
||||||
|
// this.menu.popup(remote.getCurrentWindow())
|
||||||
|
this.menu!.popup()
|
||||||
|
}
|
||||||
|
buildMenu () {
|
||||||
|
const _this = this
|
||||||
|
const submenu = this.picBed.filter(item => item.visible).map(item => {
|
||||||
|
return {
|
||||||
|
label: item.name,
|
||||||
|
type: 'radio',
|
||||||
|
checked: this.$db.get('picBed.current') === item.type,
|
||||||
|
click () {
|
||||||
|
_this.letPicGoSaveData({
|
||||||
|
'picBed.current': item.type
|
||||||
|
})
|
||||||
|
ipcRenderer.send('syncPicBed')
|
||||||
}
|
}
|
||||||
sendFiles.push(obj)
|
}
|
||||||
})
|
})
|
||||||
this.$electron.ipcRenderer.send('uploadChoosedFiles', sendFiles)
|
// @ts-ignore
|
||||||
},
|
this.menu = Menu.buildFromTemplate(submenu)
|
||||||
getPasteStyle () {
|
|
||||||
this.pasteStyle = this.$db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
},
|
|
||||||
handlePasteStyleChange (val) {
|
|
||||||
this.$db.read().set('settings.pasteStyle', val)
|
|
||||||
.write()
|
|
||||||
},
|
|
||||||
uploadClipboardFiles () {
|
|
||||||
this.$electron.ipcRenderer.send('uploadClipboardFilesFromUploadPage')
|
|
||||||
},
|
|
||||||
getDefaultPicBed () {
|
|
||||||
const current = this.$db.read().get('picBed.current').value()
|
|
||||||
this.picBed.forEach(item => {
|
|
||||||
if (item.type === current) {
|
|
||||||
this.picBedName = item.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getPicBeds (event, picBeds) {
|
|
||||||
this.picBed = picBeds
|
|
||||||
this.getDefaultPicBed()
|
|
||||||
},
|
|
||||||
handleChangePicBed () {
|
|
||||||
this.buildMenu()
|
|
||||||
this.menu.popup(this.$electron.remote.getCurrentWindow())
|
|
||||||
},
|
|
||||||
buildMenu () {
|
|
||||||
const _this = this
|
|
||||||
const submenu = this.picBed.map(item => {
|
|
||||||
return {
|
|
||||||
label: item.name,
|
|
||||||
type: 'radio',
|
|
||||||
checked: this.$db.read().get('picBed.current').value() === item.type,
|
|
||||||
click () {
|
|
||||||
_this.$db.read().set('picBed.current', item.type).write()
|
|
||||||
_this.$electron.ipcRenderer.send('syncPicBed')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.menu = this.$electron.remote.Menu.buildFromTemplate(submenu)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -236,4 +241,6 @@ export default {
|
|||||||
border-radius 0 14px 14px 0
|
border-radius 0 14px 14px 0
|
||||||
.paste-upload
|
.paste-upload
|
||||||
width 100%
|
width 100%
|
||||||
|
.el-icon-caret-bottom
|
||||||
|
cursor pointer
|
||||||
</style>
|
</style>
|
||||||
@@ -48,6 +48,11 @@
|
|||||||
>
|
>
|
||||||
<el-input v-model="form.path" @keyup.native.enter="confirm" placeholder="例如img/"></el-input>
|
<el-input v-model="form.path" @keyup.native.enter="confirm" placeholder="例如img/"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="设定网址后缀"
|
||||||
|
>
|
||||||
|
<el-input v-model="form.options" @keyup.native.enter="confirm" placeholder="例如?x-oss-process=xxx"></el-input>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="设定自定义域名"
|
label="设定自定义域名"
|
||||||
>
|
>
|
||||||
@@ -64,47 +69,46 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import mixin from '@/utils/ConfirmButtonMixin'
|
import mixin from '@/utils/ConfirmButtonMixin'
|
||||||
export default {
|
@Component({
|
||||||
mixins: [mixin],
|
|
||||||
name: 'aliyun',
|
name: 'aliyun',
|
||||||
data () {
|
mixins: [mixin]
|
||||||
return {
|
})
|
||||||
form: {
|
export default class extends Vue {
|
||||||
accessKeyId: '',
|
form: IAliYunConfig = {
|
||||||
accessKeySecret: '',
|
accessKeyId: '',
|
||||||
bucket: '',
|
accessKeySecret: '',
|
||||||
area: '',
|
bucket: '',
|
||||||
path: '',
|
area: '',
|
||||||
customUrl: ''
|
path: '',
|
||||||
}
|
customUrl: '',
|
||||||
}
|
options: ''
|
||||||
},
|
}
|
||||||
created () {
|
created () {
|
||||||
const config = this.$db.get('picBed.aliyun').value()
|
const config = this.$db.get('picBed.aliyun') as IAliYunConfig
|
||||||
if (config) {
|
if (config) {
|
||||||
for (let i in config) {
|
this.form = Object.assign({}, config)
|
||||||
this.form[i] = config[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
methods: {
|
confirm () {
|
||||||
confirm () {
|
// @ts-ignore
|
||||||
this.$refs.aliyun.validate((valid) => {
|
this.$refs.aliyun.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$db.set('picBed.aliyun', this.form).write()
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('设置结果', {
|
'picBed.aliyun': this.form
|
||||||
body: '设置成功'
|
})
|
||||||
})
|
const successNotification = new window.Notification('设置结果', {
|
||||||
successNotification.onclick = () => {
|
body: '设置成功'
|
||||||
return true
|
})
|
||||||
}
|
successNotification.onclick = () => {
|
||||||
} else {
|
return true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -56,46 +56,44 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import mixin from '@/utils/ConfirmButtonMixin'
|
import mixin from '@/utils/ConfirmButtonMixin'
|
||||||
export default {
|
@Component({
|
||||||
name: 'github',
|
name: 'github',
|
||||||
mixins: [mixin],
|
mixins: [mixin]
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
form: {
|
form: IGitHubConfig = {
|
||||||
repo: '',
|
repo: '',
|
||||||
token: '',
|
token: '',
|
||||||
path: '',
|
path: '',
|
||||||
customUrl: '',
|
customUrl: '',
|
||||||
branch: ''
|
branch: ''
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
const config = this.$db.get('picBed.github').value()
|
const config = this.$db.get('picBed.github') as IGitHubConfig
|
||||||
if (config) {
|
if (config) {
|
||||||
for (let i in config) {
|
this.form = Object.assign({}, config)
|
||||||
this.form[i] = config[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
methods: {
|
confirm () {
|
||||||
confirm () {
|
// @ts-ignore
|
||||||
this.$refs.github.validate((valid) => {
|
this.$refs.github.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$db.set('picBed.github', this.form).write()
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('设置结果', {
|
'picBed.github': this.form
|
||||||
body: '设置成功'
|
})
|
||||||
})
|
const successNotification = new Notification('设置结果', {
|
||||||
successNotification.onclick = () => {
|
body: '设置成功'
|
||||||
return true
|
})
|
||||||
}
|
successNotification.onclick = () => {
|
||||||
} else {
|
return true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -36,43 +36,41 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import mixin from '@/utils/ConfirmButtonMixin'
|
import mixin from '@/utils/ConfirmButtonMixin'
|
||||||
export default {
|
@Component({
|
||||||
name: 'imgur',
|
name: 'imgur',
|
||||||
mixins: [mixin],
|
mixins: [mixin]
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
form: {
|
form: IImgurConfig = {
|
||||||
clientId: '',
|
clientId: '',
|
||||||
proxy: ''
|
proxy: ''
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
const config = this.$db.get('picBed.imgur').value()
|
const config = this.$db.get('picBed.imgur') as IImgurConfig
|
||||||
if (config) {
|
if (config) {
|
||||||
for (let i in config) {
|
this.form = Object.assign({}, config)
|
||||||
this.form[i] = config[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
methods: {
|
confirm () {
|
||||||
confirm () {
|
// @ts-ignore
|
||||||
this.$refs.imgur.validate((valid) => {
|
this.$refs.imgur.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$db.set('picBed.imgur', this.form).write()
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('设置结果', {
|
'picBed.imgur': this.form
|
||||||
body: '设置成功'
|
})
|
||||||
})
|
const successNotification = new Notification('设置结果', {
|
||||||
successNotification.onclick = () => {
|
body: '设置成功'
|
||||||
return true
|
})
|
||||||
}
|
successNotification.onclick = () => {
|
||||||
} else {
|
return true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -27,57 +27,65 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
import ConfigForm from '@/components/ConfigForm'
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
|
import ConfigForm from '@/components/ConfigForm.vue'
|
||||||
import mixin from '@/utils/ConfirmButtonMixin'
|
import mixin from '@/utils/ConfirmButtonMixin'
|
||||||
export default {
|
import {
|
||||||
|
ipcRenderer,
|
||||||
|
IpcRendererEvent
|
||||||
|
} from 'electron'
|
||||||
|
|
||||||
|
@Component({
|
||||||
name: 'OtherPicBed',
|
name: 'OtherPicBed',
|
||||||
mixins: [mixin],
|
mixins: [mixin],
|
||||||
components: {
|
components: {
|
||||||
ConfigForm
|
ConfigForm
|
||||||
},
|
}
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
type: '',
|
type: string = ''
|
||||||
config: [],
|
config: any[] = []
|
||||||
picBedName: ''
|
picBedName: string = ''
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
this.type = this.$route.params.type
|
this.type = this.$route.params.type
|
||||||
this.$electron.ipcRenderer.send('getPicBedConfig', this.$route.params.type)
|
ipcRenderer.send('getPicBedConfig', this.$route.params.type)
|
||||||
this.$electron.ipcRenderer.on('getPicBedConfig', this.getPicBeds)
|
ipcRenderer.on('getPicBedConfig', this.getPicBeds)
|
||||||
},
|
}
|
||||||
methods: {
|
async handleConfirm () {
|
||||||
async handleConfirm () {
|
// @ts-ignore
|
||||||
const result = await this.$refs.configForm.validate()
|
const result = await this.$refs.configForm.validate()
|
||||||
if (result !== false) {
|
if (result !== false) {
|
||||||
this.$db.read().set(`picBed.${this.type}`, result).write()
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('设置结果', {
|
[`picBed.${this.type}`]: result
|
||||||
body: '设置成功'
|
})
|
||||||
})
|
const successNotification = new Notification('设置结果', {
|
||||||
successNotification.onclick = () => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setDefaultPicBed (type) {
|
|
||||||
this.$db.read().set('picBed.current', type).write()
|
|
||||||
this.defaultPicBed = type
|
|
||||||
const successNotification = new window.Notification('设置默认图床', {
|
|
||||||
body: '设置成功'
|
body: '设置成功'
|
||||||
})
|
})
|
||||||
successNotification.onclick = () => {
|
successNotification.onclick = () => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
},
|
|
||||||
getPicBeds (event, config, name) {
|
|
||||||
this.config = config
|
|
||||||
this.picBedName = name
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
setDefaultPicBed (type: string) {
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'picBed.current': type
|
||||||
|
})
|
||||||
|
// @ts-ignore 来自mixin的数据
|
||||||
|
this.defaultPicBed = type
|
||||||
|
const successNotification = new Notification('设置默认图床', {
|
||||||
|
body: '设置成功'
|
||||||
|
})
|
||||||
|
successNotification.onclick = () => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getPicBeds (event: IpcRendererEvent, config: any[], name: string) {
|
||||||
|
this.config = config
|
||||||
|
this.picBedName = name
|
||||||
|
}
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
this.$electron.ipcRenderer.removeListener('getPicBedConfig', this.getPicBeds)
|
ipcRenderer.removeListener('getPicBedConfig', this.getPicBeds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -71,48 +71,46 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import mixin from '@/utils/ConfirmButtonMixin'
|
import mixin from '@/utils/ConfirmButtonMixin'
|
||||||
export default {
|
@Component({
|
||||||
mixins: [mixin],
|
|
||||||
name: 'qiniu',
|
name: 'qiniu',
|
||||||
data () {
|
mixins: [mixin]
|
||||||
return {
|
})
|
||||||
form: {
|
export default class extends Vue {
|
||||||
accessKey: '',
|
form: IQiniuConfig = {
|
||||||
secretKey: '',
|
accessKey: '',
|
||||||
bucket: '',
|
secretKey: '',
|
||||||
url: '',
|
bucket: '',
|
||||||
area: '',
|
url: '',
|
||||||
options: '',
|
area: '',
|
||||||
path: ''
|
options: '',
|
||||||
}
|
path: ''
|
||||||
}
|
}
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
const config = this.$db.get('picBed.qiniu').value()
|
const config = this.$db.get('picBed.qiniu') as IQiniuConfig
|
||||||
if (config) {
|
if (config) {
|
||||||
for (let i in config) {
|
this.form = Object.assign({}, config)
|
||||||
this.form[i] = config[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
methods: {
|
confirm () {
|
||||||
confirm () {
|
// @ts-ignore
|
||||||
this.$refs.qiniu.validate((valid) => {
|
this.$refs.qiniu.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$db.set('picBed.qiniu', this.form).write()
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('设置结果', {
|
'picBed.qiniu': this.form
|
||||||
body: '设置成功'
|
})
|
||||||
})
|
const successNotification = new Notification('设置结果', {
|
||||||
successNotification.onclick = () => {
|
body: '设置成功'
|
||||||
return true
|
})
|
||||||
}
|
successNotification.onclick = () => {
|
||||||
} else {
|
return true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -15,24 +15,25 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator'
|
||||||
import mixin from '@/utils/ConfirmButtonMixin'
|
import mixin from '@/utils/ConfirmButtonMixin'
|
||||||
export default {
|
@Component({
|
||||||
mixins: [mixin],
|
name: 'smms',
|
||||||
name: 'upyun',
|
mixins: [mixin]
|
||||||
data () {
|
})
|
||||||
return {}
|
export default class extends Vue {
|
||||||
},
|
confirm () {
|
||||||
methods: {
|
this.letPicGoSaveData({
|
||||||
confirm () {
|
'picBed.smms': true
|
||||||
this.$db.set('picBed.smms', true).write()
|
})
|
||||||
this.setDefaultPicBed('smms')
|
// @ts-ignore 来自mixin
|
||||||
const successNotification = new window.Notification('设置结果', {
|
this.setDefaultPicBed('smms')
|
||||||
body: '设置成功'
|
const successNotification = new window.Notification('设置结果', {
|
||||||
})
|
body: '设置成功'
|
||||||
successNotification.onclick = () => {
|
})
|
||||||
return true
|
successNotification.onclick = () => {
|
||||||
}
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||