Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9274b3f8be | ||
|
|
7809b626d3 | ||
|
|
a7995c037c | ||
|
|
85f4c67e0b | ||
|
|
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 | ||
|
|
50f31bd438 | ||
|
|
5b0d596c6d | ||
|
|
c59e2bcc97 | ||
|
|
3c6b329927 | ||
|
|
466dbec4b7 | ||
|
|
4e02244ebe | ||
|
|
748a7fd07e | ||
|
|
4000cea7c8 | ||
|
|
8978166328 | ||
|
|
7f1769733b | ||
|
|
e5fbe750ae | ||
|
|
ed539cf206 | ||
|
|
74c7016d2c | ||
|
|
407b821aca | ||
|
|
6db86ec359 | ||
|
|
c64959a139 | ||
|
|
6122e17d75 | ||
|
|
37f1d34abc | ||
|
|
3dd20857aa | ||
|
|
4a11d9830b | ||
|
|
0165879f2d | ||
|
|
17302fe3e4 | ||
|
|
f65d2d2df4 | ||
|
|
af19de7168 | ||
|
|
9ab9e1973c | ||
|
|
a4056cbe58 | ||
|
|
69d660fe7e | ||
|
|
058e903789 | ||
|
|
53cdddf44a | ||
|
|
2315aad732 | ||
|
|
7f8c6fd60e | ||
|
|
10959f3c54 | ||
|
|
1f4f40848e | ||
|
|
7ef76b0a9b | ||
|
|
f87311760a |
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
# :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)
|
||||||
|
|
||||||
|
|
||||||
|
### :sparkles: Features
|
||||||
|
|
||||||
|
* add file-name for customurl ([c59e2bc](https://github.com/Molunerfinn/PicGo/commit/c59e2bc)), closes [#173](https://github.com/Molunerfinn/PicGo/issues/173)
|
||||||
|
|
||||||
|
|
||||||
|
### :bug: Bug Fixes
|
||||||
|
|
||||||
|
* log-level filter bug ([4e02244](https://github.com/Molunerfinn/PicGo/commit/4e02244)), closes [#237](https://github.com/Molunerfinn/PicGo/issues/237)
|
||||||
|
* log-level's reset value from 'all' -> ['all'] ([3c6b329](https://github.com/Molunerfinn/PicGo/commit/3c6b329)), closes [#240](https://github.com/Molunerfinn/PicGo/issues/240) [#237](https://github.com/Molunerfinn/PicGo/issues/237)
|
||||||
|
* mini window hidden bug in linux ([466dbec](https://github.com/Molunerfinn/PicGo/commit/466dbec)), closes [#239](https://github.com/Molunerfinn/PicGo/issues/239)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## :tada: 2.1.1 (2019-04-16)
|
||||||
|
|
||||||
|
|
||||||
|
### :bug: Bug Fixes
|
||||||
|
|
||||||
|
* upload-area can't upload images ([4000cea](https://github.com/Molunerfinn/PicGo/commit/4000cea))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# :tada: 2.1.0 (2019-04-15)
|
||||||
|
|
||||||
|
|
||||||
|
### :sparkles: Features
|
||||||
|
|
||||||
|
* add commandline argvs support for picgo app ([6db86ec](https://github.com/Molunerfinn/PicGo/commit/6db86ec))
|
||||||
|
* add gui-api for remove event ([407b821](https://github.com/Molunerfinn/PicGo/commit/407b821)), closes [#201](https://github.com/Molunerfinn/PicGo/issues/201)
|
||||||
|
* add windows context menu ([e5fbe75](https://github.com/Molunerfinn/PicGo/commit/e5fbe75))
|
||||||
|
* add workflow for mac ([7f17697](https://github.com/Molunerfinn/PicGo/commit/7f17697))
|
||||||
|
* support commandline -> upload images in clipboard ([74c7016](https://github.com/Molunerfinn/PicGo/commit/74c7016))
|
||||||
|
|
||||||
|
|
||||||
|
### :bug: Bug Fixes
|
||||||
|
|
||||||
|
* qiniu area option from select group -> input ([c64959a](https://github.com/Molunerfinn/PicGo/commit/c64959a)), closes [#230](https://github.com/Molunerfinn/PicGo/issues/230)
|
||||||
|
|
||||||
|
|
||||||
|
### :pencil: Documentation
|
||||||
|
|
||||||
|
* add brew cask source ([6122e17](https://github.com/Molunerfinn/PicGo/commit/6122e17))
|
||||||
|
|
||||||
|
|
||||||
|
### :package: Chore
|
||||||
|
|
||||||
|
* add picgo bump-version ([37f1d34](https://github.com/Molunerfinn/PicGo/commit/37f1d34))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,8 +1,21 @@
|
|||||||
MIT License
|
The MIT License (MIT)
|
||||||
Copyright (c) <year> <copyright holders>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal 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:
|
Copyright (c) 2017-present, Molunerfinn
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
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 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.
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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>
|
||||||
@@ -18,43 +14,50 @@
|
|||||||
<a href="https://github.com/Molunerfinn/PicGo/releases/latest">
|
<a href="https://github.com/Molunerfinn/PicGo/releases/latest">
|
||||||
<img src="https://img.shields.io/github/release/Molunerfinn/PicGo.svg?style=flat-square" alt="">
|
<img src="https://img.shields.io/github/release/Molunerfinn/PicGo.svg?style=flat-square" alt="">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
<a href="https://github.com/PicGo/bump-version">
|
||||||
|
<img src="https://img.shields.io/badge/picgo-convention-blue.svg?style=flat-square" alt="">
|
||||||
|
</a>
|
||||||
|
</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)。**
|
||||||
|
|
||||||
## 下载安装
|
## 下载安装
|
||||||
|
|
||||||
macOS用户请下载最新版本的`dmg`文件,windows用户请下载最新版本的`exe`文件,linux用户请下载`AppImage`文件。
|
|
||||||
|
|
||||||
点击此处下载[应用](https://github.com/Molunerfinn/PicGo/releases)。
|
点击此处下载[应用](https://github.com/Molunerfinn/PicGo/releases)。
|
||||||
|
|
||||||
**如果你是Arch类的Linux用户,可以直接通过`aurman -S picgo-appimage`来安装PicGo。感谢@houbaron的贡献!**
|
macOS 用户请下载最新版本的 `dmg` 文件,Windows 用户请下载最新版本的 `exe` 文件,Linux用户请下载 `AppImage` 文件。
|
||||||
|
|
||||||
|
**如果你是 Arch 类的 Linux 用户,可以直接通过 `aurman -S picgo-appimage` 来安装 PicGo。感谢 @houbaron 的贡献!**
|
||||||
|
|
||||||
|
**如果你是 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 的贡献!**
|
||||||
|
|
||||||
## 应用截图
|
## 应用截图
|
||||||
|
|
||||||
@@ -64,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 # 退出开发模式
|
||||||
@@ -86,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'
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
!macro preInit
|
!macro customInstall
|
||||||
SetRegView 64
|
SetRegView 64
|
||||||
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\PicGo"
|
WriteRegStr HKCR "*\shell\PicGo" "" "Upload pictures w&ith PicGo"
|
||||||
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\PicGo"
|
WriteRegStr HKCR "*\shell\PicGo" "Icon" "$INSTDIR\PicGo.exe"
|
||||||
SetRegView 32
|
WriteRegStr HKCR "*\shell\PicGo\command" "" '"$INSTDIR\PicGo.exe" "upload" "%1"'
|
||||||
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\PicGo"
|
SetRegView 32
|
||||||
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\PicGo"
|
WriteRegStr HKCR "*\shell\PicGo" "" "Upload pictures w&ith PicGo"
|
||||||
!macroend
|
WriteRegStr HKCR "*\shell\PicGo" "Icon" "$INSTDIR\PicGo.exe"
|
||||||
|
WriteRegStr HKCR "*\shell\PicGo\command" "" '"$INSTDIR\PicGo.exe" "upload" "%1"'
|
||||||
|
!macroend
|
||||||
|
!macro customUninstall
|
||||||
|
DeleteRegKey HKCR "*\shell\PicGo"
|
||||||
|
!macroend
|
||||||
|
|||||||
@@ -7,16 +7,16 @@
|
|||||||
small(v-if="version") {{ version }}
|
small(v-if="version") {{ version }}
|
||||||
h2.desc 图片上传+管理新体验
|
h2.desc 图片上传+管理新体验
|
||||||
button.download(@click="goLink('https://github.com/Molunerfinn/picgo/releases')") 免费下载
|
button.download(@click="goLink('https://github.com/Molunerfinn/picgo/releases')") 免费下载
|
||||||
button.download(@click="goLink('https://github.com/Molunerfinn/picgo')") 在github上查看
|
button.download(@click="goLink('https://picgo.github.io/PicGo-Doc/zh/guide/')") 查看文档
|
||||||
h3.desc
|
h3.desc
|
||||||
| 基于#[a(href="https://github.com/SimulatedGREG/electron-vue" target="_blank") electron-vue]开发
|
| 基于#[a(href="https://github.com/SimulatedGREG/electron-vue" target="_blank") electron-vue]开发
|
||||||
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,159 +1,83 @@
|
|||||||
{
|
{
|
||||||
"name": "picgo",
|
"name": "picgo",
|
||||||
"version": "2.0.3",
|
"version": "2.2.0",
|
||||||
"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",
|
"cz": "git-cz",
|
||||||
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src test",
|
"bump": "bump-version",
|
||||||
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src test",
|
"release": "vue-cli-service electron:build --publish always"
|
||||||
"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"
|
|
||||||
},
|
},
|
||||||
"build": {
|
"main": "background.js",
|
||||||
"productName": "PicGo",
|
"husky": {
|
||||||
"appId": "com.molunerfinn.picgo",
|
"hooks": {
|
||||||
"directories": {
|
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||||
"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/"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"config": {
|
||||||
|
"commitizen": {
|
||||||
|
"path": "./node_modules/cz-customizable"
|
||||||
|
},
|
||||||
|
"cz-customizable": {
|
||||||
|
"config": "./node_modules/@picgo/bump-version/.cz-config.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"commitlint": {
|
||||||
|
"extends": [
|
||||||
|
"./node_modules/@picgo/bump-version/commitlint-picgo"
|
||||||
|
]
|
||||||
|
},
|
||||||
"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.2.4",
|
"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": {
|
||||||
"babel-core": "^6.25.0",
|
"@commitlint/cli": "^8.2.0",
|
||||||
"babel-eslint": "^7.2.3",
|
"@picgo/bump-version": "^1.0.3",
|
||||||
"babel-loader": "^7.1.1",
|
"@types/fs-extra": "^8.0.1",
|
||||||
"babel-plugin-istanbul": "^4.1.1",
|
"@types/inquirer": "^6.5.0",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"@types/lowdb": "^1.0.9",
|
||||||
"babel-preset-env": "^1.6.0",
|
"@types/node": "10.17.6",
|
||||||
"babel-preset-stage-0": "^6.24.1",
|
"@types/request-promise-native": "^1.0.17",
|
||||||
"babel-register": "^6.24.1",
|
"@vue/cli-plugin-babel": "^4.0.0",
|
||||||
"babili-webpack-plugin": "^0.1.2",
|
"@vue/cli-plugin-eslint": "^4.0.0",
|
||||||
"cfonts": "^1.1.3",
|
"@vue/cli-plugin-router": "^4.0.0",
|
||||||
"chai": "^4.0.0",
|
"@vue/cli-plugin-typescript": "^4.0.0",
|
||||||
"chalk": "^2.1.0",
|
"@vue/cli-service": "^4.0.0",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"@vue/eslint-config-standard": "^4.0.0",
|
||||||
"cross-env": "^5.0.5",
|
"@vue/eslint-config-typescript": "^4.0.0",
|
||||||
"css-loader": "^0.28.4",
|
"commitizen": "^4.0.3",
|
||||||
"del": "^3.0.0",
|
"conventional-changelog": "^3.1.18",
|
||||||
"devtron": "^1.4.0",
|
"cz-customizable": "^6.2.0",
|
||||||
"electron": "4.0.2",
|
"electron": "^6.0.0",
|
||||||
"electron-builder": "^20.38.4",
|
"eslint": "^5.16.0",
|
||||||
"electron-debug": "^1.4.0",
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
"electron-devtools-installer": "^2.2.0",
|
"husky": "^3.1.0",
|
||||||
"eslint": "^4.4.1",
|
"stylus": "^0.54.7",
|
||||||
"eslint-config-standard": "^10.2.1",
|
"stylus-loader": "^3.0.2",
|
||||||
"eslint-friendly-formatter": "^3.0.0",
|
"typescript": "~3.7.3",
|
||||||
"eslint-loader": "^2.1.1",
|
"vue-cli-plugin-electron-builder": "^1.4.2",
|
||||||
"eslint-plugin-html": "^3.1.1",
|
"vue-property-decorator": "^8.3.0",
|
||||||
"eslint-plugin-import": "^2.7.0",
|
"vue-template-compiler": "^2.6.10"
|
||||||
"eslint-plugin-node": "^5.1.1",
|
},
|
||||||
"eslint-plugin-promise": "^3.5.0",
|
"resolutions": {
|
||||||
"eslint-plugin-standard": "^3.0.1",
|
"@types/node": "12.0.2"
|
||||||
"file-loader": "^3.0.1",
|
|
||||||
"html-webpack-plugin": "^3.2.0",
|
|
||||||
"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: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSServices</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSBackgroundColorName</key>
|
||||||
|
<string>background</string>
|
||||||
|
<key>NSBackgroundSystemColorName</key>
|
||||||
|
<string>systemBlueColor</string>
|
||||||
|
<key>NSIconName</key>
|
||||||
|
<string>NSTouchBarShare</string>
|
||||||
|
<key>NSMenuItem</key>
|
||||||
|
<dict>
|
||||||
|
<key>default</key>
|
||||||
|
<string>Upload pictures with PicGo</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSMessage</key>
|
||||||
|
<string>runWorkflowAsService</string>
|
||||||
|
<key>NSRequiredContext</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSApplicationIdentifier</key>
|
||||||
|
<string>com.apple.finder</string>
|
||||||
|
</dict>
|
||||||
|
<key>NSSendFileTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>public.image</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,314 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>AMApplicationBuild</key>
|
||||||
|
<string>444.42</string>
|
||||||
|
<key>AMApplicationVersion</key>
|
||||||
|
<string>2.9</string>
|
||||||
|
<key>AMDocumentVersion</key>
|
||||||
|
<string>2</string>
|
||||||
|
<key>actions</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>action</key>
|
||||||
|
<dict>
|
||||||
|
<key>AMAccepts</key>
|
||||||
|
<dict>
|
||||||
|
<key>Container</key>
|
||||||
|
<string>List</string>
|
||||||
|
<key>Optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>Types</key>
|
||||||
|
<array>
|
||||||
|
<string>com.apple.cocoa.string</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<key>AMActionVersion</key>
|
||||||
|
<string>2.0.3</string>
|
||||||
|
<key>AMApplication</key>
|
||||||
|
<array>
|
||||||
|
<string>自动操作</string>
|
||||||
|
</array>
|
||||||
|
<key>AMParameterProperties</key>
|
||||||
|
<dict>
|
||||||
|
<key>COMMAND_STRING</key>
|
||||||
|
<dict/>
|
||||||
|
<key>CheckedForUserDefaultShell</key>
|
||||||
|
<dict/>
|
||||||
|
<key>inputMethod</key>
|
||||||
|
<dict/>
|
||||||
|
<key>shell</key>
|
||||||
|
<dict/>
|
||||||
|
<key>source</key>
|
||||||
|
<dict/>
|
||||||
|
</dict>
|
||||||
|
<key>AMProvides</key>
|
||||||
|
<dict>
|
||||||
|
<key>Container</key>
|
||||||
|
<string>List</string>
|
||||||
|
<key>Types</key>
|
||||||
|
<array>
|
||||||
|
<string>com.apple.cocoa.string</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<key>ActionBundlePath</key>
|
||||||
|
<string>/System/Library/Automator/Run Shell Script.action</string>
|
||||||
|
<key>ActionName</key>
|
||||||
|
<string>运行 Shell 脚本</string>
|
||||||
|
<key>ActionParameters</key>
|
||||||
|
<dict>
|
||||||
|
<key>COMMAND_STRING</key>
|
||||||
|
<string>/Applications/PicGo.app/Contents/MacOS/PicGo upload "$@" > /dev/null 2>&1 &</string>
|
||||||
|
<key>CheckedForUserDefaultShell</key>
|
||||||
|
<true/>
|
||||||
|
<key>inputMethod</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>shell</key>
|
||||||
|
<string>/bin/bash</string>
|
||||||
|
<key>source</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
<key>BundleIdentifier</key>
|
||||||
|
<string>com.apple.RunShellScript</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>2.0.3</string>
|
||||||
|
<key>CanShowSelectedItemsWhenRun</key>
|
||||||
|
<false/>
|
||||||
|
<key>CanShowWhenRun</key>
|
||||||
|
<true/>
|
||||||
|
<key>Category</key>
|
||||||
|
<array>
|
||||||
|
<string>AMCategoryUtilities</string>
|
||||||
|
</array>
|
||||||
|
<key>Class Name</key>
|
||||||
|
<string>RunShellScriptAction</string>
|
||||||
|
<key>InputUUID</key>
|
||||||
|
<string>79609224-28DD-4ADE-AA8F-5A6C68C18C18</string>
|
||||||
|
<key>Keywords</key>
|
||||||
|
<array>
|
||||||
|
<string>Shell</string>
|
||||||
|
<string>脚本</string>
|
||||||
|
<string>命令</string>
|
||||||
|
<string>运行</string>
|
||||||
|
<string>Unix</string>
|
||||||
|
</array>
|
||||||
|
<key>OutputUUID</key>
|
||||||
|
<string>35CD6B4C-A616-4F89-8D76-DCD3249C5B4E</string>
|
||||||
|
<key>UUID</key>
|
||||||
|
<string>4350A83B-E7E6-4D2B-9768-B1D676CF58F3</string>
|
||||||
|
<key>UnlocalizedApplications</key>
|
||||||
|
<array>
|
||||||
|
<string>Automator</string>
|
||||||
|
</array>
|
||||||
|
<key>arguments</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>default value</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>name</key>
|
||||||
|
<string>inputMethod</string>
|
||||||
|
<key>required</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>type</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>0</string>
|
||||||
|
</dict>
|
||||||
|
<key>1</key>
|
||||||
|
<dict>
|
||||||
|
<key>default value</key>
|
||||||
|
<string></string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>source</string>
|
||||||
|
<key>required</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>type</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
<key>2</key>
|
||||||
|
<dict>
|
||||||
|
<key>default value</key>
|
||||||
|
<false/>
|
||||||
|
<key>name</key>
|
||||||
|
<string>CheckedForUserDefaultShell</string>
|
||||||
|
<key>required</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>type</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>2</string>
|
||||||
|
</dict>
|
||||||
|
<key>3</key>
|
||||||
|
<dict>
|
||||||
|
<key>default value</key>
|
||||||
|
<string></string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>COMMAND_STRING</string>
|
||||||
|
<key>required</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>type</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>3</string>
|
||||||
|
</dict>
|
||||||
|
<key>4</key>
|
||||||
|
<dict>
|
||||||
|
<key>default value</key>
|
||||||
|
<string>/bin/sh</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>shell</string>
|
||||||
|
<key>required</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>type</key>
|
||||||
|
<string>0</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>isViewVisible</key>
|
||||||
|
<true/>
|
||||||
|
<key>location</key>
|
||||||
|
<string>449.000000:305.000000</string>
|
||||||
|
<key>nibPath</key>
|
||||||
|
<string>/System/Library/Automator/Run Shell Script.action/Contents/Resources/Base.lproj/main.nib</string>
|
||||||
|
</dict>
|
||||||
|
<key>isViewVisible</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>connectors</key>
|
||||||
|
<dict/>
|
||||||
|
<key>workflowMetaData</key>
|
||||||
|
<dict>
|
||||||
|
<key>applicationBundleID</key>
|
||||||
|
<string>com.apple.finder</string>
|
||||||
|
<key>applicationBundleIDsByPath</key>
|
||||||
|
<dict>
|
||||||
|
<key>/System/Library/CoreServices/Finder.app</key>
|
||||||
|
<string>com.apple.finder</string>
|
||||||
|
</dict>
|
||||||
|
<key>applicationPath</key>
|
||||||
|
<string>/System/Library/CoreServices/Finder.app</string>
|
||||||
|
<key>applicationPaths</key>
|
||||||
|
<array>
|
||||||
|
<string>/System/Library/CoreServices/Finder.app</string>
|
||||||
|
</array>
|
||||||
|
<key>backgroundColor</key>
|
||||||
|
<data>
|
||||||
|
YnBsaXN0MDDUAQIDBAUGNjdYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVy
|
||||||
|
VCR0b3ASAAGGoKoHCBMUFR4kKC8zVSRudWxs1QkKCwwNDg8QERJWJGNsYXNz
|
||||||
|
W05TQ29sb3JOYW1lXE5TQ29sb3JTcGFjZV1OU0NhdGFsb2dOYW1lV05TQ29s
|
||||||
|
b3KACYADEAaAAoAEVlN5c3RlbV8QD3N5c3RlbUJsdWVDb2xvctUWFwsYCRka
|
||||||
|
GxwOXE5TQ29tcG9uZW50c1VOU1JHQl8QEk5TQ3VzdG9tQ29sb3JTcGFjZUcw
|
||||||
|
IDAgMSAxTxARMCAwIDAuOTk4MTg4OTcyNQAQAYAFgAnTHyAJISIjVE5TSURV
|
||||||
|
TlNJQ0MQB4AGgAjSJQkmJ1dOUy5kYXRhTxEMSAAADEhMaW5vAhAAAG1udHJS
|
||||||
|
R0IgWFlaIAfOAAIACQAGADEAAGFjc3BNU0ZUAAAAAElFQyBzUkdCAAAAAAAA
|
||||||
|
AAAAAAAAAAD21gABAAAAANMtSFAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEWNwcnQAAAFQAAAAM2Rlc2MAAAGE
|
||||||
|
AAAAbHd0cHQAAAHwAAAAFGJrcHQAAAIEAAAAFHJYWVoAAAIYAAAAFGdYWVoA
|
||||||
|
AAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJUAAAAcGRtZGQAAALEAAAAiHZ1
|
||||||
|
ZWQAAANMAAAAhnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAAFG1lYXMAAAQMAAAA
|
||||||
|
JHRlY2gAAAQwAAAADHJUUkMAAAQ8AAAIDGdUUkMAAAQ8AAAIDGJUUkMAAAQ8
|
||||||
|
AAAIDHRleHQAAAAAQ29weXJpZ2h0IChjKSAxOTk4IEhld2xldHQtUGFja2Fy
|
||||||
|
ZCBDb21wYW55AABkZXNjAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAA
|
||||||
|
AAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EAAQAA
|
||||||
|
AAEWzFhZWiAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAG+iAAA49QAAA5BY
|
||||||
|
WVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QAALbPZGVzYwAA
|
||||||
|
AAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAWSUVDIGh0
|
||||||
|
dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVm
|
||||||
|
YXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAALklFQyA2
|
||||||
|
MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAACxSZWZlcmVuY2UgVmlld2lu
|
||||||
|
ZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAsUmVmZXJl
|
||||||
|
bmNlIFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAdmlldwAAAAAAE6T+ABRfLgAQzxQAA+3MAAQT
|
||||||
|
CwADXJ4AAAABWFlaIAAAAAAATAlWAFAAAABXH+dtZWFzAAAAAAAAAAEAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAACjwAAAAJzaWcgAAAAAENSVCBjdXJ2AAAAAAAABAAA
|
||||||
|
AAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABt
|
||||||
|
AHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA
|
||||||
|
4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFn
|
||||||
|
AW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQC
|
||||||
|
HQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1
|
||||||
|
AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kE
|
||||||
|
BgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6
|
||||||
|
BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0G
|
||||||
|
rwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgLCB8IMghG
|
||||||
|
CFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEK
|
||||||
|
Jwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwq
|
||||||
|
DEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQO
|
||||||
|
fw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1
|
||||||
|
ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QT
|
||||||
|
xRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxay
|
||||||
|
FtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0a
|
||||||
|
BBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1w
|
||||||
|
HZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDwIRwh
|
||||||
|
SCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4
|
||||||
|
JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWsp
|
||||||
|
nSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4W
|
||||||
|
Lkwugi63Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQz
|
||||||
|
DTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgU
|
||||||
|
OFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0iPWE9
|
||||||
|
oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6
|
||||||
|
Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1J
|
||||||
|
Y0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+T
|
||||||
|
T91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9W
|
||||||
|
XFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0n
|
||||||
|
XXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBk
|
||||||
|
lGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/
|
||||||
|
bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0
|
||||||
|
FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwh
|
||||||
|
fIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE
|
||||||
|
44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Y
|
||||||
|
jf+OZo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+X
|
||||||
|
Cpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBp
|
||||||
|
oNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyq
|
||||||
|
j6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSc
|
||||||
|
tRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/
|
||||||
|
er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4
|
||||||
|
yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V
|
||||||
|
0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE
|
||||||
|
4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHt
|
||||||
|
nO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH
|
||||||
|
+lf65/t3/Af8mP0p/br+S/7c/23//4AH0ikqKyxaJGNsYXNzbmFtZVgkY2xh
|
||||||
|
c3Nlc11OU011dGFibGVEYXRhoystLlZOU0RhdGFYTlNPYmplY3TSKSowMVxO
|
||||||
|
U0NvbG9yU3BhY2WiMi5cTlNDb2xvclNwYWNl0ikqNDVXTlNDb2xvcqI0Ll8Q
|
||||||
|
D05TS2V5ZWRBcmNoaXZlctE4OVRyb290gAEACAARABoAIwAtADIANwBCAEgA
|
||||||
|
UwBaAGYAcwCBAIkAiwCNAI8AkQCTAJoArAC3AMQAygDfAOcA+wD9AP8BAQEI
|
||||||
|
AQ0BEwEVARcBGQEeASYNcg10DXkNhA2NDZsNnw2mDa8NtA3BDcQN0Q3WDd4N
|
||||||
|
4Q3zDfYN+wAAAAAAAAIBAAAAAAAAADoAAAAAAAAAAAAAAAAAAA39
|
||||||
|
</data>
|
||||||
|
<key>backgroundColorName</key>
|
||||||
|
<string>systemBlueColor</string>
|
||||||
|
<key>inputTypeIdentifier</key>
|
||||||
|
<string>com.apple.Automator.fileSystemObject.image</string>
|
||||||
|
<key>outputTypeIdentifier</key>
|
||||||
|
<string>com.apple.Automator.nothing</string>
|
||||||
|
<key>presentationMode</key>
|
||||||
|
<integer>15</integer>
|
||||||
|
<key>processesInput</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>serviceApplicationBundleID</key>
|
||||||
|
<string>com.apple.finder</string>
|
||||||
|
<key>serviceApplicationPath</key>
|
||||||
|
<string>/System/Library/CoreServices/Finder.app</string>
|
||||||
|
<key>serviceInputTypeIdentifier</key>
|
||||||
|
<string>com.apple.Automator.fileSystemObject.image</string>
|
||||||
|
<key>serviceOutputTypeIdentifier</key>
|
||||||
|
<string>com.apple.Automator.nothing</string>
|
||||||
|
<key>serviceProcessesInput</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>systemImageName</key>
|
||||||
|
<string>NSTouchBarShare</string>
|
||||||
|
<key>useAutomaticInputType</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>workflowTypeIdentifier</key>
|
||||||
|
<string>com.apple.Automator.servicesMenu</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
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>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# require xclip(see http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212)
|
||||||
|
command -v xclip >/dev/null 2>&1 || { echo >&1 "no xclip"; exit 1; }
|
||||||
|
|
||||||
|
# write image in clipboard to file (see http://unix.stackexchange.com/questions/145131/copy-image-from-clipboard-to-file)
|
||||||
|
filePath=`xclip -selection clipboard -o 2>/dev/null | grep ^file:// | cut -c8-`
|
||||||
|
if [ ! -n "$filePath" ] ;then
|
||||||
|
if
|
||||||
|
xclip -selection clipboard -target image/png -o >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
xclip -selection clipboard -target image/png -o >$1 2>/dev/null
|
||||||
|
echo $1
|
||||||
|
else
|
||||||
|
echo "no image"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo $filePath
|
||||||
|
fi
|
||||||
|
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,44 @@
|
|||||||
|
# Adapted from https://github.com/octan3/img-clipboard-dump/blob/master/dump-clipboard-png.ps1
|
||||||
|
param($imagePath)
|
||||||
|
|
||||||
|
# https://github.com/PowerShell/PowerShell/issues/7233
|
||||||
|
# fix the output encoding bug
|
||||||
|
[console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
|
||||||
|
|
||||||
|
Add-Type -Assembly PresentationCore
|
||||||
|
function main {
|
||||||
|
$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
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
# For WIN10
|
||||||
|
$file = Get-Clipboard -Format FileDropList
|
||||||
|
if ($file -ne $null) {
|
||||||
|
Convert-Path $file
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
# For WIN7 WIN8 WIN10
|
||||||
|
main
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
@@ -0,0 +1,743 @@
|
|||||||
|
'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/utils/picgo'
|
||||||
|
import uploader from '~/main/utils/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/shortKeyUpdateHelper'
|
||||||
|
import shortKeyHandler from '~/main/utils/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
|
||||||
|
} from '~/main/utils/busApi/constants'
|
||||||
|
import server from '~/main/server/index'
|
||||||
|
|
||||||
|
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||||
|
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
|
||||||
|
|
||||||
|
beforeOpen()
|
||||||
|
|
||||||
|
let window: BrowserWindow | null
|
||||||
|
let settingWindow: BrowserWindow | null
|
||||||
|
let miniWindow: BrowserWindow | null
|
||||||
|
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 (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',
|
||||||
|
// @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 (window) {
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
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', () => {
|
||||||
|
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 imgs = await uploader.setWebContents(window!.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])
|
||||||
|
}
|
||||||
|
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: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
nodeIntegrationInWorker: true,
|
||||||
|
backgroundThrottling: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
window.loadURL(winURL)
|
||||||
|
|
||||||
|
window.on('closed', () => {
|
||||||
|
window = null
|
||||||
|
})
|
||||||
|
|
||||||
|
window.on('blur', () => {
|
||||||
|
window!.hide()
|
||||||
|
})
|
||||||
|
return window
|
||||||
|
}
|
||||||
|
|
||||||
|
const createMiniWindow = () => {
|
||||||
|
if (miniWindow || process.platform === 'darwin') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
miniWindow = new BrowserWindow(obj)
|
||||||
|
|
||||||
|
miniWindow.loadURL(miniWinURL)
|
||||||
|
|
||||||
|
miniWindow.on('closed', () => {
|
||||||
|
miniWindow = null
|
||||||
|
})
|
||||||
|
return miniWindow
|
||||||
|
}
|
||||||
|
|
||||||
|
const createSettingWindow = () => {
|
||||||
|
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`
|
||||||
|
}
|
||||||
|
settingWindow = new BrowserWindow(options)
|
||||||
|
|
||||||
|
settingWindow!.loadURL(settingWinURL)
|
||||||
|
|
||||||
|
settingWindow!.on('closed', () => {
|
||||||
|
bus.emit('toggleShortKeyModifiedMode', false)
|
||||||
|
settingWindow = null
|
||||||
|
if (process.platform === 'linux') {
|
||||||
|
process.nextTick(() => {
|
||||||
|
app.quit()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
createMenu()
|
||||||
|
createMiniWindow()
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
// @ts-ignore
|
||||||
|
menu = Menu.buildFromTemplate(template)
|
||||||
|
Menu.setApplicationMenu(menu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleWindow = (bounds: IBounds) => {
|
||||||
|
if (window!.isVisible()) {
|
||||||
|
window!.hide()
|
||||||
|
} else {
|
||||||
|
showWindow(bounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const showWindow = (bounds: IBounds) => {
|
||||||
|
window!.setPosition(bounds.x - 98 + 11, bounds.y, false)
|
||||||
|
window!.webContents.send('updateFiles')
|
||||||
|
window!.show()
|
||||||
|
window!.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadClipboardFiles = async (): Promise<string> => {
|
||||||
|
const win = getAvailableWindow()
|
||||||
|
let img = await uploader.setWebContents(win!.webContents).upload()
|
||||||
|
if (img !== false) {
|
||||||
|
if (img.length > 0) {
|
||||||
|
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])
|
||||||
|
window!.webContents.send('clipboardFiles', [])
|
||||||
|
window!.webContents.send('uploadFiles', img)
|
||||||
|
if (settingWindow) {
|
||||||
|
settingWindow.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)
|
||||||
|
window!.webContents.send('uploadFiles', imgs)
|
||||||
|
if (settingWindow) {
|
||||||
|
settingWindow.webContents.send('updateGallery')
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
picgoCoreIPC()
|
||||||
|
|
||||||
|
// from macOS tray
|
||||||
|
ipcMain.on('uploadClipboardFiles', async () => {
|
||||||
|
const img = await uploader.setWebContents(window!.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])
|
||||||
|
window!.webContents.send('clipboardFiles', [])
|
||||||
|
if (settingWindow) {
|
||||||
|
settingWindow.webContents.send('updateGallery')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window!.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', () => {
|
||||||
|
if (!settingWindow) {
|
||||||
|
createSettingWindow()
|
||||||
|
} else {
|
||||||
|
settingWindow.show()
|
||||||
|
}
|
||||||
|
if (miniWindow) {
|
||||||
|
miniWindow.hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('openMiniWindow', () => {
|
||||||
|
if (!miniWindow) {
|
||||||
|
createMiniWindow()
|
||||||
|
}
|
||||||
|
miniWindow!.show()
|
||||||
|
miniWindow!.focus()
|
||||||
|
settingWindow!.hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
// from mini window
|
||||||
|
ipcMain.on('syncPicBed', () => {
|
||||||
|
if (settingWindow) {
|
||||||
|
settingWindow.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 = getAvailableWindow()
|
||||||
|
uploadChoosedFiles(win.webContents, files)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (settingWindow) {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createWindow()
|
||||||
|
createSettingWindow()
|
||||||
|
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 = getAvailableWindow()
|
||||||
|
uploadChoosedFiles(win.webContents, files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
createProtocol('picgo')
|
||||||
|
if (window === null) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
if (settingWindow === null) {
|
||||||
|
createSettingWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
for (let i in eventList) {
|
||||||
|
bus.on(i, eventList[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAvailableWindow () {
|
||||||
|
let win
|
||||||
|
if (miniWindow && miniWindow.isVisible()) {
|
||||||
|
win = miniWindow
|
||||||
|
} else {
|
||||||
|
win = settingWindow || window || createSettingWindow()
|
||||||
|
}
|
||||||
|
return win
|
||||||
|
}
|
||||||
|
|
||||||
|
async function busCallUploadClipboardFiles () {
|
||||||
|
const imgUrl = await uploadClipboardFiles()
|
||||||
|
bus.emit(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, imgUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function busCallUploadFiles (pathList: IFileWithPath[]) {
|
||||||
|
const win = getAvailableWindow()
|
||||||
|
const urls = await uploadChoosedFiles(win.webContents, pathList)
|
||||||
|
bus.emit(UPLOAD_WITH_FILES_RESPONSE, urls)
|
||||||
|
}
|
||||||
|
|
||||||
|
function busCallGetWindowId () {
|
||||||
|
const win = getAvailableWindow()
|
||||||
|
bus.emit(GET_WINDOW_ID_REPONSE, win.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function busCallGetSettingWindowId () {
|
||||||
|
if (!settingWindow) createSettingWindow()
|
||||||
|
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,52 +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
|
|
||||||
if (!fs.pathExistsSync(path.join(STORE_PATH, 'windows.ps1'))) {
|
|
||||||
fs.copySync(path.join(__static, '/linux.sh'), path.join(STORE_PATH, '/linux.sh'))
|
|
||||||
fs.copySync(path.join(__static, '/mac.applescript'), path.join(STORE_PATH, '/mac.applescript'))
|
|
||||||
fs.copySync(path.join(__static, '/windows.ps1'), path.join(STORE_PATH, '/windows.ps1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
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')
|
||||||
@@ -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,565 +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 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'
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
const url = imgs[i].url || imgs[i].imgUrl
|
|
||||||
clipboard.writeText(pasteTemplate(pasteStyle, url))
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const createMiniWidow = () => {
|
|
||||||
if (miniWindow) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let obj = {
|
|
||||||
height: 64,
|
|
||||||
width: 64,
|
|
||||||
show: true,
|
|
||||||
frame: false,
|
|
||||||
fullscreenable: false,
|
|
||||||
skipTaskbar: true,
|
|
||||||
resizable: false,
|
|
||||||
transparent: true,
|
|
||||||
icon: `${__static}/logo.png`,
|
|
||||||
webPreferences: {
|
|
||||||
backgroundThrottling: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
|
||||||
obj.transparent = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
obj.show = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (db.read().get('settings.miniWindowOntop').value()) {
|
|
||||||
obj.alwaysOnTop = true
|
|
||||||
}
|
|
||||||
|
|
||||||
miniWindow = new BrowserWindow(obj)
|
|
||||||
|
|
||||||
miniWindow.loadURL(miniWinURL)
|
|
||||||
|
|
||||||
miniWindow.on('closed', () => {
|
|
||||||
miniWindow = null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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'
|
|
||||||
const url = img[0].url || img[0].imgUrl
|
|
||||||
clipboard.writeText(pasteTemplate(pasteStyle, url))
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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'
|
|
||||||
const url = img[0].url || img[0].imgUrl
|
|
||||||
clipboard.writeText(pasteTemplate(pasteStyle, url))
|
|
||||||
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) => {
|
|
||||||
const input = files.map(item => item.path)
|
|
||||||
const imgs = await new Uploader(input, evt.sender).upload()
|
|
||||||
if (imgs !== false) {
|
|
||||||
const pasteStyle = db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
let pasteText = ''
|
|
||||||
for (let i in imgs) {
|
|
||||||
const url = imgs[i].url || imgs[i].imgUrl
|
|
||||||
pasteText += pasteTemplate(pasteStyle, url) + '\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')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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,90 @@
|
|||||||
|
import http from 'http'
|
||||||
|
import routers from './routerManager'
|
||||||
|
import {
|
||||||
|
handleResponse
|
||||||
|
} from './utils'
|
||||||
|
import picgo from '~/main/utils/picgo'
|
||||||
|
import logger from '~/main/utils/logger'
|
||||||
|
|
||||||
|
class Server {
|
||||||
|
private httpServer: http.Server
|
||||||
|
private config: IServerConfig
|
||||||
|
constructor () {
|
||||||
|
this.config = picgo.getConfig('settings.server') || {
|
||||||
|
port: 36677,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
enable: true
|
||||||
|
}
|
||||||
|
this.httpServer = http.createServer(this.handleRequest)
|
||||||
|
}
|
||||||
|
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.port': this.config.port
|
||||||
|
})
|
||||||
|
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/utils/busApi/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()
|
||||||
|
}
|
||||||
@@ -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,8 @@
|
|||||||
|
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'
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import bus from '../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,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,19 @@
|
|||||||
|
import picgo from './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 {
|
||||||
|
getPicBeds
|
||||||
|
}
|
||||||
@@ -1,105 +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) {
|
|
||||||
const url = imgs[i].url || imgs[i].imgUrl
|
|
||||||
pasteText += pasteTemplate(pasteStyle, url) + '\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) {
|
|
||||||
if (options === undefined) {
|
|
||||||
options = {
|
|
||||||
title: '',
|
|
||||||
body: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const notification = new Notification({
|
|
||||||
title: options.title,
|
|
||||||
body: options.body
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GuiApi
|
|
||||||
@@ -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/utils/busApi'
|
||||||
|
|
||||||
|
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,41 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
type ClipboardFileObject = {
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
type Result = ClipboardFileObject[]
|
||||||
|
const getUploadFiles = (argv = process.argv, cwd = process.cwd()) => {
|
||||||
|
let files = argv.slice(1)
|
||||||
|
if (files.length > 0 && files[0] === 'upload') {
|
||||||
|
if (files.length === 1) {
|
||||||
|
return null // for uploading images in clipboard
|
||||||
|
} else if (files.length > 1) {
|
||||||
|
files = argv.slice(1)
|
||||||
|
let result: Result = []
|
||||||
|
if (files.length > 0) {
|
||||||
|
result = files.map(item => {
|
||||||
|
if (path.isAbsolute(item)) {
|
||||||
|
return {
|
||||||
|
path: item
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let tempPath = path.join(cwd, item)
|
||||||
|
if (fs.existsSync(tempPath)) {
|
||||||
|
return {
|
||||||
|
path: tempPath
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).filter(item => item !== null) as Result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getUploadFiles
|
||||||
|
}
|
||||||
@@ -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,13 +0,0 @@
|
|||||||
import db from '../../datastore'
|
|
||||||
|
|
||||||
export default (style, url) => {
|
|
||||||
const customLink = db.read().get('settings.customLink').value() || '$url'
|
|
||||||
const tpl = {
|
|
||||||
'markdown': ``,
|
|
||||||
'HTML': `<img src="${url}"/>`,
|
|
||||||
'URL': url,
|
|
||||||
'UBB': `[IMG]${url}[/IMG]`,
|
|
||||||
'Custom': customLink.replace(/\$url/g, url)
|
|
||||||
}
|
|
||||||
return tpl[style]
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
@@ -1,14 +1,38 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import GuiApi from './guiApi'
|
import GuiApi from './guiApi'
|
||||||
|
import {
|
||||||
|
dialog,
|
||||||
|
shell,
|
||||||
|
IpcMain,
|
||||||
|
IpcMainEvent,
|
||||||
|
App,
|
||||||
|
ipcMain,
|
||||||
|
app
|
||||||
|
} from 'electron'
|
||||||
|
import PicGoCore from '~/universal/types/picgo'
|
||||||
|
import { IPicGoHelperType } from '#/types/enum'
|
||||||
|
import shortKeyHandler from './shortKeyHandler'
|
||||||
|
import picgo from '~/main/utils/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 {
|
||||||
@@ -22,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()
|
||||||
@@ -34,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) {
|
||||||
@@ -55,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,
|
||||||
@@ -69,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]}`),
|
||||||
@@ -88,45 +111,67 @@ const handleGetPluginList = (ipcMain, STORE_PATH, CONFIG_PATH) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePluginInstall = (ipcMain, CONFIG_PATH) => {
|
const handlePluginInstall = () => {
|
||||||
ipcMain.on('installPlugin', (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')
|
||||||
})
|
})
|
||||||
pluginHandler.install([msg])
|
picgo.once('installFailed', () => {
|
||||||
|
handleNPMError()
|
||||||
|
picgo.removeAllListeners('installSuccess')
|
||||||
|
})
|
||||||
|
await picgo.pluginHandler.install([msg])
|
||||||
picgo.cmd.program.removeAllListeners()
|
picgo.cmd.program.removeAllListeners()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePluginUninstall = (ipcMain, CONFIG_PATH) => {
|
const handlePluginUninstall = () => {
|
||||||
ipcMain.on('uninstallPlugin', (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')
|
||||||
})
|
})
|
||||||
pluginHandler.uninstall([msg])
|
picgo.once('uninstallFailed', () => {
|
||||||
|
handleNPMError()
|
||||||
|
picgo.removeAllListeners('uninstallSuccess')
|
||||||
|
})
|
||||||
|
await picgo.pluginHandler.uninstall([msg])
|
||||||
picgo.cmd.program.removeAllListeners()
|
picgo.cmd.program.removeAllListeners()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePluginUpdate = (ipcMain, CONFIG_PATH) => {
|
const handlePluginUpdate = () => {
|
||||||
ipcMain.on('updatePlugin', (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')
|
||||||
})
|
})
|
||||||
pluginHandler.update([msg])
|
picgo.once('updateFailed', () => {
|
||||||
|
handleNPMError()
|
||||||
|
picgo.removeAllListeners('updateSuccess')
|
||||||
|
})
|
||||||
|
await picgo.pluginHandler.update([msg])
|
||||||
picgo.cmd.program.removeAllListeners()
|
picgo.cmd.program.removeAllListeners()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleGetPicBedConfig = (ipcMain, CONFIG_PATH) => {
|
const handleNPMError = () => {
|
||||||
ipcMain.on('getPicBedConfig', (event, type) => {
|
dialog.showMessageBox({
|
||||||
const picgo = new PicGo(CONFIG_PATH)
|
title: '发生错误',
|
||||||
|
message: '请安装Node.js并重启PicGo再继续操作',
|
||||||
|
buttons: ['Yes']
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.response === 0) {
|
||||||
|
shell.openExternal('https://nodejs.org/')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGetPicBedConfig = () => {
|
||||||
|
ipcMain.on('getPicBedConfig', (event: IpcMainEvent, type: string) => {
|
||||||
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))
|
||||||
@@ -138,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)
|
||||||
@@ -154,21 +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()
|
||||||
picgo.emit('remove', files)
|
setTimeout(() => {
|
||||||
|
picgo.emit('remove', files, guiApi)
|
||||||
|
}, 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()
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import bus from './eventBus'
|
||||||
|
import PicGoCore from '~/universal/types/picgo'
|
||||||
|
import path from 'path'
|
||||||
|
import {
|
||||||
|
app,
|
||||||
|
globalShortcut,
|
||||||
|
BrowserWindow
|
||||||
|
} from 'electron'
|
||||||
|
import logger from './logger'
|
||||||
|
import GuiApi from './guiApi'
|
||||||
|
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 './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()
|
||||||
@@ -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))
|
||||||
|
|
||||||
@@ -2,20 +2,19 @@ import {
|
|||||||
app,
|
app,
|
||||||
Notification,
|
Notification,
|
||||||
BrowserWindow,
|
BrowserWindow,
|
||||||
ipcMain
|
ipcMain,
|
||||||
|
WebContents
|
||||||
} from 'electron'
|
} from 'electron'
|
||||||
import path from 'path'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
import picgo from '~/main/utils/picgo'
|
||||||
|
import db from '#/datastore'
|
||||||
|
|
||||||
// eslint-disable-next-line
|
const renameURL = process.env.NODE_ENV === 'development'
|
||||||
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#rename-page`
|
||||||
const PicGo = requireFunc('picgo')
|
: `picgo://./index.html#rename-page`
|
||||||
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) => {
|
const createRenameWindow = (currentWindow: BrowserWindow) => {
|
||||||
let options = {
|
let options: IBrowserWindowOptions = {
|
||||||
height: 175,
|
height: 175,
|
||||||
width: 300,
|
width: 300,
|
||||||
show: true,
|
show: true,
|
||||||
@@ -23,6 +22,8 @@ const createRenameWindow = (win) => {
|
|||||||
resizable: false,
|
resizable: false,
|
||||||
vibrancy: 'ultra-dark',
|
vibrancy: 'ultra-dark',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
nodeIntegrationInWorker: true,
|
||||||
backgroundThrottling: false
|
backgroundThrottling: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,9 +38,9 @@ const createRenameWindow = (win) => {
|
|||||||
const window = new BrowserWindow(options)
|
const window = new BrowserWindow(options)
|
||||||
window.loadURL(renameURL)
|
window.loadURL(renameURL)
|
||||||
// check if this window is visible
|
// check if this window is visible
|
||||||
if (win.isVisible()) {
|
if (currentWindow && currentWindow.isVisible()) {
|
||||||
// bounds: { x: 821, y: 75, width: 800, height: 450 }
|
// bounds: { x: 821, y: 75, width: 800, height: 450 }
|
||||||
const bounds = win.getBounds()
|
const bounds = currentWindow.getBounds()
|
||||||
const positionX = bounds.x + bounds.width / 2 - 150
|
const positionX = bounds.x + bounds.width / 2 - 150
|
||||||
let positionY
|
let positionY
|
||||||
// if is the settingWindow
|
// if is the settingWindow
|
||||||
@@ -53,19 +54,19 @@ const createRenameWindow = (win) => {
|
|||||||
return window
|
return window
|
||||||
}
|
}
|
||||||
|
|
||||||
const waitForShow = (webcontent) => {
|
const waitForShow = (webcontent: WebContents) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
webcontent.on('dom-ready', () => {
|
webcontent.on('did-finish-load', () => {
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const waitForRename = (window, id) => {
|
const waitForRename = (window: BrowserWindow, id: number): Promise<string|null> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
ipcMain.once(`rename${id}`, (evt, newName) => {
|
ipcMain.once(`rename${id}`, (evt: Event, newName: string) => {
|
||||||
resolve(newName)
|
resolve(newName)
|
||||||
window.hide()
|
window.close()
|
||||||
})
|
})
|
||||||
window.on('close', () => {
|
window.on('close', () => {
|
||||||
resolve(null)
|
resolve(null)
|
||||||
@@ -75,34 +76,44 @@ const waitForRename = (window, id) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Uploader {
|
class Uploader {
|
||||||
constructor (img, webContents, picgo = undefined) {
|
private webContents: WebContents | null = null
|
||||||
this.img = img
|
private currentWindow: BrowserWindow | null = null
|
||||||
this.webContents = webContents
|
constructor () {
|
||||||
this.picgo = picgo
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
upload () {
|
init () {
|
||||||
const win = BrowserWindow.fromWebContents(this.webContents)
|
picgo.on('notification', message => {
|
||||||
const picgo = this.picgo || new PicGo(CONFIG_PATH)
|
const notification = new Notification(message)
|
||||||
picgo.config.debug = true
|
notification.show()
|
||||||
// for picgo-core
|
})
|
||||||
picgo.config.PICGO_ENV = 'GUI'
|
|
||||||
let input = this.img
|
|
||||||
|
|
||||||
|
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', {
|
picgo.helper.beforeUploadPlugins.register('renameFn', {
|
||||||
handle: async ctx => {
|
handle: async ctx => {
|
||||||
const rename = picgo.getConfig('settings.rename')
|
const rename = db.get('settings.rename')
|
||||||
const autoRename = picgo.getConfig('settings.autoRename')
|
const autoRename = db.get('settings.autoRename')
|
||||||
await Promise.all(ctx.output.map(async (item, index) => {
|
await Promise.all(ctx.output.map(async (item, index) => {
|
||||||
let name
|
let name: undefined | string | null
|
||||||
let fileName
|
let fileName: string | undefined
|
||||||
if (autoRename) {
|
if (autoRename) {
|
||||||
fileName = dayjs().add(index, 'second').format('YYYYMMDDHHmmss') + item.extname
|
fileName = dayjs().add(index, 'second').format('YYYYMMDDHHmmss') + item.extname
|
||||||
} else {
|
} else {
|
||||||
fileName = item.fileName
|
fileName = item.fileName
|
||||||
}
|
}
|
||||||
if (rename) {
|
if (rename) {
|
||||||
const window = createRenameWindow(win)
|
const window = createRenameWindow(this.currentWindow!)
|
||||||
await waitForShow(window.webContents)
|
await waitForShow(window.webContents)
|
||||||
window.webContents.send('rename', fileName, window.webContents.id)
|
window.webContents.send('rename', fileName, window.webContents.id)
|
||||||
name = await waitForRename(window, window.webContents.id)
|
name = await waitForRename(window, window.webContents.id)
|
||||||
@@ -111,46 +122,40 @@ class Uploader {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
picgo.on('beforeTransform', ctx => {
|
setWebContents (webContents: WebContents) {
|
||||||
if (ctx.getConfig('settings.uploadNotification')) {
|
this.webContents = webContents
|
||||||
const notification = new Notification({
|
return this
|
||||||
title: '上传进度',
|
}
|
||||||
body: '正在上传'
|
|
||||||
})
|
|
||||||
notification.show()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
picgo.upload(input)
|
upload (img?: IUploadOption): Promise<ImgInfo[]|false> {
|
||||||
|
this.currentWindow = BrowserWindow.fromWebContents(this.webContents!)
|
||||||
|
|
||||||
picgo.on('notification', message => {
|
picgo.upload(img)
|
||||||
const notification = new Notification(message)
|
|
||||||
notification.show()
|
|
||||||
})
|
|
||||||
|
|
||||||
picgo.on('uploadProgress', progress => {
|
|
||||||
this.webContents.send('uploadProgress', progress)
|
|
||||||
})
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
picgo.on('finished', ctx => {
|
picgo.once('finished', ctx => {
|
||||||
if (ctx.output.every(item => item.imgUrl)) {
|
if (ctx.output.every((item: ImgInfo) => item.imgUrl)) {
|
||||||
resolve(ctx.output)
|
resolve(ctx.output)
|
||||||
} else {
|
} else {
|
||||||
resolve(false)
|
resolve(false)
|
||||||
}
|
}
|
||||||
|
picgo.removeAllListeners('failed')
|
||||||
})
|
})
|
||||||
picgo.on('failed', ctx => {
|
picgo.once('failed', ctx => {
|
||||||
const notification = new Notification({
|
setTimeout(() => {
|
||||||
title: '上传失败',
|
const notification = new Notification({
|
||||||
body: '请检查配置和上传的文件是否符合要求'
|
title: '上传失败',
|
||||||
})
|
body: '请检查配置和上传的文件是否符合要求'
|
||||||
notification.show()
|
})
|
||||||
|
notification.show()
|
||||||
|
}, 500)
|
||||||
|
picgo.removeAllListeners('finished')
|
||||||
resolve(false)
|
resolve(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Uploader
|
export default new 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"
|
||||||
@@ -143,152 +120,176 @@
|
|||||||
<el-button type="primary" @click="confirmCustomLink">确定</el-button>
|
<el-button type="primary" @click="confirmCustomLink">确定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
:title="inputBoxOptions.title || '输入框'"
|
||||||
|
:visible.sync="showInputBoxVisible"
|
||||||
|
:modal-append-to-body="false"
|
||||||
|
@close="handleInputBoxClose"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="inputBoxValue"
|
||||||
|
:placeholder="inputBoxOptions.placeholder"></el-input>
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button @click="showInputBoxVisible = false" round>取消</el-button>
|
||||||
|
<el-button type="primary" @click="showInputBoxVisible = false" round>确定</el-button>
|
||||||
|
</span>
|
||||||
|
</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: []
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
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)
|
||||||
},
|
ipcRenderer.on('showInputBox', (evt: IpcRendererEvent, options: IShowInputBoxOption) => {
|
||||||
methods: {
|
this.inputBoxValue = ''
|
||||||
handleSelect (index) {
|
this.inputBoxOptions.title = options.title || ''
|
||||||
const type = index.match(/picbeds-/)
|
this.inputBoxOptions.placeholder = options.placeholder || ''
|
||||||
if (type === null) {
|
this.showInputBoxVisible = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handleSelect (index: string) {
|
||||||
|
const type = index.match(/picbeds-/)
|
||||||
|
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
|
|
||||||
}
|
|
||||||
},
|
|
||||||
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)
|
||||||
|
ipcRenderer.removeAllListeners('showInputBox')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -333,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
|
||||||
|
|||||||
@@ -74,9 +74,9 @@
|
|||||||
<el-col :span="6" v-for="(item, index) in images" :key="item.id" class="gallery-list__img">
|
<el-col :span="6" v-for="(item, index) in images" :key="item.id" class="gallery-list__img">
|
||||||
<div
|
<div
|
||||||
class="gallery-list__item"
|
class="gallery-list__item"
|
||||||
v-lazy:background-image="item.imgUrl"
|
|
||||||
@click="zoomImage(index)"
|
@click="zoomImage(index)"
|
||||||
>
|
>
|
||||||
|
<img v-lazy="item.imgUrl" class="gallery-list__item-img">
|
||||||
</div>
|
</div>
|
||||||
<div class="gallery-list__tool-panel">
|
<div class="gallery-list__tool-panel">
|
||||||
<i class="el-icon-document" @click="copy(item)"></i>
|
<i class="el-icon-document" @click="copy(item)"></i>
|
||||||
@@ -102,260 +102,266 @@
|
|||||||
</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.get('uploaded').getById(id)
|
||||||
} else {
|
// @ts-ignore
|
||||||
document.querySelector('.main-content.el-row').style.zIndex = 10
|
this.$db.read().get('uploaded').removeById(id).write()
|
||||||
}
|
ipcRenderer.send('removeFiles', [file])
|
||||||
},
|
|
||||||
handleClose () {
|
|
||||||
this.idx = null
|
|
||||||
this.changeZIndexForGallery(false)
|
|
||||||
},
|
|
||||||
copy (item) {
|
|
||||||
const url = item.url || item.imgUrl
|
|
||||||
const style = this.$db.read().get('settings.pasteStyle').value() || 'markdown'
|
|
||||||
const copyLink = pasteStyle(style, url)
|
|
||||||
const obj = {
|
const obj = {
|
||||||
title: '复制链接成功',
|
title: '操作结果',
|
||||||
body: copyLink,
|
body: '删除成功'
|
||||||
icon: url
|
|
||||||
}
|
}
|
||||||
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(() => {
|
||||||
this.$confirm('此操作将把该图片移出相册, 是否继续?', '提示', {
|
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]) {
|
||||||
|
// @ts-ignore
|
||||||
|
const file = this.$db.read().get('uploaded').getById(key).value()
|
||||||
|
files.push(file)
|
||||||
|
// @ts-ignore
|
||||||
|
this.$db.read().get('uploaded').removeById(key).write()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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})
|
// @ts-ignore
|
||||||
.write()
|
const item = this.$db.read().get('uploaded').getById(key).value()
|
||||||
|
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()
|
|
||||||
const url = item.url || item.imgUrl
|
|
||||||
copyString += pasteStyle(style, url) + '\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>
|
||||||
@@ -423,12 +429,11 @@ export default {
|
|||||||
&__item
|
&__item
|
||||||
width 100%
|
width 100%
|
||||||
height 120px
|
height 120px
|
||||||
background-size cover
|
|
||||||
background-position 50% 50%
|
|
||||||
background-repeat no-repeat
|
|
||||||
transition all .2s ease-in-out
|
transition all .2s ease-in-out
|
||||||
cursor pointer
|
cursor pointer
|
||||||
margin-bottom 8px
|
margin-bottom 8px
|
||||||
|
overflow hidden
|
||||||
|
display flex
|
||||||
&-fake
|
&-fake
|
||||||
position absolute
|
position absolute
|
||||||
top 0
|
top 0
|
||||||
@@ -437,8 +442,10 @@ export default {
|
|||||||
width 100%
|
width 100%
|
||||||
z-index -1
|
z-index -1
|
||||||
&:hover
|
&:hover
|
||||||
background-color #49B1F5
|
|
||||||
transform scale(1.1)
|
transform scale(1.1)
|
||||||
|
&-img
|
||||||
|
width 100%
|
||||||
|
object-fit fill
|
||||||
&__tool-panel
|
&__tool-panel
|
||||||
color #ddd
|
color #ddd
|
||||||
i
|
i
|
||||||
|
|||||||
@@ -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,143 @@ 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: '最小化窗口',
|
||||||
},
|
role: 'minimize'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="picgo-setting">
|
<div id="picgo-setting">
|
||||||
<div class="view-title">
|
<div class="view-title">
|
||||||
PicGo设置
|
PicGo设置 - <i class="el-icon-document" @click="goConfigPage"></i>
|
||||||
</div>
|
</div>
|
||||||
<el-row class="setting-list">
|
<el-row class="setting-list">
|
||||||
<el-col :span="15" :offset="4">
|
<el-col :span="15" :offset="4">
|
||||||
@@ -14,12 +14,17 @@
|
|||||||
<el-form-item
|
<el-form-item
|
||||||
label="打开配置文件"
|
label="打开配置文件"
|
||||||
>
|
>
|
||||||
<el-button type="primary" round size="mini" @click="openConfigFile">点击打开</el-button>
|
<el-button type="primary" round size="mini" @click="openFile('data.json')">点击打开</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="openLogSetting">点击设置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="修改快捷键"
|
||||||
|
>
|
||||||
|
<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="自定义链接格式"
|
||||||
@@ -31,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="检查更新"
|
||||||
>
|
>
|
||||||
@@ -115,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"
|
||||||
@@ -149,11 +135,17 @@
|
|||||||
:model="customLink"
|
:model="customLink"
|
||||||
ref="customLink"
|
ref="customLink"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="用占位符$url来表示url的位置"
|
|
||||||
prop="value"
|
prop="value"
|
||||||
>
|
>
|
||||||
|
<div class="custom-title">
|
||||||
|
用占位符 <b>$url</b> 来表示url的位置
|
||||||
|
</div>
|
||||||
|
<div class="custom-title">
|
||||||
|
用占位符 <b>$fileName</b> 来表示文件名的位置
|
||||||
|
</div>
|
||||||
<el-input
|
<el-input
|
||||||
class="align-center"
|
class="align-center"
|
||||||
v-model="customLink.value"
|
v-model="customLink.value"
|
||||||
@@ -162,7 +154,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div>
|
<div>
|
||||||
如[]($url)
|
如[$fileName]($url)
|
||||||
</div>
|
</div>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<el-button @click="cancelCustomLink" round>取消</el-button>
|
<el-button @click="cancelCustomLink" round>取消</el-button>
|
||||||
@@ -215,200 +207,394 @@
|
|||||||
<el-button type="primary" @click="confirmCheckVersion" round>确定</el-button>
|
<el-button type="primary" @click="confirmCheckVersion" round>确定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
title="设置日志文件"
|
||||||
|
:visible.sync="logFileVisible"
|
||||||
|
:modal-append-to-body="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
label-position="right"
|
||||||
|
label-width="100px"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="日志文件"
|
||||||
|
>
|
||||||
|
<el-button type="primary" round size="mini" @click="openFile('picgo.log')">点击打开</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="日志记录等级"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="form.logLevel"
|
||||||
|
multiple
|
||||||
|
collapse-tags
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(value, key) of logLevel"
|
||||||
|
:key="key"
|
||||||
|
:label="value"
|
||||||
|
:value="key"
|
||||||
|
:disabled="handleLevelDisabled(key)"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button @click="cancelLogLevelSetting" round>取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmLogLevelSetting" round>确定</el-button>
|
||||||
|
</span>
|
||||||
|
</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
|
||||||
return {
|
})
|
||||||
form: {
|
this.letPicGoSaveData({
|
||||||
updateHelper: this.$db.read().get('settings.showUpdateTip').value(),
|
'picBed.list': list
|
||||||
showPicBedList: [],
|
})
|
||||||
autoStart: this.$db.read().get('settings.autoStart').value() || false,
|
ipcRenderer.send('getPicBeds')
|
||||||
rename: this.$db.read().get('settings.rename').value() || false,
|
}
|
||||||
autoRename: this.$db.read().get('settings.autoRename').value() || false,
|
handleAutoStartChange (val: boolean) {
|
||||||
uploadNotification: this.$db.read().get('settings.uploadNotification').value() || false,
|
db.set('settings.autoStart', val)
|
||||||
miniWindowOntop: this.$db.read().get('settings.miniWindowOntop').value() || false
|
ipcRenderer.send('autoStart', val)
|
||||||
},
|
}
|
||||||
picBed: [],
|
handleRename (val: boolean) {
|
||||||
keyBindingVisible: false,
|
this.letPicGoSaveData({
|
||||||
customLinkVisible: false,
|
'settings.rename': val
|
||||||
checkUpdateVisible: false,
|
})
|
||||||
proxyVisible: false,
|
}
|
||||||
customLink: {
|
handleAutoRename (val: boolean) {
|
||||||
value: this.$db.read().get('settings.customLink').value() || '$url'
|
this.letPicGoSaveData({
|
||||||
},
|
'settings.autoRename': val
|
||||||
shortKey: {
|
})
|
||||||
upload: this.$db.read().get('settings.shortKey.upload').value()
|
}
|
||||||
},
|
compareVersion2Update (current: string, latest: string) {
|
||||||
proxy: this.$db.read().get('picBed.proxy').value() || undefined,
|
const currentVersion = current.split('.').map(item => parseInt(item))
|
||||||
rules: {
|
const latestVersion = latest.split('.').map(item => parseInt(item))
|
||||||
value: [
|
|
||||||
{ validator: customLinkRule, trigger: 'blur' }
|
for (let i = 0; i < 3; i++) {
|
||||||
]
|
if (currentVersion[i] < latestVersion[i]) {
|
||||||
},
|
|
||||||
version: pkg.version,
|
|
||||||
latestVersion: '',
|
|
||||||
os: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
this.os = process.platform
|
|
||||||
this.$electron.ipcRenderer.send('getPicBeds')
|
|
||||||
this.$electron.ipcRenderer.on('getPicBeds', this.getPicBeds)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getPicBeds (event, picBeds) {
|
|
||||||
this.picBed = picBeds
|
|
||||||
this.form.showPicBedList = this.picBed.map(item => {
|
|
||||||
if (item.visible) {
|
|
||||||
return item.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
openConfigFile () {
|
|
||||||
const { app, shell } = this.$electron.remote
|
|
||||||
const STORE_PATH = app.getPath('userData')
|
|
||||||
const CONFIG_FILE = path.join(STORE_PATH, '/data.json')
|
|
||||||
shell.openItem(CONFIG_FILE)
|
|
||||||
},
|
|
||||||
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
|
||||||
}
|
}
|
||||||
},
|
if (currentVersion[i] > latestVersion[i]) {
|
||||||
updateHelperChange (val) {
|
return false
|
||||||
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('需要重启生效')
|
|
||||||
}
|
}
|
||||||
},
|
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 (logLevel && logLevel.length > 0) {
|
||||||
|
logLevel = [logLevel]
|
||||||
|
} else {
|
||||||
|
logLevel = ['all']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.form.logLevel = logLevel
|
||||||
|
}
|
||||||
|
confirmServerSetting () {
|
||||||
|
this.letPicGoSaveData({
|
||||||
|
'settings.server': this.server
|
||||||
|
})
|
||||||
|
const successNotification = new Notification('设置PicGo-Server', {
|
||||||
|
body: '设置成功'
|
||||||
|
})
|
||||||
|
successNotification.onclick = () => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
this.serverVisible = false
|
||||||
|
ipcRenderer.send('updateServer')
|
||||||
|
}
|
||||||
|
cancelServerSetting () {
|
||||||
|
this.serverVisible = false
|
||||||
|
this.server = db.get('settings.server') || {
|
||||||
|
port: 36677,
|
||||||
|
host: '127.0.0.1',
|
||||||
|
enable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleLevelDisabled (val: string) {
|
||||||
|
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 () {
|
||||||
|
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>
|
||||||
<style lang='stylus'>
|
<style lang='stylus'>
|
||||||
.el-message
|
.el-message
|
||||||
left 60%
|
left 60%
|
||||||
|
.view-title
|
||||||
|
.el-icon-document
|
||||||
|
cursor pointer
|
||||||
|
transition color .2s ease-in-out
|
||||||
|
&:hover
|
||||||
|
color #49B1F5
|
||||||
#picgo-setting
|
#picgo-setting
|
||||||
.sub-title
|
.sub-title
|
||||||
font-size 14px
|
font-size 14px
|
||||||
@@ -453,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"
|
||||||
@@ -91,81 +91,78 @@
|
|||||||
<el-button type="primary" @click="handleConfirmConfig" round>确定</el-button>
|
<el-button type="primary" @click="handleConfirmConfig" round>确定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog
|
|
||||||
:title="inputBoxOptions.title || '输入框'"
|
|
||||||
:visible.sync="showInputBoxVisible"
|
|
||||||
:modal-append-to-body="false"
|
|
||||||
@close="handleInputBoxClose"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="inputBoxValue"
|
|
||||||
:placeholder="inputBoxOptions.placeholder"></el-input>
|
|
||||||
<span slot="footer">
|
|
||||||
<el-button @click="showInputBoxVisible = false" round>取消</el-button>
|
|
||||||
<el-button type="primary" @click="showInputBoxVisible = false" round>确定</el-button>
|
|
||||||
</span>
|
|
||||||
</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 = ''
|
||||||
// for showInputBox
|
defaultLogo: string = 'this.src="https://cdn.jsdelivr.net/gh/Molunerfinn/PicGo@dev/public/roundLogo.png"'
|
||||||
showInputBoxVisible: false,
|
get npmSearchText () {
|
||||||
inputBoxValue: '',
|
return this.searchText.match('picgo-plugin-')
|
||||||
inputBoxOptions: {
|
? this.searchText
|
||||||
title: '',
|
: this.searchText !== ''
|
||||||
placeholder: ''
|
? `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) {
|
||||||
@@ -174,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) {
|
||||||
@@ -186,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
|
||||||
@@ -204,252 +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')
|
||||||
this.$electron.ipcRenderer.on('showInputBox', (evt, options) => {
|
}
|
||||||
this.inputBoxValue = ''
|
buildContextMenu (plugin: IPicGoPlugin) {
|
||||||
this.inputBoxOptions.title = options.title || ''
|
const _this = this
|
||||||
this.inputBoxOptions.placeholder = options.placeholder || ''
|
let menu = [{
|
||||||
this.showInputBoxVisible = true
|
label: '启用插件',
|
||||||
})
|
enabled: !plugin.enabled,
|
||||||
},
|
click () {
|
||||||
methods: {
|
_this.letPicGoSaveData({
|
||||||
buildContextMenu (plugin) {
|
[`picgoPlugins.picgo-plugin-${plugin.name}`]: true
|
||||||
const _this = this
|
})
|
||||||
let menu = [{
|
plugin.enabled = true
|
||||||
label: '启用插件',
|
_this.getPicBeds()
|
||||||
enabled: !plugin.enabled,
|
}
|
||||||
click () {
|
}, {
|
||||||
_this.$db.read().set(`picgoPlugins.picgo-plugin-${plugin.name}`, true).write()
|
label: '禁用插件',
|
||||||
plugin.enabled = true
|
enabled: plugin.enabled,
|
||||||
_this.getPicBeds()
|
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)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleInputBoxClose () {
|
|
||||||
this.$electron.ipcRenderer.send('showInputBox', this.inputBoxValue)
|
|
||||||
},
|
|
||||||
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')
|
||||||
this.$electron.ipcRenderer.removeAllListeners('showInputBox')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -483,6 +495,9 @@ $darwinBg = #172426
|
|||||||
font-size 20px
|
font-size 20px
|
||||||
vertical-align middle
|
vertical-align middle
|
||||||
cursor pointer
|
cursor pointer
|
||||||
|
transition color .2s ease-in-out
|
||||||
|
&:hover
|
||||||
|
color #49B1F5
|
||||||
.handle-bar
|
.handle-bar
|
||||||
margin-bottom 20px
|
margin-bottom 20px
|
||||||
&.cut-width
|
&.cut-width
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="wait-upload-img" v-if="clipboardFiles.length > 0">
|
<div class="wait-upload-img" v-if="clipboardFiles.length > 0">
|
||||||
<div class="list-title">等待上传</div>
|
<div class="list-title">等待上传</div>
|
||||||
<div v-for="(item, index) in clipboardFiles" :key="index" class="img-list" :style="{height: calcHeight(item.width, item.height) + 'px'}">
|
<div v-for="(item, index) in clipboardFiles" :key="index" class="img-list">
|
||||||
<div
|
<div
|
||||||
class="upload-img__container"
|
class="upload-img__container"
|
||||||
:class="{ upload: uploadFlag }"
|
:class="{ upload: uploadFlag }"
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="uploaded-img">
|
<div class="uploaded-img">
|
||||||
<div class="list-title">已上传</div>
|
<div class="list-title">已上传</div>
|
||||||
<div v-for="item in files" :key="item.imgUrl" class="img-list" :style="{height: calcHeight(item.width, item.height) + 'px'}">
|
<div v-for="item in files" :key="item.imgUrl" class="img-list">
|
||||||
<div class="upload-img__container" @click="copyTheLink(item)">
|
<div class="upload-img__container" @click="copyTheLink(item)">
|
||||||
<img :src="item.imgUrl" class="upload-img">
|
<img :src="item.imgUrl" class="upload-img">
|
||||||
</div>
|
</div>
|
||||||
@@ -25,91 +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()
|
|
||||||
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.imgUrl))
|
|
||||||
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">
|
||||||
@@ -146,11 +146,11 @@ body::-webkit-scrollbar
|
|||||||
top 0px
|
top 0px
|
||||||
width 100%
|
width 100%
|
||||||
.img-list
|
.img-list
|
||||||
padding 16px 8px
|
padding 8px 8px
|
||||||
display flex
|
display flex
|
||||||
justify-content space-between
|
justify-content space-between
|
||||||
align-items center
|
align-items center
|
||||||
height 45px
|
// height 45px
|
||||||
cursor pointer
|
cursor pointer
|
||||||
transition all .2s ease-in-out
|
transition all .2s ease-in-out
|
||||||
&:hover
|
&:hover
|
||||||
@@ -158,8 +158,8 @@ body::-webkit-scrollbar
|
|||||||
.upload-img__index
|
.upload-img__index
|
||||||
color #fff
|
color #fff
|
||||||
.upload-img
|
.upload-img
|
||||||
height 100%
|
|
||||||
width 100%
|
width 100%
|
||||||
|
object-fit scale-down
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
&__container
|
&__container
|
||||||
width 100%
|
width 100%
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="20" :offset="2">
|
<el-col :span="20" :offset="2">
|
||||||
<div class="view-title">
|
<div class="view-title">
|
||||||
图片上传 - {{ picBedName }}
|
图片上传 - {{ picBedName }} <i class="el-icon-caret-bottom" @click="handleChangePicBed"></i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id="upload-area"
|
id="upload-area"
|
||||||
@@ -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,22 +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 {
|
||||||
}
|
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
|
||||||
@@ -81,75 +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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -216,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>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
:rules="{
|
:rules="{
|
||||||
required: true, message: 'Token不能为空', trigger: 'blur'
|
required: true, message: 'Token不能为空', trigger: 'blur'
|
||||||
}">
|
}">
|
||||||
<el-input v-model="form.token" @keyup.native.enter="confirm" placeholder="token"></el-input>
|
<el-input v-model="form.token" @keyup.native.enter="confirm" placeholder="token" type="password"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="指定存储路径"
|
label="指定存储路径"
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -45,13 +45,10 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="确认存储区域"
|
label="确认存储区域"
|
||||||
>
|
:rules="{
|
||||||
<el-radio-group v-model="form.area" size="mini">
|
required: true, message: '区域代码不能为空', trigger: 'blur'
|
||||||
<el-radio-button label="z0">华东</el-radio-button>
|
}">
|
||||||
<el-radio-button label="z1">华北</el-radio-button>
|
<el-input v-model="form.area" placeholder="例如z0"></el-input>
|
||||||
<el-radio-button label="z2">华南</el-radio-button>
|
|
||||||
<el-radio-button label="na0">北美</el-radio-button>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="设定网址后缀"
|
label="设定网址后缀"
|
||||||
@@ -74,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: 'z0',
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,52 +85,51 @@
|
|||||||
</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 {
|
import { remote } from 'electron'
|
||||||
mixins: [mixin],
|
@Component({
|
||||||
name: 'tcyun',
|
name: 'tcyun',
|
||||||
data () {
|
mixins: [mixin]
|
||||||
return {
|
})
|
||||||
form: {
|
export default class extends Vue {
|
||||||
secretId: '',
|
form: ITcYunConfig = {
|
||||||
secretKey: '',
|
secretId: '',
|
||||||
bucket: '',
|
secretKey: '',
|
||||||
appId: '',
|
bucket: '',
|
||||||
area: '',
|
appId: '',
|
||||||
path: '',
|
area: '',
|
||||||
customUrl: '',
|
path: '',
|
||||||
version: 'v4'
|
customUrl: '',
|
||||||
}
|
version: 'v4'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
const config = this.$db.get('picBed.tcyun').value()
|
const config = this.$db.get('picBed.tcyun') as ITcYunConfig
|
||||||
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.tcyun.validate((valid) => {
|
this.$refs.tcyun.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$db.set('picBed.tcyun', this.form).write()
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('设置结果', {
|
'picBed.tcyun': this.form
|
||||||
body: '设置成功'
|
})
|
||||||
})
|
const successNotification = new window.Notification('设置结果', {
|
||||||
successNotification.onclick = () => {
|
body: '设置成功'
|
||||||
return true
|
})
|
||||||
}
|
successNotification.onclick = () => {
|
||||||
} else {
|
return true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
},
|
return false
|
||||||
openWiki () {
|
}
|
||||||
this.$electron.remote.shell.openExternal('https://github.com/Molunerfinn/PicGo/wiki/%E8%AF%A6%E7%BB%86%E7%AA%97%E5%8F%A3%E7%9A%84%E4%BD%BF%E7%94%A8#腾讯云cos')
|
})
|
||||||
}
|
}
|
||||||
|
openWiki () {
|
||||||
|
remote.shell.openExternal('https://github.com/Molunerfinn/PicGo/wiki/%E8%AF%A6%E7%BB%86%E7%AA%97%E5%8F%A3%E7%9A%84%E4%BD%BF%E7%94%A8#腾讯云cos')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -64,46 +64,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: 'upyun',
|
name: 'upyun',
|
||||||
mixins: [mixin],
|
mixins: [mixin]
|
||||||
data () {
|
})
|
||||||
return {
|
export default class extends Vue {
|
||||||
form: {
|
form: IUpYunConfig = {
|
||||||
bucket: '',
|
bucket: '',
|
||||||
operator: '',
|
operator: '',
|
||||||
password: '',
|
password: '',
|
||||||
options: '',
|
options: '',
|
||||||
path: ''
|
path: ''
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
created () {
|
||||||
const config = this.$db.get('picBed.upyun').value()
|
const config = this.$db.get('picBed.upyun') as IUpYunConfig
|
||||||
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.tcyun.validate((valid) => {
|
this.$refs.tcyun.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$db.set('picBed.upyun', this.form).write()
|
this.letPicGoSaveData({
|
||||||
const successNotification = new window.Notification('设置结果', {
|
'picBed.upyun': this.form
|
||||||
body: '设置成功'
|
})
|
||||||
})
|
const successNotification = new Notification('设置结果', {
|
||||||
successNotification.onclick = () => {
|
body: '设置成功'
|
||||||
return true
|
})
|
||||||
}
|
successNotification.onclick = () => {
|
||||||
} else {
|
return true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="16" :offset="4">
|
<el-col :span="16" :offset="4">
|
||||||
<div class="view-title">
|
<div class="view-title">
|
||||||
微博图床设置
|
微博图床设置[已停止支持]
|
||||||
</div>
|
</div>
|
||||||
<el-form
|
<el-form
|
||||||
ref="weiboForm"
|
ref="weiboForm"
|
||||||
@@ -78,7 +78,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
const config = this.$db.read().get('picBed.weibo').value()
|
const config = this.$db.get('picBed.weibo')
|
||||||
if (config) {
|
if (config) {
|
||||||
this.form.username = config.username
|
this.form.username = config.username
|
||||||
this.form.password = config.password
|
this.form.password = config.password
|
||||||
@@ -91,13 +91,15 @@ export default {
|
|||||||
confirm (formName) {
|
confirm (formName) {
|
||||||
this.$refs[formName].validate((valid) => {
|
this.$refs[formName].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$db.read().set('picBed.weibo', {
|
this.letPicGoSaveData({
|
||||||
username: this.form.username,
|
'picBed.weibo': {
|
||||||
password: this.form.password,
|
username: this.form.username,
|
||||||
quality: this.quality,
|
password: this.form.password,
|
||||||
cookie: this.form.cookie,
|
quality: this.quality,
|
||||||
chooseCookie: this.chooseCookie
|
cookie: this.form.cookie,
|
||||||
}).write()
|
chooseCookie: this.chooseCookie
|
||||||
|
}
|
||||||
|
})
|
||||||
const successNotification = new window.Notification('设置结果', {
|
const successNotification = new window.Notification('设置结果', {
|
||||||
body: '设置成功'
|
body: '设置成功'
|
||||||
})
|
})
|
||||||
|
|||||||