first commit
30
.babelrc
Executable file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"comments": false,
|
||||
"env": {
|
||||
"main": {
|
||||
"presets": [
|
||||
["env", {
|
||||
"targets": { "node": 7 }
|
||||
}],
|
||||
"stage-0"
|
||||
]
|
||||
},
|
||||
"renderer": {
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false
|
||||
}],
|
||||
"stage-0"
|
||||
]
|
||||
},
|
||||
"web": {
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false
|
||||
}],
|
||||
"stage-0"
|
||||
]
|
||||
}
|
||||
},
|
||||
"plugins": ["transform-runtime"]
|
||||
}
|
||||
1
.electron-vue/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
10fa0628-4dc5-4c15-b1da-9c73cdfe350a
|
||||
115
.electron-vue/build.js
Executable file
@@ -0,0 +1,115 @@
|
||||
'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 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 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 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()
|
||||
}
|
||||
40
.electron-vue/dev-client.js
Executable file
@@ -0,0 +1,40 @@
|
||||
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>
|
||||
`
|
||||
}
|
||||
})
|
||||
190
.electron-vue/dev-runner.js
Executable file
@@ -0,0 +1,190 @@
|
||||
'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()
|
||||
71
.electron-vue/webpack.main.config.js
Executable file
@@ -0,0 +1,71 @@
|
||||
'use strict'
|
||||
|
||||
process.env.BABEL_ENV = 'main'
|
||||
|
||||
const path = require('path')
|
||||
const { dependencies } = require('../package.json')
|
||||
const webpack = require('webpack')
|
||||
const fs= require('fs')
|
||||
// 检测是否有用户配置文件,没有的话根据模板生成一个
|
||||
const userConfigPath=path.resolve(__dirname,'../.user-config.js')
|
||||
|
||||
if(!fs.existsSync(userConfigPath)){
|
||||
fs.copyFileSync(path.resolve(__dirname,'../user-config.template.js'), userConfigPath)
|
||||
}
|
||||
|
||||
let mainConfig = {
|
||||
entry: {
|
||||
main: path.join(__dirname, '../src/main/index.js')
|
||||
},
|
||||
externals: [
|
||||
...Object.keys(dependencies || {})
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
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 webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = mainConfig
|
||||
175
.electron-vue/webpack.renderer.config.js
Executable file
@@ -0,0 +1,175 @@
|
||||
'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')
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 whiteListedModules = ['vue', 'vue-router', 'axios', 'vuex', 'vue-electron']
|
||||
|
||||
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: /\.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|vue)$/,
|
||||
loader: 'eslint-loader',
|
||||
enforce: 'pre',
|
||||
include: [resolve('src')],
|
||||
options: {
|
||||
formatter: require('eslint-friendly-formatter'),
|
||||
emitWarning: true
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
use: {
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
extractCSS: process.env.NODE_ENV === 'production',
|
||||
loaders: {
|
||||
less: 'vue-style-loader!css-loader!less-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',
|
||||
'static': path.join(__dirname, '../static')
|
||||
},
|
||||
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 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
|
||||
3
.eslintignore
Executable file
@@ -0,0 +1,3 @@
|
||||
/*.ejs
|
||||
src/out
|
||||
docs/*
|
||||
112
.eslintrc.js
Executable file
@@ -0,0 +1,112 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"commonjs": true,
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"amd": true
|
||||
},
|
||||
extends: ['plugin:vue/essential', 'airbnb-base'],
|
||||
globals: {
|
||||
Atomics: 'readonly',
|
||||
SharedArrayBuffer: 'readonly'
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
parser: "babel-eslint"
|
||||
},
|
||||
plugins: ['vue', 'html'],
|
||||
// check if imports actually resolve
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
webpack: {
|
||||
config: '.electron-vue/webpack.renderer.config.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
// 句尾分号可以省略
|
||||
'semi': ['error', 'never'],
|
||||
// 代码中console/debugger处理
|
||||
'no-console': 'off',
|
||||
'no-debugger': 'off',
|
||||
// 代码使用4个空格的缩进风格
|
||||
'indent': ['error', 4],
|
||||
// 关闭命名function表达式规则
|
||||
'func-names': 'off',
|
||||
// 可以行尾空白
|
||||
'no-trailing-spaces': 'off',
|
||||
// 关闭拖尾逗号
|
||||
'comma-dangle': 'off',
|
||||
// 关闭换行符转换
|
||||
'linebreak-style': 'off',
|
||||
// 禁止使用指定语法
|
||||
'no-restricted-syntax': ['error', 'WithStatement'],
|
||||
// 关闭语句块之前的空格保持一致
|
||||
'space-before-blocks': 'off',
|
||||
// 可以使用++/--
|
||||
'no-plusplus': 'off',
|
||||
// 禁止未使用过的变量包括全局变量和函数中的最后一个参数必须使用
|
||||
'no-unused-vars': [
|
||||
'error', {
|
||||
'vars': 'all',
|
||||
'args': 'after-used'
|
||||
}
|
||||
],
|
||||
// 使用单引号
|
||||
'quotes': [
|
||||
'error', 'single'
|
||||
],
|
||||
// 强制最大可嵌深度为8
|
||||
'max-depth': 0,
|
||||
// 强制函数块中的语句最大50行
|
||||
'max-statements': [
|
||||
'error', 50
|
||||
],
|
||||
// 强制行的最大长度150,注释200
|
||||
'max-len': [
|
||||
'error', {
|
||||
'code': 200,
|
||||
'comments': 800
|
||||
}
|
||||
],
|
||||
|
||||
// NodeJs rules, 9.0之后全部使用import
|
||||
// 关闭require()强制在模块顶部调用
|
||||
'global-require': 'off',
|
||||
|
||||
// ES6 rules
|
||||
// 箭头函数的箭头前后都要有空格
|
||||
'arrow-spacing': 'error',
|
||||
// 接收const被修改的通知
|
||||
'no-const-assign': 'error',
|
||||
// 要求使用let或const而不是var
|
||||
'no-var': 'error',
|
||||
// 如果一个变量不会被重新赋值,则使用const声明
|
||||
'prefer-const': 'error',
|
||||
// 关闭强制在花括号内使用一致的换行符
|
||||
'object-curly-newline': 'off',
|
||||
|
||||
// 链接地址中可以使用 javascript:
|
||||
'no-script-url': 'off',
|
||||
// 关闭点击元素上强制增加onKey**事件
|
||||
'click-events-have-key-events': 'off',
|
||||
// 关闭引用依赖检查
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
// 关闭路径处理依赖
|
||||
'import/no-cycle': 'off',
|
||||
"no-param-reassign": 0, //禁止给参数重新赋值
|
||||
"no-use-before-define": 0,
|
||||
"no-unused-vars": 'off',
|
||||
"no-underscore-dangle":0,
|
||||
"brace-style":0,
|
||||
// 扩展名处理
|
||||
'import/extensions': 'off',
|
||||
}
|
||||
};
|
||||
8
.gitignore
vendored
Executable file
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
dist/*
|
||||
build/*
|
||||
node_modules/
|
||||
npm-debug.log.*
|
||||
thumbs.db
|
||||
.user-config.js
|
||||
!.gitkeep
|
||||
36
.travis.yml
Executable file
@@ -0,0 +1,36 @@
|
||||
osx_image: xcode8.3
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: c
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ npm_config_clang=1
|
||||
compiler: clang
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- "$HOME/.electron"
|
||||
- "$HOME/.cache"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgnome-keyring-dev
|
||||
- icnsutils
|
||||
before_install:
|
||||
- mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v1.2.1/git-lfs-$([
|
||||
"$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-1.2.1.tar.gz
|
||||
| tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi
|
||||
install:
|
||||
- nvm install 7
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
- source ~/.bashrc
|
||||
- npm install -g xvfb-maybe
|
||||
- yarn
|
||||
script:
|
||||
- yarn run build
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
1
.vscode/.pydio
vendored
Normal file
@@ -0,0 +1 @@
|
||||
a2beb42a-53d7-4c5b-b4be-7f513fcdfdd8
|
||||
21
.vscode/launch.json
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Electron Main",
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
|
||||
"program": "${workspaceFolder}/src/main/index.js"
|
||||
},
|
||||
// {
|
||||
// "type": "node",
|
||||
// "request": "launch",
|
||||
// "name": "Launch Program",
|
||||
// "program": "${workspaceFolder}/src/get-image/500px.js"
|
||||
// }
|
||||
]
|
||||
}
|
||||
12
.vscode/settings.json
vendored
Executable file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
// 忽略的文件
|
||||
"csscomb.ignoreFilesOnSave": [
|
||||
".git/**",
|
||||
"node_modules/**",
|
||||
"dist/**",
|
||||
"dll/**",
|
||||
],
|
||||
// 规则路径,也可以为一个对象自定义规则
|
||||
"csscomb.preset": "csscomb.js",
|
||||
"csscomb.formatOnSave": true,
|
||||
}
|
||||
21
LICENSE
Executable file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 peng
|
||||
|
||||
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 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.
|
||||
119
README.md
Executable file
@@ -0,0 +1,119 @@
|
||||
|
||||
## Strawberry Wallpaper 草莓壁纸🍓
|
||||
|
||||
> 采用electron-vue开发的壁纸应用
|
||||
> 本应用相关图片都源自于网络,壁纸图片的一切版权归壁纸来源网站所有,切不可将版权图片作为商用。
|
||||
|
||||
|
||||
#### 开发
|
||||
```
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
#### 打包
|
||||
1.先执行webpack打包页面
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
2.按平台打包 `electron-builder` 会默认当前平台进行打包
|
||||
```
|
||||
npm run build-mac
|
||||
npm run build-win
|
||||
```
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 1.适用范围
|
||||
|
||||
Works on macOS 10.12+, and Windows 10+.
|
||||
|
||||
目前只在mac10.14.3与win10上进行了测试
|
||||
|
||||
#### 1.安装软件
|
||||
|
||||
提供两个打包好的下载地址:
|
||||
|
||||
[Strawberry Wallpaper-mac](http://sw.taoacat.com/Strawberry%20Wallpaper-mac.dmg)
|
||||
|
||||
[Strawberry Wallpaper-win](http://sw.taoacat.com/Strawberry%20Wallpaper-win.exe)
|
||||
|
||||
macOS可以使用[homebrew](https://brew.sh/index_zh-cn)进行安装:
|
||||
|
||||
```bash
|
||||
brew cask install strawberry-wallpaper
|
||||
```
|
||||
|
||||
#### 2.软件介绍
|
||||
|
||||
【软件主页】
|
||||
|
||||
用于显示壁纸照片,可以切换图库,可以进行关键词搜索,并可存储最近搜索的关键词。
|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/stwallpaper-1.png" width="300px" />
|
||||
|
||||
【设置】
|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/stwallpaper-2.png" width="300px" />
|
||||
|
||||
|
||||
【检测更新】
|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/stwallpaper-3.png" width="500px" />
|
||||
|
||||
|
||||
【意见反馈】
|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/stwallpaper-4.png" width="500px" />
|
||||
|
||||
【公告】
|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/stwallpaper-5.png" width="500px" />
|
||||
|
||||
【网页模式】
|
||||
|
||||
可在网页中对图库图片进行搜索、下载、设置为壁纸
|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/stwallpaper-6.png" width="700px" />
|
||||
|
||||
|
||||
## 更新日志
|
||||
|
||||
> v1.4.2
|
||||
- 修复1.4.1已知问题
|
||||
|
||||
> v1.4.1
|
||||
- 修复新安装用户不能设置壁纸问题
|
||||
|
||||
> v1.4
|
||||
- 修复pexels图库加载不成功问题
|
||||
- 增加设置壁纸的填充方式(mac下有效)
|
||||
- 增加是否自动应用到所有屏幕设置(mac下有效)
|
||||
- 增加壁纸方向与尺寸的筛选
|
||||
- 增加网页模式,网页模式下加载相关网页,并可直接在网页中可以下载图片到本地以及设置壁纸
|
||||
- 增加公告展示
|
||||
|
||||
|
||||
[历史更新](./update-log.md)
|
||||
|
||||
|
||||
## 用户统计
|
||||
草莓壁纸会针对用户安装量以及用户的活跃量进行统计,根据用户的网卡信息生成唯一UID。统计信息只获取用户的电脑系统,用户电脑用户名。
|
||||
可以打开[草莓壁纸后台统计平台](http://sw.taoacat.com)进行查看相关统计数据。后台统计相关接口采用go语言开发,[项目地址](https://github.com/wangkaibo/strawberry-wallpaper):https://github.com/wangkaibo/strawberry-wallpaper 欢迎点赞,支持。
|
||||
|
||||
## LICENSE
|
||||
|
||||
MIT
|
||||
|
||||
## 点👍
|
||||
|
||||
如果觉得本项目不错,请点击页面右上角的的小星星。也可以为作者点👍,欢迎打赏。
|
||||
|
||||

|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/wechat-money.png" width="200px" />
|
||||
|
||||
## 感谢
|
||||
- vue
|
||||
- electron
|
||||
- vue-electron
|
||||
- ...
|
||||
29
appveyor.yml
Executable file
@@ -0,0 +1,29 @@
|
||||
version: 0.1.{build}
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
image: Visual Studio 2017
|
||||
platform:
|
||||
- x64
|
||||
|
||||
cache:
|
||||
- node_modules
|
||||
- '%APPDATA%\npm-cache'
|
||||
- '%USERPROFILE%\.electron'
|
||||
- '%USERPROFILE%\AppData\Local\Yarn\cache'
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 8 x64
|
||||
- git reset --hard HEAD
|
||||
- yarn
|
||||
- node --version
|
||||
|
||||
build_script:
|
||||
- yarn build
|
||||
|
||||
test: off
|
||||
1
build-config/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
ed5f7899-add2-43b2-aff7-2c63e4603fff
|
||||
1
build-config/icons/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2e10cfaa-9570-4d45-8179-9a1fbb20ed05
|
||||
BIN
build-config/icons/256x256.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
build-config/icons/icon.icns
Executable file
BIN
build-config/icons/icon.ico
Executable file
|
After Width: | Height: | Size: 264 KiB |
208
csscomb.js
Executable file
@@ -0,0 +1,208 @@
|
||||
module.exports = {
|
||||
exclude: [
|
||||
'.git/**',
|
||||
'node_modules/**',
|
||||
'bower_components/**',
|
||||
'dist/**',
|
||||
'dll/**',
|
||||
'src/css/**'
|
||||
],
|
||||
'always-semicolon': true, // 总是显示分号
|
||||
'block-indent': ' ', // 代码块缩进,可以是数字或字符串与空白和制表符等
|
||||
'color-case': 'lower', // 十六进制颜色统一,可选值'lower'全部小写;'upper'全部大写
|
||||
'color-hex-case': 'lower', // 颜色值统一小写
|
||||
'color-shorthand': false, // 十六进制颜色缩写与否
|
||||
'element-case': 'lower', // 选择器元素统一,可选值'lower'全部小写;'upper'全部大写
|
||||
'eof-newline': true, // 文件结束后添换行
|
||||
'leading-zero': true, // 是否需要小数点前的0
|
||||
quotes: 'double', // 引号风格,可选值'single'单引号,'double'双引号
|
||||
'remove-empty-rulesets': true, // 是否移除空规则集,为true时,如:'a{ }'这样的空规则集将被移除
|
||||
'space-after-colon': ' ', // 冒号后规则
|
||||
'space-after-combinator': ' ', // 选择符后规则
|
||||
'space-between-declarations': '\n', // 属性后的规则
|
||||
'space-after-opening-brace': '\n', // '{' 之后的规则
|
||||
'space-after-selector-delimiter': '\n', // 选择器之后的规则
|
||||
'space-before-closing-brace': '\n', // '}' 之后的规则
|
||||
'space-before-colon': '', // 冒号前的规则
|
||||
'space-before-combinator': ' ', // 选择符前规则
|
||||
'space-before-opening-brace': ' ', // '{' 之前的规则
|
||||
'space-before-selector-delimiter': '', // 选择器之前的规则
|
||||
'strip-spaces': true, // 是否修剪尾随的空格
|
||||
'tab-size': 4, // 缩进大小
|
||||
'unitless-zero': true, // 是否移除0后的单位值,比如'0px'格式化为'0'
|
||||
'vendor-prefix-align': true, // 是否对齐属性和值中的前缀
|
||||
'lines-between-rulesets': 1, // 规则与规则之间的换行数
|
||||
'sort-order': [
|
||||
// Directions about where and how the box is placed
|
||||
|
||||
// ['@include'],
|
||||
|
||||
'display',
|
||||
|
||||
'grid',
|
||||
'grid-area',
|
||||
'grid-auto-flow',
|
||||
'grid-auto-columns',
|
||||
'grid-auto-rows',
|
||||
'grid-gap',
|
||||
'grid-column',
|
||||
'grid-column-start',
|
||||
'grid-column-end',
|
||||
'grid-column-gap',
|
||||
'grid-row',
|
||||
'grid-row-start',
|
||||
'grid-row-end',
|
||||
'grid-row-gap',
|
||||
'grid-template',
|
||||
'grid-template-areas',
|
||||
'grid-template-columns',
|
||||
'grid-template-rows',
|
||||
|
||||
'flex',
|
||||
'flex-basis',
|
||||
'flex-direction',
|
||||
'flex-flow',
|
||||
'flex-grow',
|
||||
'flex-shrink',
|
||||
'flex-wrap',
|
||||
'align-content',
|
||||
'align-items',
|
||||
'align-self',
|
||||
'justify-self',
|
||||
'justify-content',
|
||||
'order',
|
||||
|
||||
'position',
|
||||
'top',
|
||||
'right',
|
||||
'bottom',
|
||||
'left',
|
||||
|
||||
'columns',
|
||||
'column-gap',
|
||||
'column-fill',
|
||||
'column-rule',
|
||||
'column-span',
|
||||
'column-count',
|
||||
'column-width',
|
||||
|
||||
'float',
|
||||
'clear',
|
||||
|
||||
'transform',
|
||||
'transform-origin',
|
||||
|
||||
// can the box be seen?
|
||||
'visibility',
|
||||
'opacity',
|
||||
'z-index',
|
||||
|
||||
// Layers of the box model, from outside to inside
|
||||
'margin',
|
||||
'margin-top',
|
||||
'margin-right',
|
||||
'margin-bottom',
|
||||
'margin-left',
|
||||
|
||||
'outline',
|
||||
|
||||
'border',
|
||||
'border-top',
|
||||
'border-right',
|
||||
'border-bottom',
|
||||
'border-left',
|
||||
'border-width',
|
||||
'border-top-width',
|
||||
'border-right-width',
|
||||
'border-bottom-width',
|
||||
'border-left-width',
|
||||
'border-style',
|
||||
'border-top-style',
|
||||
'border-right-style',
|
||||
'border-bottom-style',
|
||||
'border-left-style',
|
||||
'border-color',
|
||||
'border-top-color',
|
||||
'border-right-color',
|
||||
'border-bottom-color',
|
||||
'border-left-color',
|
||||
'border-radius',
|
||||
'border-top-left-radius',
|
||||
'border-top-right-radius',
|
||||
'border-bottom-left-radius',
|
||||
'border-bottom-right-radius',
|
||||
|
||||
'box-shadow',
|
||||
'box-sizing',
|
||||
|
||||
// Content dimensions and background and scrollbars
|
||||
'background',
|
||||
'background-clip',
|
||||
'background-color',
|
||||
'background-image',
|
||||
'background-position',
|
||||
'background-repeat',
|
||||
'background-size',
|
||||
'cursor',
|
||||
|
||||
'width',
|
||||
'min-width',
|
||||
'max-width',
|
||||
'height',
|
||||
'min-height',
|
||||
'max-height',
|
||||
|
||||
'overflow',
|
||||
'overflow-x',
|
||||
'overflow-y',
|
||||
|
||||
// (Padding after dimensions because of `box-sizing: border-box`)
|
||||
'padding',
|
||||
'padding-top',
|
||||
'padding-right',
|
||||
'padding-bottom',
|
||||
'padding-left',
|
||||
|
||||
// Special content types: lists, tables
|
||||
'list-style',
|
||||
'caption-side',
|
||||
'table-layout',
|
||||
'border-collapse',
|
||||
'border-spacing',
|
||||
'empty-cells',
|
||||
|
||||
// Textual content
|
||||
'vertical-align',
|
||||
'text-align',
|
||||
'text-decoration',
|
||||
'text-indent',
|
||||
'text-overflow',
|
||||
'text-rendering',
|
||||
'text-shadow',
|
||||
'text-transform',
|
||||
|
||||
'line-height',
|
||||
'word-spacing',
|
||||
'letter-spacing',
|
||||
'white-space',
|
||||
|
||||
'color',
|
||||
|
||||
'font',
|
||||
'font-family',
|
||||
'font-size',
|
||||
'font-weight',
|
||||
'font-style',
|
||||
'font-smoothing',
|
||||
|
||||
'content',
|
||||
'quotes',
|
||||
|
||||
// Transitions change previously defined properties
|
||||
'transition',
|
||||
'transition-property',
|
||||
'transition-duration',
|
||||
'transition-timing-function',
|
||||
'transition-delay'
|
||||
]
|
||||
}
|
||||
0
docs/.nojekyll
Executable file
1
docs/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
bea3cae9-474d-415a-a5d3-98173ba38eac
|
||||
41
docs/README.md
Executable file
@@ -0,0 +1,41 @@
|
||||
|
||||
## Strawberry Wallpaper 草莓壁纸 🍓
|
||||
|
||||
### 一款追求更好用的桌面壁纸APP
|
||||
|
||||
<img src="./img/bk1.png" width="100%" />
|
||||
|
||||
|
||||
###### `Strawberry Wallpaper` 是一款针对macOS以及windows的一款精美壁纸应用。自动更新各大图库的高清壁纸,非常适合寻找各种美的图片的你。
|
||||
|
||||
##### 功能:
|
||||
|
||||
- 目前支持pexels、500px、paper、unsplash、wallhaven、NASA每日一图、 themoviedb(类似豆瓣)
|
||||
- 同时支持macOS与windows
|
||||
- 支持壁纸预览,通过缩略图就可预览众多壁纸,同时对壁纸的尺寸做了明显的标记
|
||||
- 支持关键词搜索,想要什么样的图片一触即得
|
||||
- 支持定时自动设置壁纸
|
||||
- 支持方向、尺寸筛选,
|
||||
- 支持设置壁纸平铺方式(mac系统)
|
||||
- 支持网页模式,在浏览原生网页的时候也可以设置壁纸
|
||||
- 对设置过的壁纸存放到固定目录,方便随时查看
|
||||
- 长期更新、完全免费
|
||||
|
||||
##### 亮点:
|
||||
|
||||
###### 简单而又不失优雅的UI设计(仿Pap.er)
|
||||
|
||||
<img src="./img/bk.png" width="100%" />
|
||||
|
||||
###### 支持不同图库的自由切换以及支持自动定时更新壁纸
|
||||
|
||||
<img src="./img/bk2.png" width="100%" />
|
||||
|
||||
###### 支持网页模式
|
||||
可在网页中对图库图片进行搜索、下载、设置为壁纸
|
||||
|
||||
<img src="http://file.qiniu.taoacat.com/stwallpaper-6.png" width="700px" />
|
||||
|
||||
##### [项目地址](https://github.com/aitexiaoy/Strawberry-Wallpaper)
|
||||
##### [Windows下载](http://sw.taoacat.com/Strawberry%20Wallpaper-win.exe)
|
||||
##### [Mac下载](http://sw.taoacat.com/Strawberry%20Wallpaper-mac.dmg)
|
||||
10
docs/_coverpage.md
Executable file
@@ -0,0 +1,10 @@
|
||||
# Strawberry Wallpaper
|
||||
|
||||
> 一款非常好用的桌面壁纸APP
|
||||
|
||||
[GitHub](https://github.com/aitexiaoy/Strawberry-Wallpaper)
|
||||
[Get Started](#quick-start)
|
||||
|
||||

|
||||
|
||||

|
||||
8
docs/_sidebar.md
Executable file
@@ -0,0 +1,8 @@
|
||||
* 开发笔记
|
||||
* [如何利用Node进行图片的抓取](zh-cn/reptile.md)
|
||||
* [将图片保存到本地](zh-cn/save-image.md)
|
||||
* [如何设置壁纸](zh-cn/set-wallpaper.md)
|
||||
* [项目搭建](zh-cn/start.md)
|
||||
* [主窗口定位-tarbar](zh-cn/tarbar.md)
|
||||
* [如何进行远程升级](zh-cn/updata.md)
|
||||
* [遇到的问题](zh-cn/problem.md)
|
||||
1
docs/img/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
6ab41161-5a2a-45ad-b5a8-89b0c8421b13
|
||||
BIN
docs/img/bk.png
Executable file
|
After Width: | Height: | Size: 942 KiB |
BIN
docs/img/bk1.png
Executable file
|
After Width: | Height: | Size: 863 KiB |
BIN
docs/img/bk2.png
Executable file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
docs/img/logo.png
Executable file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
docs/img/stwallpaper-1.png
Executable file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
docs/img/stwallpaper-2.png
Executable file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
docs/img/stwallpaper-3.png
Executable file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
docs/img/stwallpaper-4.png
Executable file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/img/stwallpaper-5.png
Executable file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/img/stwallpaper-6.png
Executable file
|
After Width: | Height: | Size: 1.9 MiB |
213
docs/index.html
Executable file
@@ -0,0 +1,213 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>strawberrywallpaper - a wallpaper app by electron</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/vuep/dist/vuep.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<link rel="icon" type="image/x-icon" class="js-site-favicon" href="./image/favicon.ico">
|
||||
<!-- 引入element样式 -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
||||
|
||||
|
||||
<style>
|
||||
.sidebar-nav-parent-li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.sidebar-nav .ul-after {
|
||||
content: '';
|
||||
width: 10px;
|
||||
height: 30px;
|
||||
/* background: red; */
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 0px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ul-after-sanjiao {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 8px solid #cecece;
|
||||
border-top: 8px solid transparent;
|
||||
border-bottom: 8px solid transparent;
|
||||
transition: transform 0.3s;
|
||||
position: relative;
|
||||
|
||||
}
|
||||
|
||||
.ul-after-sanjiao::after {
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
left: -11px;
|
||||
border-left: 8px solid #fff;
|
||||
border-top: 8px solid transparent;
|
||||
border-bottom: 8px solid transparent;
|
||||
}
|
||||
|
||||
.ul-after-sanjiao:hover {
|
||||
border-left: 8px solid #42b983;
|
||||
}
|
||||
|
||||
.sidebar-nav-parent-li-shouqi .ul-after-sanjiao {
|
||||
transform: rotate(90deg);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.return-top {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
display: none;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 100%;
|
||||
background: #d8d7d7;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.return-top-div {
|
||||
margin-left: 5px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: 5px;
|
||||
font-size: 14px;
|
||||
color: #5f5959;
|
||||
line-height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.return-top:hover {
|
||||
background: #42b983;
|
||||
}
|
||||
|
||||
.return-top:hover .return-top-div {
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav></nav>
|
||||
<div id="app">loading...</div>
|
||||
|
||||
<!-- vue文件在线编辑 -->
|
||||
<script src="//unpkg.com/vue/dist/vue.min.js"></script>
|
||||
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
|
||||
<!-- 引入组件库 -->
|
||||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
||||
|
||||
<script src="//unpkg.com/docsify-demo-box-vue/dist/docsify-demo-box-vue.min.js"></script>
|
||||
<!-- 在线编辑运行Vue的插件 -->
|
||||
<script src="//unpkg.com/vuep/dist/vuep.min.js"></script>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
// 引入docsify-demo-box-vue
|
||||
var jsResources = '<scr' + 'ipt src="//unpkg.com/vue/dist/vue.js"></scr' + 'ipt>'
|
||||
var cssResources = '@import url("//cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css");'
|
||||
var bootCode = 'var globalVariable = "leon"'
|
||||
var globalVariable = "leon"
|
||||
|
||||
window.$docsify = {
|
||||
// name: 'strawberry wallpaper',
|
||||
loadNavbar: true,
|
||||
maxLevel: 6,
|
||||
auto2top: true,
|
||||
autoHeader: true,
|
||||
// loadSidebar: true,
|
||||
subMaxLevel: 3,
|
||||
// disqus: 'yangpeng',
|
||||
// 搜索完整配置参数
|
||||
search: {
|
||||
placeholder: '请输入关键字',
|
||||
noData: '暂无结果',
|
||||
// 搜索标题的最大程级, 1 - 6
|
||||
depth: 6
|
||||
},
|
||||
|
||||
plugins: [
|
||||
DemoBoxVue.create(jsResources, cssResources, bootCode),
|
||||
function (hook) {
|
||||
hook.doneEach(function () {
|
||||
//回到顶部
|
||||
let return_top = $('<div class="return-top"><div class="return-top-div">顶</div></div>')
|
||||
$('html').append(return_top);
|
||||
$(window).scroll(function () {
|
||||
var scroll = $(window).scrollTop();
|
||||
if (scroll > 1000) {
|
||||
$(return_top).show();
|
||||
} else {
|
||||
$(return_top).hide();
|
||||
}
|
||||
})
|
||||
return_top.on('click', function (e) {
|
||||
$('html,body').animate({
|
||||
scrollTop: 0
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
|
||||
<!-- 复制到剪切板 -->
|
||||
<script src="https://unpkg.com/docsify-copy-code@2"></script>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
|
||||
<!-- 图片放大 -->
|
||||
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.js"></script>
|
||||
|
||||
<script src="//unpkg.com/docsify/lib/plugins/external-script.min.js"></script>
|
||||
|
||||
<!-- Disqus 评论系统-->
|
||||
<!-- <script src="//unpkg.com/docsify/lib/plugins/disqus.min.js"></script> -->
|
||||
|
||||
|
||||
<!-- 分页导航插件 -->
|
||||
<!-- <script src="//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script> -->
|
||||
|
||||
<!-- 引入代码块的颜色支持 -->
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-json.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-javascript.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-diff.min.js"></script>
|
||||
<!-- <script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script> -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
1
docs/zh-cn/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
d51c4cfd-204c-4d1f-b63f-975d8241cdaa
|
||||
30
docs/zh-cn/problem.md
Executable file
@@ -0,0 +1,30 @@
|
||||
### 软件在window下会存在重复运行的问题
|
||||
即双击打开软件,在windows下会创建一个新的运行程序。
|
||||
|
||||
#### 解决方法
|
||||
```js
|
||||
// 创建程序锁,保证只能打开单个实例
|
||||
if (isWin()) {
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
if (mainWindow) {
|
||||
if (!mainWindow.isVisible()) {
|
||||
mainWindowShow()
|
||||
}
|
||||
mainWindow.focus()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### win.setPosition方法报错
|
||||
##### 原因:setPosition方法中的参数不支持浮点数,只支持整数
|
||||
|
||||
### 远程升级相关问题
|
||||
#### 1.远程升级只能在build后生效
|
||||
#### 2.mac端远程升级需要development ID 到官网申请
|
||||
#### 3.安装最新的electron-update后,运行提示缺少`whenReady()`方法,那是因为`electron-vue`的`electron`版本为2.7的而`whenReady()`为electron3.0.0更新的。解决办法就是升级electron
|
||||
8
docs/zh-cn/reptile.md
Executable file
@@ -0,0 +1,8 @@
|
||||
### 分析网页接口
|
||||
> 在此处拿https://www.pexels.com 的图库进行分析
|
||||
|
||||
pexels为一个面版权的图库网站,
|
||||
|
||||
### 模拟请求
|
||||
|
||||
### 处理DOM
|
||||
94
docs/zh-cn/save-image.md
Executable file
@@ -0,0 +1,94 @@
|
||||
#### 文件代码在 src/file.js
|
||||
|
||||
起初采用axios进行图片的下载,但是axios在服务端不支持进度条,最后又换成了request请求。
|
||||
|
||||
```js
|
||||
export const downloadPic = async function (src, mainWindow) {
|
||||
// 返回一个Promise方便处理
|
||||
return new Promise((resolve, reject) => {
|
||||
// 先检测目录,没有相关目录的话会自动创建新的目录
|
||||
mkdirSync(hostdir)
|
||||
// 自动重命名
|
||||
let dstpath = `${hostdir}/${(new Date()).getTime()}_${(new Date()).getMilliseconds()}`
|
||||
// webp格式的图片标志,500px下载的图片为webp格式的
|
||||
let isWebp = false
|
||||
// 判断图片格式
|
||||
if (src.match('webp=true')) {
|
||||
dstpath += '.webp'
|
||||
isWebp = true
|
||||
} else {
|
||||
dstpath += '.jpg'
|
||||
isWebp = false
|
||||
}
|
||||
|
||||
// 已经接受的文件的大小
|
||||
let receivedBytes = 0
|
||||
// 文件总的字大小
|
||||
let totalBytes = 0
|
||||
|
||||
// 创建一个文件流
|
||||
const writeStream = fs.createWriteStream(dstpath, {
|
||||
autoClose: true
|
||||
})
|
||||
// 创建一个请求
|
||||
myRequest = request({
|
||||
url: src,
|
||||
headers: browserHeader,
|
||||
})
|
||||
myRequest.pipe(writeStream)
|
||||
myRequest.on('response', (data) => {
|
||||
// 更新总文件字节大小
|
||||
totalBytes = parseInt(data.headers['content-length'], 10)
|
||||
})
|
||||
myRequest.on('data', (chunk) => {
|
||||
// 更新下载的文件块字节大小
|
||||
receivedBytes += chunk.length
|
||||
// 更新进度条
|
||||
mainWindow.webContents.send('datainfo', {
|
||||
type: 'updaterProgress',
|
||||
data: parseFloat(((receivedBytes / totalBytes) * 100))
|
||||
})
|
||||
})
|
||||
|
||||
myRequest.on('finish', () => {
|
||||
myRequest = null
|
||||
})
|
||||
myRequest.on('error', () => {
|
||||
reject()
|
||||
})
|
||||
writeStream.on('finish', () => {
|
||||
writeStream.end()
|
||||
myRequest = null
|
||||
if (receivedBytes === totalBytes){
|
||||
if (isWebp) {
|
||||
// 将webp图片转成jpg图片
|
||||
webp.dwebp(dstpath, dstpath.replace('webp', 'jpg'), '-o', (status) => {
|
||||
// status 101->fails || 100->successful
|
||||
if (status === '100'){
|
||||
fs.unlink(dstpath, (err) => {
|
||||
if (err) throw err
|
||||
// console.log('文件已删除')
|
||||
})
|
||||
resolve(dstpath.replace('webp', 'jpg'))
|
||||
} else {
|
||||
reject()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolve(dstpath)
|
||||
}
|
||||
} else {
|
||||
fs.unlink(dstpath, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
// 更新进度条
|
||||
mainWindow.webContents.send('datainfo', {
|
||||
type: 'updaterProgress',
|
||||
data: 0
|
||||
})
|
||||
reject()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
```
|
||||
1
docs/zh-cn/set-wallpaper.md
Executable file
@@ -0,0 +1 @@
|
||||
不支持
|
||||
1
docs/zh-cn/start.md
Executable file
@@ -0,0 +1 @@
|
||||
xiangmudajian
|
||||
79
docs/zh-cn/tarbar.md
Executable file
@@ -0,0 +1,79 @@
|
||||
#### 定位
|
||||
```js
|
||||
appTray.on('click', (event, bounds, position) => {
|
||||
// mainWindow === null ? createWindow() : mainWindow.close()
|
||||
// return
|
||||
// 点击时显示窗口,并修改窗口的显示位置
|
||||
function setMainWinPosition(win, trayBounds) {
|
||||
try {
|
||||
const { screen } = electron
|
||||
const winWidth = mainWindow.getSize()[0]
|
||||
const winHeight = mainWindow.getSize()[1]
|
||||
const cursorPosition = screen.getCursorScreenPoint()
|
||||
const currentScreen = screen.getDisplayNearestPoint(cursorPosition)
|
||||
const screens = screen.getAllDisplays()
|
||||
|
||||
let screenWidth = 0
|
||||
|
||||
// 这目前判断多屏都是横着拼的多屏,
|
||||
for (let i = 0; i < screens.length; i++) {
|
||||
screenWidth += screens[i].workAreaSize.width
|
||||
}
|
||||
|
||||
cursorPosition.x = trayBounds.x + trayBounds.width / 2
|
||||
|
||||
const parallelType = cursorPosition.x < screenWidth / 2 ? 'left' : 'right'
|
||||
const verticaType = cursorPosition.y < currentScreen.workAreaSize.height / 2 ? 'top' : 'bottom'
|
||||
|
||||
let trayPositionType = '' // 任务栏的位置
|
||||
let trayPositionSize = 0
|
||||
|
||||
if (currentScreen.workAreaSize.height < currentScreen.size.height) {
|
||||
trayPositionType = verticaType === 'top' ? 'top' : 'bottom'
|
||||
trayPositionSize = currentScreen.size.height - currentScreen.workAreaSize.height
|
||||
} else if (currentScreen.workAreaSize.width < currentScreen.size.width) {
|
||||
trayPositionType = parallelType === 'left' ? 'left' : 'right'
|
||||
trayPositionSize = currentScreen.size.width - currentScreen.workAreaSize.width
|
||||
}
|
||||
|
||||
let winPositionX = 1
|
||||
let winPositionY = 1
|
||||
|
||||
if (trayPositionType === 'top') {
|
||||
winPositionX = Math.max(Math.min(screenWidth - winWidth, cursorPosition.x - (winWidth / 2)), 1)
|
||||
winPositionY = trayBounds.height + 2
|
||||
} else if (trayPositionType === 'bottom') {
|
||||
winPositionX = Math.max(Math.min(screenWidth - winWidth, cursorPosition.x - (winWidth / 2)), 1)
|
||||
winPositionY = currentScreen.size.height - trayPositionSize - winHeight
|
||||
} else if (trayPositionType === 'left') {
|
||||
winPositionX = trayPositionSize
|
||||
winPositionY = Math.max(Math.min(currentScreen.size.height - winHeight, cursorPosition.y - (winHeight / 2)), 1)
|
||||
} else if (trayPositionType === 'right') {
|
||||
winPositionX = screenWidth - trayPositionSize - winWidth
|
||||
winPositionY = Math.max(Math.min(currentScreen.size.height - winHeight, cursorPosition.y - (winHeight / 2)), 1)
|
||||
}
|
||||
win.setPosition(parseInt(winPositionX, 10), winPositionY)
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (mainWindow.isVisible()) {
|
||||
mainWindow.webContents.send('datainfo', {
|
||||
type: 'windowShow',
|
||||
data: false
|
||||
})
|
||||
mainWindowHide()
|
||||
} else {
|
||||
mainWindow.webContents.send('datainfo', {
|
||||
type: 'windowShow',
|
||||
data: true
|
||||
})
|
||||
mainWindowShow()
|
||||
setMainWinPosition(mainWindow, bounds)
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
}
|
||||
})
|
||||
```
|
||||
3
docs/zh-cn/updata.md
Executable file
@@ -0,0 +1,3 @@
|
||||
### 远程升级
|
||||
|
||||
采用`electron-updater`模块
|
||||
1
icons/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
20ff6b22-6de6-486e-829b-9760a83e63dd
|
||||
BIN
icons/icon_128x128.png
Executable file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
icons/icon_128x128@2x.png
Executable file
|
After Width: | Height: | Size: 19 KiB |
BIN
icons/icon_16x16.png
Executable file
|
After Width: | Height: | Size: 957 B |
BIN
icons/icon_16x16@2x.png
Executable file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
icons/icon_256x256.png
Executable file
|
After Width: | Height: | Size: 19 KiB |
BIN
icons/icon_256x256@2x.png
Executable file
|
After Width: | Height: | Size: 43 KiB |
BIN
icons/icon_32x32.png
Executable file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
icons/icon_512x512.png
Executable file
|
After Width: | Height: | Size: 43 KiB |
BIN
icons/icon_512x512@2x.png
Executable file
|
After Width: | Height: | Size: 15 KiB |
13237
package-lock.json
generated
Executable file
127
package.json
Executable file
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"name": "Strawberry Wallpaper",
|
||||
"version": "v1.4.2",
|
||||
"author": "taoacat,流浪记",
|
||||
"description": "a wallpaper app by electron",
|
||||
"license": "",
|
||||
"main": "./dist/electron/main.js",
|
||||
"bin": "cli.js",
|
||||
"scripts": {
|
||||
"build-r": "node .electron-vue/build.js",
|
||||
"build-win": "electron-builder --win",
|
||||
"build-mac": "electron-builder --mac",
|
||||
"build": "npm run build-r && npm run build-win && npm run build-mac",
|
||||
"build:dir": "cross-env node .electron-vue/build.js && electron-builder --mac --dir",
|
||||
"clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js",
|
||||
"dev": "node .electron-vue/dev-runner.js",
|
||||
"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",
|
||||
"postinstall": "",
|
||||
"docs": "docsify serve docs"
|
||||
},
|
||||
"build": {
|
||||
"productName": "Strawberry Wallpaper",
|
||||
"appId": "9Y7KR6Q842.com.taoacat.wallpaperapplications",
|
||||
"directories": {
|
||||
"output": "build"
|
||||
},
|
||||
"publish": {
|
||||
"provider": "generic",
|
||||
"url": "http://sw.taoacat.com/version/"
|
||||
},
|
||||
"files": [
|
||||
"dist/electron/**/*"
|
||||
],
|
||||
"mac": {
|
||||
"icon": "build-config/icons/icon.icns",
|
||||
"target": [
|
||||
"dmg",
|
||||
"zip"
|
||||
]
|
||||
},
|
||||
"win": {
|
||||
"icon": "build-config/icons/icon.ico",
|
||||
"requestedExecutionLevel": "highestAvailable",
|
||||
"target": [
|
||||
"nsis",
|
||||
"zip"
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"icon": "build-config/icons"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/node": "^7.10.1",
|
||||
"ajv": "^6.5.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"cfonts": "^2.1.2",
|
||||
"chalk": "^2.4.1",
|
||||
"copy-webpack-plugin": "^4.5.1",
|
||||
"cross-env": "^5.1.6",
|
||||
"css-loader": "^3.0.0",
|
||||
"del": "^3.0.0",
|
||||
"devtron": "^1.4.0",
|
||||
"drop-console-webpack-plugin": "^3.0.2",
|
||||
"electron": "^9.0.4",
|
||||
"electron-builder": "^22.7.0",
|
||||
"electron-debug": "^2.1.0",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-airbnb-base": "^13.1.0",
|
||||
"eslint-friendly-formatter": "^4.0.1",
|
||||
"eslint-import-resolver-webpack": "^0.11.0",
|
||||
"eslint-loader": "^2.1.2",
|
||||
"eslint-plugin-html": "^5.0.3",
|
||||
"eslint-plugin-import": "^2.17.2",
|
||||
"eslint-plugin-node": "^8.0.1",
|
||||
"eslint-plugin-promise": "^4.1.1",
|
||||
"eslint-plugin-vue": "^5.2.2",
|
||||
"file-loader": "^1.1.11",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^5.0.0",
|
||||
"mini-css-extract-plugin": "0.4.0",
|
||||
"multispinner": "^0.2.1",
|
||||
"node-loader": "^0.6.0",
|
||||
"sass-loader": "^7.0.3",
|
||||
"style-loader": "^0.21.0",
|
||||
"url-loader": "^1.0.1",
|
||||
"vue-html-loader": "^1.2.4",
|
||||
"vue-loader": "^15.2.4",
|
||||
"vue-style-loader": "^4.1.0",
|
||||
"vue-template-compiler": "^2.6.7",
|
||||
"webpack": "^4.15.1",
|
||||
"webpack-cli": "^3.0.8",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"auto-launch": "^5.0.5",
|
||||
"axios": "^0.18.0",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"custom-electron-titlebar": "^3.2.2-hotfix62",
|
||||
"electron-log": "^3.0.1",
|
||||
"electron-updater": "^4.0.6",
|
||||
"element-ui": "^2.5.4",
|
||||
"fs": "^0.0.1-security",
|
||||
"http2-client": "^1.3.3",
|
||||
"jsdom": "^13.2.0",
|
||||
"macaddress": "^0.2.9",
|
||||
"node-os-utils": "^1.0.7",
|
||||
"nodemailer": "^5.1.1",
|
||||
"path": "^0.12.7",
|
||||
"progress": "^2.0.3",
|
||||
"qs": "^6.7.0",
|
||||
"request": "^2.88.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-electron": "^1.0.6",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.0.1",
|
||||
"vuex-electron": "^1.0.0",
|
||||
"wallpaper": "^4.2.0",
|
||||
"wangeditor": "^3.1.1",
|
||||
"webp-converter": "^2.2.2"
|
||||
}
|
||||
}
|
||||
1
src/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
3c55ee6b-00f5-48af-a641-b8fc0b4cc892
|
||||
1
src/api/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
9d8d83fd-0709-4fcf-8e6c-08e6596dfee3
|
||||
105
src/api/api.js
Executable file
@@ -0,0 +1,105 @@
|
||||
|
||||
|
||||
import userConfig from '../../.user-config.js'
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
const { baiDuTranslationAppId, baiDuTranslationAppKey } = userConfig
|
||||
const { MD5: swMd5 } = require('./baidu-md5')
|
||||
const { apiBaseUrl } = require('../utils/config')
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: apiBaseUrl,
|
||||
timeout: 1000,
|
||||
|
||||
})
|
||||
|
||||
/**
|
||||
* 第一次的时候注册
|
||||
*/
|
||||
export const postRegister = data => new Promise((resolve, reject) => {
|
||||
instance({
|
||||
url: '/register',
|
||||
method: 'post',
|
||||
data,
|
||||
}).then((res) => {
|
||||
const { data: result } = res
|
||||
if (result.code === 0 || result.code === 400){
|
||||
resolve()
|
||||
}
|
||||
else {
|
||||
reject()
|
||||
}
|
||||
}).catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
/**
|
||||
* 统计用户的使用情况
|
||||
*/
|
||||
export const apiStatisticActive = data => instance.post('/active', data)
|
||||
|
||||
export const apiGetNotices = () => new Promise((resolve) => {
|
||||
instance.get('/notice', {
|
||||
params: {
|
||||
is_test: 1
|
||||
}
|
||||
}).then((res) => {
|
||||
const { data: result } = res
|
||||
if (result.code === 0){
|
||||
resolve(result.data || [])
|
||||
}
|
||||
else {
|
||||
resolve([])
|
||||
}
|
||||
}).catch(() => { resolve([]) })
|
||||
})
|
||||
|
||||
/**
|
||||
* 百度翻译接口,将用户搜索的中文转成英文
|
||||
*/
|
||||
export const apiTranslation = val => new Promise((resolve, reject) => {
|
||||
if (val === ''){
|
||||
resolve('')
|
||||
return
|
||||
}
|
||||
// 如果包含数字就直接返回搜索值
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
if (!isNaN(Number(val))){
|
||||
resolve(val)
|
||||
return
|
||||
}
|
||||
const appid = baiDuTranslationAppId
|
||||
const key = baiDuTranslationAppKey
|
||||
const salt = (new Date()).getTime()
|
||||
const query = val
|
||||
// 多个query可以用\n连接 如 query='apple\norange\nbanana\npear'
|
||||
const from = 'zh'
|
||||
const to = 'en'
|
||||
const str1 = appid + query + salt + key
|
||||
const sign = swMd5(str1)
|
||||
|
||||
axios({
|
||||
url: 'http://api.fanyi.baidu.com/api/trans/vip/translate',
|
||||
method: 'get',
|
||||
params: {
|
||||
q: val,
|
||||
appid,
|
||||
salt,
|
||||
from,
|
||||
to,
|
||||
sign
|
||||
}
|
||||
}).then((result) => {
|
||||
const { trans_result: transResult } = result.data
|
||||
if (transResult && transResult.length > 0){
|
||||
const { dst = '' } = transResult[0]
|
||||
resolve(dst.toLocaleLowerCase())
|
||||
}
|
||||
else {
|
||||
resolve('')
|
||||
}
|
||||
}).catch(() => {
|
||||
resolve('')
|
||||
})
|
||||
})
|
||||
205
src/api/baidu-md5.js
Executable file
@@ -0,0 +1,205 @@
|
||||
/* eslint-disable */
|
||||
export const MD5 = function (string) {
|
||||
function RotateLeft(lValue, iShiftBits) {
|
||||
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
|
||||
}
|
||||
|
||||
function AddUnsigned(lX, lY) {
|
||||
let lX4; var lY4; var lX8; var lY8; var lResult;
|
||||
lX8 = (lX & 0x80000000);
|
||||
lY8 = (lY & 0x80000000);
|
||||
lX4 = (lX & 0x40000000);
|
||||
lY4 = (lY & 0x40000000);
|
||||
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
|
||||
if (lX4 & lY4) {
|
||||
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
|
||||
}
|
||||
if (lX4 | lY4) {
|
||||
if (lResult & 0x40000000) {
|
||||
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
|
||||
}
|
||||
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
|
||||
}
|
||||
return (lResult ^ lX8 ^ lY8);
|
||||
}
|
||||
|
||||
function F(x, y, z) { return (x & y) | ((~x) & z); }
|
||||
function G(x, y, z) { return (x & z) | (y & (~z)); }
|
||||
function H(x, y, z) { return (x ^ y ^ z); }
|
||||
function I(x, y, z) { return (y ^ (x | (~z))); }
|
||||
|
||||
function FF(a, b, c, d, x, s, ac) {
|
||||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
|
||||
return AddUnsigned(RotateLeft(a, s), b);
|
||||
}
|
||||
|
||||
function GG(a, b, c, d, x, s, ac) {
|
||||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
|
||||
return AddUnsigned(RotateLeft(a, s), b);
|
||||
}
|
||||
|
||||
function HH(a, b, c, d, x, s, ac) {
|
||||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
|
||||
return AddUnsigned(RotateLeft(a, s), b);
|
||||
}
|
||||
|
||||
function II(a, b, c, d, x, s, ac) {
|
||||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
|
||||
return AddUnsigned(RotateLeft(a, s), b);
|
||||
}
|
||||
|
||||
function ConvertToWordArray(string) {
|
||||
let lWordCount;
|
||||
const lMessageLength = string.length;
|
||||
const lNumberOfWords_temp1 = lMessageLength + 8;
|
||||
const lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
|
||||
const lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
|
||||
const lWordArray = Array(lNumberOfWords - 1);
|
||||
let lBytePosition = 0;
|
||||
let lByteCount = 0;
|
||||
while (lByteCount < lMessageLength) {
|
||||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||
lBytePosition = (lByteCount % 4) * 8;
|
||||
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
|
||||
lByteCount++;
|
||||
}
|
||||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||
lBytePosition = (lByteCount % 4) * 8;
|
||||
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
|
||||
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
|
||||
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
|
||||
return lWordArray;
|
||||
}
|
||||
|
||||
function WordToHex(lValue) {
|
||||
let WordToHexValue = ''; let WordToHexValue_temp = ''; let lByte; let
|
||||
lCount;
|
||||
for (lCount = 0; lCount <= 3; lCount++) {
|
||||
lByte = (lValue >>> (lCount * 8)) & 255;
|
||||
// eslint-disable-next-line camelcase
|
||||
WordToHexValue_temp = `0${lByte.toString(16)}`;
|
||||
WordToHexValue += WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
|
||||
}
|
||||
return WordToHexValue;
|
||||
}
|
||||
|
||||
function Utf8Encode(string) {
|
||||
string = string.replace(/\r\n/g, '\n');
|
||||
let utftext = '';
|
||||
|
||||
for (let n = 0; n < string.length; n++) {
|
||||
const c = string.charCodeAt(n);
|
||||
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
}
|
||||
else if ((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
}
|
||||
|
||||
return utftext;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-array-constructor
|
||||
let x = Array();
|
||||
let k; let AA; let BB; let CC; let DD; let a; let b; let c; let
|
||||
d;
|
||||
const S11 = 7; const S12 = 12; const S13 = 17; const
|
||||
S14 = 22;
|
||||
const S21 = 5; const S22 = 9; const S23 = 14; const
|
||||
S24 = 20;
|
||||
const S31 = 4; const S32 = 11; const S33 = 16; const
|
||||
S34 = 23;
|
||||
const S41 = 6; const S42 = 10; const S43 = 15; const
|
||||
S44 = 21;
|
||||
|
||||
string = Utf8Encode(string);
|
||||
|
||||
x = ConvertToWordArray(string);
|
||||
|
||||
a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
|
||||
|
||||
for (k = 0; k < x.length; k += 16) {
|
||||
AA = a; BB = b; CC = c; DD = d;
|
||||
a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
|
||||
d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
|
||||
c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
|
||||
b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
|
||||
a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
|
||||
d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
|
||||
c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
|
||||
b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
|
||||
a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
|
||||
d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
|
||||
c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
|
||||
b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
|
||||
a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
|
||||
d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
|
||||
c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
|
||||
b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
|
||||
a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
|
||||
d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
|
||||
c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
|
||||
b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
|
||||
a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
|
||||
d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
|
||||
c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
|
||||
b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
|
||||
a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
|
||||
d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
|
||||
c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
|
||||
b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
|
||||
a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
|
||||
d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
|
||||
c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
|
||||
b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
|
||||
a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
|
||||
d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
|
||||
c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
|
||||
b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
|
||||
a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
|
||||
d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
|
||||
c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
|
||||
b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
|
||||
a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
|
||||
d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
|
||||
c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
|
||||
b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
|
||||
a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
|
||||
d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
|
||||
c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
|
||||
b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
|
||||
a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
|
||||
d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
|
||||
c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
|
||||
b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
|
||||
a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
|
||||
d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
|
||||
c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
|
||||
b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
|
||||
a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
|
||||
d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
|
||||
c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
|
||||
b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
|
||||
a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
|
||||
d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
|
||||
c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
|
||||
b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
|
||||
a = AddUnsigned(a, AA);
|
||||
b = AddUnsigned(b, BB);
|
||||
c = AddUnsigned(c, CC);
|
||||
d = AddUnsigned(d, DD);
|
||||
}
|
||||
|
||||
const temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
|
||||
|
||||
return temp.toLowerCase();
|
||||
}
|
||||
|
||||
1
src/file/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
de8c304e-5871-4f4d-928d-b9ec94969b87
|
||||
24
src/file/auto-open.js
Executable file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* @Description: 设置开机启动
|
||||
* @Author: --
|
||||
* @Date: 2019-02-19 10:51:01
|
||||
* @LastEditTime: 2019-04-09 09:48:22
|
||||
*/
|
||||
|
||||
const AutoLaunch = require('auto-launch')
|
||||
|
||||
const minecraftAutoLauncher = new AutoLaunch({
|
||||
name: 'Strawberry Wallpaper',
|
||||
})
|
||||
|
||||
export const openAutoStart = function (){
|
||||
return minecraftAutoLauncher.enable() // 设置开机自动启动
|
||||
}
|
||||
|
||||
export const openDisStart = function (){
|
||||
return minecraftAutoLauncher.disable() // 禁止开机自动启动
|
||||
}
|
||||
|
||||
export const openType = async function (){
|
||||
await minecraftAutoLauncher.isEnabled()
|
||||
}
|
||||
154
src/file/file.js
Executable file
@@ -0,0 +1,154 @@
|
||||
|
||||
/**
|
||||
* @Description: 下载图片并存到指定文件夹
|
||||
* @Author: --
|
||||
* @Date: 2019-01-24 21:35:23
|
||||
* @LastEditTime: 2019-04-09 09:39:45
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const request = require('request')
|
||||
const webp = require('webp-converter')
|
||||
const { md5_32: md5 } = require('../utils/md5')
|
||||
|
||||
/**
|
||||
* @type {String} 图片下载地址
|
||||
*/
|
||||
const { browserHeader } = require('../utils/config')
|
||||
/**
|
||||
* @type {Object} 保存当前的请求对象
|
||||
*/
|
||||
let myRequest = null
|
||||
let currentSaveFilePath = ''
|
||||
|
||||
/**
|
||||
* 创建指定路径文件
|
||||
* @param {String} dirname
|
||||
*/
|
||||
export function mkdirSync(dirname) {
|
||||
try {
|
||||
if (fs.existsSync(dirname)) {
|
||||
return true
|
||||
}
|
||||
if (mkdirSync(path.dirname(dirname))) {
|
||||
fs.mkdirSync(dirname)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定连接下图片
|
||||
* @param {*} src 下载图片的绝对地址
|
||||
* @param {*} sendData 发送消息
|
||||
* @param {Object} userConfig 用户配置
|
||||
*/
|
||||
export const downloadPic = async function (src, sendData, userConfig) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 创建文件夹
|
||||
const hostdir = userConfig.downloadImagePath
|
||||
// 文件名
|
||||
const fileName = md5(src)
|
||||
mkdirSync(hostdir)
|
||||
let dstpath = `${hostdir}/SW-${fileName}`
|
||||
let isWebp = false
|
||||
// 如图图片已经下载完成了
|
||||
if (fs.existsSync(`${dstpath}.jpg`)){
|
||||
resolve(`${dstpath}.jpg`)
|
||||
return
|
||||
}
|
||||
if (src.match('webp=true')) {
|
||||
dstpath += '.webp'
|
||||
isWebp = true
|
||||
} else {
|
||||
dstpath += '.jpg'
|
||||
isWebp = false
|
||||
}
|
||||
currentSaveFilePath = dstpath
|
||||
|
||||
let receivedBytes = 0
|
||||
let totalBytes = 0
|
||||
|
||||
const writeStream = fs.createWriteStream(dstpath, {
|
||||
autoClose: true
|
||||
})
|
||||
myRequest = request({
|
||||
url: src,
|
||||
headers: browserHeader,
|
||||
timeout: 120000 // 120s
|
||||
})
|
||||
myRequest.pipe(writeStream)
|
||||
myRequest.on('response', (data) => {
|
||||
// 更新总文件字节大小
|
||||
totalBytes = parseInt(data.headers['content-length'], 10)
|
||||
})
|
||||
myRequest.on('data', (chunk) => {
|
||||
// 更新下载的文件块字节大小
|
||||
receivedBytes += chunk.length
|
||||
// console.log(receivedBytes, totalBytes)
|
||||
sendData('datainfo', {
|
||||
type: 'updaterProgress',
|
||||
data: parseFloat(((receivedBytes / totalBytes) * 100))
|
||||
})
|
||||
})
|
||||
|
||||
myRequest.on('error', () => {
|
||||
deleteDownLoadFile(dstpath)
|
||||
reject()
|
||||
})
|
||||
writeStream.on('finish', () => {
|
||||
writeStream.end()
|
||||
myRequest = null
|
||||
if (receivedBytes === totalBytes) {
|
||||
if (isWebp) {
|
||||
webp.dwebp(dstpath, dstpath.replace('webp', 'jpg'), '-o', (status) => {
|
||||
// status 101->fails || 100->successful
|
||||
if (status === '100') {
|
||||
deleteDownLoadFile(dstpath)
|
||||
resolve(dstpath.replace('webp', 'jpg'))
|
||||
} else {
|
||||
reject()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolve(dstpath)
|
||||
}
|
||||
} else {
|
||||
deleteDownLoadFile(dstpath)
|
||||
reject()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
export const cancelDownloadPic = function () {
|
||||
return new Promise((resolve) => {
|
||||
if (myRequest) {
|
||||
myRequest.abort()
|
||||
deleteDownLoadFile(currentSaveFilePath)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function deleteDownLoadFile(filePath){
|
||||
try {
|
||||
// 取消下载的时候删除图片
|
||||
if (fs.existsSync(filePath)){
|
||||
fs.unlink(filePath, (err) => {
|
||||
if (err) {
|
||||
console.log('图片已删除')
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
1
src/get-image/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
db0822f1-20bc-4004-a84d-3b55ee4d9c18
|
||||
131
src/get-image/500px.js
Executable file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* pexels网站 https://500px.com/
|
||||
*/
|
||||
|
||||
|
||||
// 搜索
|
||||
// https://api.500px.com/v1/photos/search?type=photos&term=cat&image_size%5B%5D=1&image_size%5B%5D=2&image_size%5B%5D=32&image_size%5B%5D=31&image_size%5B%5D=33&image_size%5B%5D=34&image_size%5B%5D=35&image_size%5B%5D=36&image_size%5B%5D=2048&image_size%5B%5D=4&image_size%5B%5D=14&include_states=true&formats=jpeg%2Clytro&include_tags=true&exclude_nude=true&page=1&rpp=50
|
||||
|
||||
|
||||
// 热门
|
||||
// https: //api.500px.com/v1/photos?rpp=50&feature=popular&image_size%5B%5D=1&image_size%5B%5D=2&image_size%5B%5D=32&image_size%5B%5D=31&image_size%5B%5D=33&image_size%5B%5D=34&image_size%5B%5D=35&image_size%5B%5D=36&image_size%5B%5D=2048&image_size%5B%5D=4&image_size%5B%5D=14&sort=&include_states=true&include_licensing=true&formats=jpeg%2Clytro&only=&exclude=&personalized_categories=&page=1&rpp=50
|
||||
|
||||
|
||||
const axios = require('axios')
|
||||
const cheerio = require('cheerio')
|
||||
|
||||
const { axiosGet } = require('../utils/axios')
|
||||
|
||||
const { CancelToken } = axios
|
||||
let source = null
|
||||
|
||||
let cookies = ''
|
||||
let csrToken = ''
|
||||
let htmlAddress = ''
|
||||
|
||||
/**
|
||||
* 先获取页面取得cookie等信息
|
||||
* @param {*} data
|
||||
*/
|
||||
function getHtmlPage(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (data.searchKey) {
|
||||
htmlAddress = `https://500px.com/search?submit=%E6%8F%90%E4%BA%A4&q=${data.searchKey}&type=photos`
|
||||
} else {
|
||||
htmlAddress = 'https://500px.com/popular'
|
||||
}
|
||||
axios.get(htmlAddress).then((result) => {
|
||||
cookies = result.headers['set-cookie']
|
||||
const $ = cheerio.load(result.data)
|
||||
csrToken = $('meta[name="csrf-token"]')[0].attribs.content
|
||||
resolve()
|
||||
}).catch((error) => {
|
||||
console.log('-------------------500px获取cookie出错')
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const getImage = async function (data) {
|
||||
if (cookies === '') {
|
||||
await getHtmlPage(data)
|
||||
}
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (!data) {
|
||||
resolve([])
|
||||
}
|
||||
let baseUrl = 'https://api.500px.com/v1/photos'
|
||||
const params = {
|
||||
image_size: [100, 200, 400, 600, 1600, 2048, 2500, 3000, 4096, 4500, 5120, 5500, 6144, 7168],
|
||||
page: data.page,
|
||||
rpp: 50, // 单页条数
|
||||
formats: 'jpeg,lytro'
|
||||
}
|
||||
if (data.searchKey) {
|
||||
baseUrl = 'https://api.500px.com/v1/photos/search'
|
||||
params.type = 'photos'
|
||||
params.term = data.searchKey
|
||||
params.include_tags = true
|
||||
params.exclude_nude = true
|
||||
} else {
|
||||
baseUrl = 'https://api.500px.com/v1/photos'
|
||||
params.feature = 'popular'
|
||||
params.only = 'All photographers,Pulse'
|
||||
params.include_licensing = true
|
||||
params.include_states = true
|
||||
}
|
||||
source = CancelToken.source()
|
||||
axiosGet({
|
||||
url: baseUrl,
|
||||
params,
|
||||
responseType: 'json',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Origin: 'https://500px.com',
|
||||
Referer: htmlAddress,
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
|
||||
'x-csrf-token': null,
|
||||
cookie: cookies
|
||||
},
|
||||
cancelToken: source.token
|
||||
}).then((result) => {
|
||||
source = null
|
||||
const urls = []
|
||||
const { photos } = result
|
||||
photos.forEach((item) => {
|
||||
const obj = {
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
url: '',
|
||||
downloadUrl: '',
|
||||
}
|
||||
const { images } = item
|
||||
let maxSize = 0
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
if (images[i].size >= 200 && images[i].size <= 700) {
|
||||
obj.url = images[i].https_url
|
||||
}
|
||||
const realSize = images[i].https_url.match(/m%3D(\d*)/)
|
||||
if (realSize && realSize[1]){
|
||||
if (parseInt(realSize[1], 10) > maxSize) {
|
||||
obj.downloadUrl = images[i].https_url
|
||||
}
|
||||
maxSize = parseInt(realSize[1], 10)
|
||||
}
|
||||
}
|
||||
urls.push(obj)
|
||||
})
|
||||
resolve(urls)
|
||||
}).catch((err) => {
|
||||
source = null
|
||||
console.log('------------请求失败500px:', baseUrl)
|
||||
reject()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const cancelImage = function () {
|
||||
if (source) {
|
||||
source.cancel()
|
||||
}
|
||||
}
|
||||
73
src/get-image/nasa.js
Executable file
@@ -0,0 +1,73 @@
|
||||
/* eslint-disable max-len */
|
||||
|
||||
const BASEPARAMS = {
|
||||
size: 50,
|
||||
from: 0,
|
||||
sort: 'promo-date-time:desc',
|
||||
q: '((ubernode-type:image) AND (routes:1446))',
|
||||
_source_include: 'promo-date-time,master-image,nid,title,topics,missions,collections,other-tags,ubernode-type,primary-tag,secondary-tag,cardfeed-title,type,collection-asset-link,link-or-attachment,pr-leader-sentence,image-feature-caption,attachments,uri'
|
||||
}
|
||||
|
||||
const BASEURL = 'https://www.nasa.gov/api/2/ubernode/_search'
|
||||
|
||||
const PUBLICURL = 'https://www.nasa.gov/sites/default/files/styles/image_card_4x3_ratio/public/'
|
||||
const DOWNLOADPUBLICURL = 'https://www.nasa.gov/sites/default/files/'
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
const { CancelToken } = axios
|
||||
let source = null
|
||||
|
||||
const { axiosGet } = require('../utils/axios')
|
||||
|
||||
export const getImage = function (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!data) {
|
||||
resolve([])
|
||||
return
|
||||
}
|
||||
const baseUrl = BASEURL
|
||||
source = CancelToken.source()
|
||||
axiosGet({
|
||||
url: baseUrl,
|
||||
params: {
|
||||
...BASEPARAMS,
|
||||
from: (data.page * BASEPARAMS.size)
|
||||
},
|
||||
cancelToken: source.token
|
||||
}).then((result) => {
|
||||
source = null
|
||||
|
||||
const { hits: { hits } } = result
|
||||
const urls = []
|
||||
|
||||
hits.forEach((item) => {
|
||||
const { _source: { 'master-image': imageData } } = item
|
||||
const { width, height, uri } = imageData
|
||||
const obj = {
|
||||
width,
|
||||
height,
|
||||
url: uri.replace('public://', PUBLICURL),
|
||||
downloadUrl: uri.replace('public://', DOWNLOADPUBLICURL),
|
||||
}
|
||||
urls.push(obj)
|
||||
})
|
||||
resolve(urls)
|
||||
}).catch((error) => {
|
||||
source = null
|
||||
console.log('------------请求失败nasa:', error)
|
||||
reject()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// getImage({
|
||||
// page: 0,
|
||||
// searchKey: ''
|
||||
// })
|
||||
|
||||
export const cancelImage = function () {
|
||||
if (source) {
|
||||
source.cancel()
|
||||
}
|
||||
}
|
||||
68
src/get-image/paper.js
Executable file
@@ -0,0 +1,68 @@
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
const { CancelToken } = axios
|
||||
let source = null
|
||||
|
||||
const { axiosGet } = require('../utils/axios')
|
||||
|
||||
export const getPaperSetting = function (data){
|
||||
const returnResult = []
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosGet({
|
||||
url: 'https://service.paper.meiyuan.in/api/v2/columns'
|
||||
}).then((result) => {
|
||||
for (const item of result){
|
||||
returnResult.push({
|
||||
name: item.langs['zh-Hans-CN'],
|
||||
value: item._id
|
||||
})
|
||||
}
|
||||
resolve(returnResult)
|
||||
}).catch(() => {
|
||||
resolve(returnResult)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const getImage = function (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!data || !data.searchKey) {
|
||||
resolve([])
|
||||
return
|
||||
}
|
||||
const baseUrl = `https://service.paper.meiyuan.in/api/v2/columns/flow/${data.searchKey}`
|
||||
source = CancelToken.source()
|
||||
axiosGet({
|
||||
url: baseUrl,
|
||||
params: {
|
||||
page: data.page + 1,
|
||||
per_page: 50
|
||||
},
|
||||
cancelToken: source.token
|
||||
}).then((result) => {
|
||||
source = null
|
||||
const urls = []
|
||||
result.forEach((item) => {
|
||||
const obj = {
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
url: item.urls.small,
|
||||
downloadUrl: item.urls.raw,
|
||||
}
|
||||
urls.push(obj)
|
||||
})
|
||||
resolve(urls)
|
||||
}).catch((error) => {
|
||||
source = null
|
||||
console.log('------------请求失败paper:', baseUrl, data)
|
||||
reject()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const cancelImage = function () {
|
||||
if (source) {
|
||||
source.cancel()
|
||||
}
|
||||
}
|
||||
100
src/get-image/pexels.js
Executable file
@@ -0,0 +1,100 @@
|
||||
/** *
|
||||
* pexels网站 https://www.pexels.com
|
||||
*/
|
||||
|
||||
const cheerio = require('cheerio')
|
||||
const { request } = require('http2-client')
|
||||
|
||||
// 下一页的时间参数
|
||||
let nextPageSeed = ''
|
||||
// 请求对象
|
||||
let reqObject = null
|
||||
|
||||
const analysisResult = function (result){
|
||||
const urls = []
|
||||
const $ = cheerio.load(result)
|
||||
if ($('.next_page').length){
|
||||
nextPageSeed = $('.next_page')[0].attribs.href
|
||||
}
|
||||
const imageItems = $('.photo-item__img')
|
||||
// 是否存在
|
||||
if (nextPageSeed.length){
|
||||
const imageItemsLength = imageItems.length
|
||||
for (let i = 0; i < imageItemsLength; i++){
|
||||
const { attribs } = imageItems[i]
|
||||
if (attribs['data-big-src']){
|
||||
const obj = {
|
||||
width: attribs['data-image-width'],
|
||||
height: attribs['data-image-height'],
|
||||
url: attribs['data-large-src'],
|
||||
downloadUrl: attribs['data-big-src'].split('?')[0]
|
||||
}
|
||||
urls.push(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
return urls
|
||||
}
|
||||
|
||||
|
||||
export const getImage = function (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!data) {
|
||||
resolve([])
|
||||
}
|
||||
if (data.page === 0){
|
||||
nextPageSeed = ''
|
||||
}
|
||||
let baseUrl = 'https://www.pexels.com'
|
||||
if (data.searchKey) {
|
||||
baseUrl = `https://www.pexels.com/search/${data.searchKey}`
|
||||
}
|
||||
const url = baseUrl + nextPageSeed
|
||||
console.log('------------', url)
|
||||
|
||||
reqObject = request(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36',
|
||||
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||
cookie: '__cfduid=dc0c8a5d9efdac6eb0e5b49745a6ce78e1579152913;'
|
||||
+ 'locale=en-US; _ga=GA1.2.727888903.1579152916;'
|
||||
+ '_gid=GA1.2.1309891260.1579152916; _fbp=fb.1.1579152916921.482810349;'
|
||||
+ '_hjid=dac493c8-a7f3-4834-9d25-10ef85de0227; _gat=1',
|
||||
},
|
||||
}, (res) => {
|
||||
const { http2Clients } = reqObject.getGlobalManager({})
|
||||
if (res.statusCode === 200){
|
||||
res.setEncoding('utf8')
|
||||
let resultData = ''
|
||||
res.on('data', (chunk) => { resultData += chunk })
|
||||
res.on('end', () => {
|
||||
Object.values(http2Clients).forEach((i) => { i.close() })
|
||||
try {
|
||||
reqObject = null
|
||||
resolve(analysisResult(resultData))
|
||||
} catch (error) {
|
||||
console.log('------------解析失败pexels:')
|
||||
reject()
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
console.log('------------请求失败pexels:')
|
||||
reject()
|
||||
Object.values(http2Clients).forEach((i) => { i.close() })
|
||||
reqObject = null
|
||||
}
|
||||
res.end()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const cancelImage = function () {
|
||||
if (reqObject && reqObject.getGlobalManager) {
|
||||
const { http2Clients } = reqObject.getGlobalManager({})
|
||||
Object.values(http2Clients).forEach((i) => { i.close() })
|
||||
}
|
||||
}
|
||||
53
src/get-image/search.js
Executable file
@@ -0,0 +1,53 @@
|
||||
import { apiTranslation } from '../api/api'
|
||||
import { imageSourceType } from '../utils/utils'
|
||||
|
||||
let type = ''
|
||||
|
||||
const pexels = require('./pexels')
|
||||
const fiveHundred = require('./500px')
|
||||
const paper = require('./paper')
|
||||
const unsplash = require('./unsplash')
|
||||
const wallhaven = require('./wallhaven')
|
||||
const nasa = require('./nasa')
|
||||
const themoviedb = require('./themoviedb')
|
||||
|
||||
const cancelFn = {
|
||||
pexels: pexels.cancelImage,
|
||||
'500px': fiveHundred.cancelImage,
|
||||
paper: paper.cancelImage,
|
||||
unsplash: unsplash.cancelImage,
|
||||
wallhaven: unsplash.cancelImage,
|
||||
nasa: nasa.cancelImage,
|
||||
themoviedb: themoviedb.cancelImage
|
||||
}
|
||||
|
||||
const getUrl = {
|
||||
pexels: pexels.getImage,
|
||||
'500px': fiveHundred.getImage,
|
||||
paper: paper.getImage,
|
||||
unsplash: unsplash.getImage,
|
||||
wallhaven: wallhaven.getImage,
|
||||
nasa: nasa.getImage,
|
||||
themoviedb: themoviedb.getImage
|
||||
}
|
||||
|
||||
export const getUrls = function (data) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
type = data.imageSource
|
||||
const currentImageSource = imageSourceType.find(i => i.value === type)
|
||||
data.searchKey = currentImageSource.isSupportChinaSearch ? data.searchKey : await apiTranslation(data.searchKey)
|
||||
getUrl[type](data).then((urls) => {
|
||||
resolve(urls)
|
||||
}).catch((error) => {
|
||||
reject(error)
|
||||
}).finally(() => {
|
||||
type = ''
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const cancelUrls = function () {
|
||||
if (type !== '') {
|
||||
cancelFn[type]()
|
||||
}
|
||||
}
|
||||
102
src/get-image/themoviedb.js
Executable file
@@ -0,0 +1,102 @@
|
||||
/* eslint-disable max-len */
|
||||
|
||||
import userConfig from '../../.user-config'
|
||||
|
||||
const { themoviedbAppKey } = userConfig
|
||||
const APIKEY = themoviedbAppKey
|
||||
const MOVELISTAPI = 'https://api.themoviedb.org/3/discover/movie'
|
||||
const ALLSEARCHAPI = 'https://api.themoviedb.org/3/search/multi'
|
||||
const MOVELISTPARAMS = {
|
||||
api_key: APIKEY,
|
||||
language: 'zh-CN',
|
||||
sort_by: 'popularity.desc',
|
||||
include_adult: false,
|
||||
include_video: false,
|
||||
page: 1
|
||||
}
|
||||
|
||||
const BASEIMAGEDOWNURL = 'https://image.tmdb.org/t/p/original'
|
||||
const BASEIMAGEURL = 'https://image.tmdb.org/t/p/w500'
|
||||
|
||||
// const GETMOVEIMAGEURL='https://api.themoviedb.org/3/movie/${moveid}/images?api_key='
|
||||
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
const { CancelToken } = axios
|
||||
let source = null
|
||||
|
||||
|
||||
const { axiosGet } = require('../utils/axios')
|
||||
|
||||
const getImages = function (movieId, type){
|
||||
return new Promise((resolve) => {
|
||||
axiosGet({
|
||||
url: `https://api.themoviedb.org/3/${type}/${movieId}/images`,
|
||||
params: {
|
||||
api_key: APIKEY
|
||||
},
|
||||
}).then((result) => {
|
||||
const { backdrops } = result
|
||||
const urls = []
|
||||
backdrops.forEach((item) => {
|
||||
const { width, height, file_path: filePath } = item
|
||||
urls.push({
|
||||
width,
|
||||
height,
|
||||
url: `${BASEIMAGEURL}${filePath}`,
|
||||
downloadUrl: `${BASEIMAGEDOWNURL}${filePath}`,
|
||||
})
|
||||
})
|
||||
resolve(urls)
|
||||
}).catch((err) => {
|
||||
resolve([])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const getImage = function (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!data) {
|
||||
resolve([])
|
||||
return
|
||||
}
|
||||
source = CancelToken.source()
|
||||
let url = MOVELISTAPI
|
||||
let params = {
|
||||
...MOVELISTPARAMS,
|
||||
page: data.page + 1
|
||||
}
|
||||
if (data.searchKey){
|
||||
url = ALLSEARCHAPI
|
||||
params = {
|
||||
api_key: APIKEY,
|
||||
// language: 'zh-CN',
|
||||
page: data.page + 1,
|
||||
include_adult: false,
|
||||
query: data.searchKey
|
||||
}
|
||||
}
|
||||
axiosGet({ url, params, cancelToken: source.token }).then(async (result) => {
|
||||
const { results } = result
|
||||
let urls = []
|
||||
await Promise.all(results.map(async (item) => {
|
||||
const { id, media_type: mediaType = 'movie' } = item
|
||||
const movieImages = await getImages(id, mediaType)
|
||||
urls = [...movieImages, ...urls]
|
||||
return Promise.resolve
|
||||
}))
|
||||
resolve(urls)
|
||||
}).catch((error) => {
|
||||
source = null
|
||||
console.log('------------请求失败tmdb:', error)
|
||||
reject()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const cancelImage = function () {
|
||||
if (source) {
|
||||
source.cancel()
|
||||
}
|
||||
}
|
||||
87
src/get-image/unsplash.js
Executable file
@@ -0,0 +1,87 @@
|
||||
/** *
|
||||
* pexels网站 https://unsplash.com/t/wallpapers
|
||||
*
|
||||
*
|
||||
* 获取壁纸
|
||||
* https://unsplash.com/napi/collections/1065976/photos?
|
||||
* page=6
|
||||
* per_page=10
|
||||
* order_by=latest
|
||||
* share_key=a4a197fc196734b74c9d87e48cc86838
|
||||
*
|
||||
* 主图片
|
||||
* https://unsplash.com/napi/photos?page=3&per_page=12
|
||||
*
|
||||
*
|
||||
*
|
||||
* 搜索
|
||||
* https://unsplash.com/napi/search?query=cat&xp=&per_page=20
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
const { CancelToken } = axios
|
||||
let source = null
|
||||
|
||||
const { axiosGet } = require('../utils/axios')
|
||||
|
||||
export const getImage = function (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!data) {
|
||||
resolve([])
|
||||
}
|
||||
let baseUrl = 'https://unsplash.com/napi/collections/1065976/photos'
|
||||
let searchFalg = false
|
||||
let params = {
|
||||
page: data.page,
|
||||
order_by: 'latest',
|
||||
per_page: 50,
|
||||
share_key: 'a4a197fc196734b74c9d87e48cc86838'
|
||||
}
|
||||
if (data.searchKey) {
|
||||
baseUrl = 'https://unsplash.com/napi/search/photos'
|
||||
searchFalg = true
|
||||
params = {
|
||||
query: data.searchKey,
|
||||
xp: '',
|
||||
per_page: 50,
|
||||
page: data.page,
|
||||
}
|
||||
}
|
||||
source = CancelToken.source()
|
||||
axiosGet({
|
||||
url: baseUrl,
|
||||
params,
|
||||
cancelToken: source.token
|
||||
}).then((result) => {
|
||||
source = null
|
||||
const urls = []
|
||||
let newRes = result
|
||||
if (searchFalg){
|
||||
newRes = result.results
|
||||
}
|
||||
newRes.forEach((item) => {
|
||||
const obj = {
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
url: item.urls.small,
|
||||
downloadUrl: item.urls.full,
|
||||
}
|
||||
urls.push(obj)
|
||||
})
|
||||
resolve(urls)
|
||||
}).catch(() => {
|
||||
source = null
|
||||
console.log('------------请求失败unsplash:', baseUrl)
|
||||
reject()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const cancelImage = function () {
|
||||
if (source) {
|
||||
source.cancel()
|
||||
}
|
||||
}
|
||||
83
src/get-image/wallhaven.js
Executable file
@@ -0,0 +1,83 @@
|
||||
/** *
|
||||
* https://wallhaven.cc
|
||||
*
|
||||
*
|
||||
* 获取壁纸
|
||||
* https://wallhaven.cc/latest?
|
||||
* page=2
|
||||
*
|
||||
*
|
||||
* 搜索
|
||||
* https://wallhaven.cc/search?q=cat&categories=111&purity=100&sorting=date_added&order=desc
|
||||
* page=2
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const axios = require('axios')
|
||||
const cheerio = require('cheerio')
|
||||
|
||||
const { CancelToken } = axios
|
||||
let source = null
|
||||
|
||||
const { axiosGet } = require('../utils/axios')
|
||||
|
||||
export const getImage = function (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!data) {
|
||||
resolve([])
|
||||
}
|
||||
let baseUrl = 'https://wallhaven.cc/latest'
|
||||
let params = {}
|
||||
if (data.page > 0){
|
||||
params.page = data.page + 1
|
||||
}
|
||||
if (data.searchKey) {
|
||||
baseUrl = 'https://wallhaven.cc/search'
|
||||
params = {
|
||||
...params,
|
||||
q: data.searchKey,
|
||||
categories: 111,
|
||||
purity: 100,
|
||||
sorting: 'date_added',
|
||||
order: 'desc'
|
||||
}
|
||||
}
|
||||
source = CancelToken.source()
|
||||
axiosGet({
|
||||
url: baseUrl,
|
||||
params,
|
||||
cancelToken: source.token
|
||||
}).then((result) => {
|
||||
source = null
|
||||
const urls = []
|
||||
const $ = cheerio.load(result)
|
||||
|
||||
$('figure').each((index, node) => {
|
||||
const wallpaperId = node.attribs['data-wallpaper-id']
|
||||
const url = $(node).find('img').attr('data-src')
|
||||
const isPng = Boolean($(node).find('.png').length)
|
||||
const [width, height] = $(node).find('.wall-res').html().split('x')
|
||||
const downloadUrl = `https://w.wallhaven.cc/full/${wallpaperId.slice(0, 2)}/wallhaven-${wallpaperId}.${isPng ? 'png' : 'jpg'}`
|
||||
const obj = {
|
||||
width: width.trim(),
|
||||
height: height.trim(),
|
||||
url,
|
||||
downloadUrl,
|
||||
}
|
||||
urls.push(obj)
|
||||
})
|
||||
resolve(urls)
|
||||
}).catch(() => {
|
||||
source = null
|
||||
console.log('------------请求失败wallhaven:', baseUrl)
|
||||
reject()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const cancelImage = function () {
|
||||
if (source) {
|
||||
source.cancel()
|
||||
}
|
||||
}
|
||||
24
src/index.ejs
Executable file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Strawberry Wallpaper</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 -->
|
||||
<% if (!process.browser) { %>
|
||||
<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
src/main/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
ea3afe40-4434-4a1e-8de1-7776424a00b8
|
||||
58
src/main/full-window.js
Executable file
@@ -0,0 +1,58 @@
|
||||
const electron = require('electron')
|
||||
const { baseUrl } = require('../utils/utils')
|
||||
|
||||
const { BrowserWindow } = electron
|
||||
|
||||
let fullWindow = null
|
||||
|
||||
/**
|
||||
* 创建窗口
|
||||
* @function createWindow
|
||||
*/
|
||||
function createWindow() {
|
||||
fullWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 700,
|
||||
frame: false,
|
||||
maximizable: true,
|
||||
minimizable: true,
|
||||
// fullscreenable: true,
|
||||
// fullscreen: true,
|
||||
})
|
||||
fullWindow.loadURL(`${baseUrl}#/full`)
|
||||
|
||||
fullWindow.on('close', () => {
|
||||
fullWindow = null
|
||||
})
|
||||
|
||||
fullWindow.on('enter-full-screen', () => {
|
||||
// console.log('Jin人员')
|
||||
// fullWindow.setWindowButtonVisibility(true)
|
||||
})
|
||||
}
|
||||
|
||||
function openWindow(){
|
||||
if (!fullWindow){
|
||||
createWindow()
|
||||
// fullWindow.openDevTools()
|
||||
}
|
||||
else {
|
||||
fullWindow.show()
|
||||
}
|
||||
}
|
||||
|
||||
function closeWindow(){
|
||||
if (fullWindow){
|
||||
fullWindow.hide()
|
||||
}
|
||||
}
|
||||
|
||||
function getWindow(){
|
||||
return fullWindow
|
||||
}
|
||||
|
||||
export default {
|
||||
openWindow,
|
||||
closeWindow,
|
||||
getWindow,
|
||||
}
|
||||
18
src/main/index.dev.js
Executable file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
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')
|
||||
532
src/main/index.js
Executable file
@@ -0,0 +1,532 @@
|
||||
import fullWindow from './full-window'
|
||||
|
||||
const electron = require('electron')
|
||||
|
||||
const { app, BrowserWindow, Tray, ipcMain, dialog } = electron
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { autoUpdater } = require('electron-updater')
|
||||
const log = require('electron-log')
|
||||
const { setCurrentWallpaper, changeWallpaperScale } = require('../wallpaper/outwallpaper')
|
||||
const { openAutoStart, openDisStart } = require('../file/auto-open')
|
||||
const { downloadPic, cancelDownloadPic } = require('../file/file')
|
||||
const { getUrls, cancelUrls } = require('../get-image/search')
|
||||
const { newEmail } = require('./mail')
|
||||
|
||||
const { isDev, isMac, isWin, baseUrl } = require('../utils/utils')
|
||||
const { getPaperSetting } = require('../get-image/paper')
|
||||
|
||||
log.transports.file.level = 'info'
|
||||
|
||||
|
||||
let mainWindow = null
|
||||
// 托盘对象
|
||||
let appTray = null
|
||||
let openAppFlag = true
|
||||
let currentScreenIndex = 0 // 当前屏幕的索引
|
||||
|
||||
const mainCallBack = {
|
||||
'autoUpdater.downloadUpdate': () => {
|
||||
autoUpdater.downloadUpdate()
|
||||
},
|
||||
}
|
||||
|
||||
appOpenInit()
|
||||
ipcMainInit()
|
||||
autoUpdaterInit()
|
||||
setTimeIntervalInit()
|
||||
|
||||
|
||||
/**
|
||||
* 创建程序锁,保证只能打开单个实例
|
||||
* @function appOpenInit
|
||||
*/
|
||||
function appOpenInit(){
|
||||
if (isWin()) {
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
} else {
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
if (mainWindow) {
|
||||
if (!mainWindow.isVisible()) {
|
||||
mainWindowShow()
|
||||
}
|
||||
mainWindow.focus()
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if (isMac()) {
|
||||
app.dock.hide()
|
||||
}
|
||||
app.on('ready', () => {
|
||||
// fullWindow.openWindow()
|
||||
setTimeout(() => {
|
||||
if (!isDev()) {
|
||||
autoUpdater.logger = log
|
||||
autoUpdater.autoDownload = false
|
||||
checkUpdater()
|
||||
}
|
||||
appInit()
|
||||
}, 10)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
app.on('activate', () => {
|
||||
if (mainWindow === null) {
|
||||
appInit()
|
||||
} else {
|
||||
mainWindowShow()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建窗口
|
||||
* @function createWindow
|
||||
*/
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
height: 600,
|
||||
width: 310,
|
||||
frame: false,
|
||||
transparent: true,
|
||||
show: false,
|
||||
alwaysOnTop: true,
|
||||
resizable: false, // 禁止变化尺寸
|
||||
hasShadow: true, // 是否阴影
|
||||
focusable: true,
|
||||
fullscreenable: false,
|
||||
skipTaskbar: true,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
closable: false,
|
||||
fullscreen: false,
|
||||
titleBarStyle: 'customButtonsOnHover'
|
||||
})
|
||||
|
||||
// mainWindow.openDevTools()
|
||||
|
||||
mainWindow.loadURL(baseUrl)
|
||||
|
||||
mainWindow.on('blur', () => {
|
||||
mainWindow.hide()
|
||||
})
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
app.quit()
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置定时器
|
||||
*/
|
||||
function setTimeIntervalInit(){
|
||||
// 10s执行一次
|
||||
setInterval(() => {
|
||||
sendData('intervalTime')
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Tray
|
||||
* @function createAppTray
|
||||
*/
|
||||
function createAppTray() {
|
||||
if (isMac()) {
|
||||
// eslint-disable-next-line no-undef
|
||||
appTray = new Tray(path.resolve(__static, './img/trayTemplate.png'))
|
||||
} else if (isWin()) {
|
||||
// eslint-disable-next-line no-undef
|
||||
appTray = new Tray(path.resolve(__static, './img/tray.png'))
|
||||
}
|
||||
|
||||
// 系统托盘图标目录
|
||||
appTray.on('click', (event, bounds, position) => {
|
||||
// mainWindow === null ? createWindow() : mainWindow.close()
|
||||
// return
|
||||
// 点击时显示窗口,并修改窗口的显示位置
|
||||
function setMainWinPosition(win, trayBounds) {
|
||||
try {
|
||||
const { screen } = electron
|
||||
const winWidth = mainWindow.getSize()[0]
|
||||
const winHeight = mainWindow.getSize()[1]
|
||||
const cursorPosition = screen.getCursorScreenPoint()
|
||||
const currentScreen = screen.getDisplayNearestPoint(cursorPosition)
|
||||
const screenLists = screen.getAllDisplays()
|
||||
|
||||
currentScreenIndex = screenLists.findIndex(i => i.id === currentScreen.id)
|
||||
|
||||
|
||||
// 保证永远在图标的中心位置,因为没有做其他方向的三角,所以暂不考虑高
|
||||
cursorPosition.x = trayBounds.x + trayBounds.width / 2
|
||||
const parallelType = cursorPosition.x < currentScreen.bounds.x + currentScreen.workAreaSize.width / 2 ? 'left' : 'right'
|
||||
const verticaType = cursorPosition.y < currentScreen.bounds.y + currentScreen.workAreaSize.height / 2 ? 'top' : 'bottom'
|
||||
|
||||
let trayPositionType = '' // 任务栏的位置 top|bottom|left|right
|
||||
let trayPositionSize = 0 // 任务栏的尺寸
|
||||
|
||||
if (currentScreen.workAreaSize.height < currentScreen.size.height) {
|
||||
trayPositionType = verticaType === 'top' ? 'top' : 'bottom'
|
||||
trayPositionSize = currentScreen.size.height - currentScreen.workAreaSize.height
|
||||
} else if (currentScreen.workAreaSize.width < currentScreen.size.width) {
|
||||
trayPositionType = parallelType === 'left' ? 'left' : 'right'
|
||||
trayPositionSize = currentScreen.size.width - currentScreen.workAreaSize.width
|
||||
}
|
||||
let winPositionX = 0
|
||||
let winPositionY = 0
|
||||
if (trayPositionType === 'top') {
|
||||
winPositionX = Math.max(Math.min(currentScreen.bounds.width + currentScreen.bounds.x - winWidth, cursorPosition.x - (winWidth / 2)), currentScreen.bounds.x)
|
||||
winPositionY = currentScreen.bounds.y + trayPositionSize + 2
|
||||
} else if (trayPositionType === 'bottom') {
|
||||
winPositionX = Math.max(Math.min(currentScreen.bounds.width + currentScreen.bounds.x - winWidth, cursorPosition.x - (winWidth / 2)), currentScreen.bounds.x)
|
||||
winPositionY = currentScreen.bounds.height + currentScreen.bounds.y - trayPositionSize - winHeight
|
||||
} else if (trayPositionType === 'left') {
|
||||
winPositionX = currentScreen.bounds.x + trayPositionSize
|
||||
winPositionY = Math.max(Math.min(currentScreen.bounds.height + currentScreen.bounds.y - winHeight, cursorPosition.y - (winHeight / 2)), currentScreen.bounds.y)
|
||||
} else if (trayPositionType === 'right') {
|
||||
winPositionX = currentScreen.bounds.x + currentScreen.bounds.width - trayPositionSize - winWidth
|
||||
winPositionY = Math.max(Math.min(currentScreen.bounds.height + currentScreen.bounds.y - winHeight, cursorPosition.y - (winHeight / 2)), currentScreen.bounds.y)
|
||||
}
|
||||
log.info('--------------------------------')
|
||||
log.info('currentScreen:', currentScreen)
|
||||
log.info('position:', winPositionX, winPositionY)
|
||||
log.info('trayPositionType:', trayPositionType)
|
||||
log.info('trayPositionSize', trayPositionSize)
|
||||
log.info('cursorPosition:', cursorPosition)
|
||||
log.info('--------------------------------')
|
||||
win.setPosition(parseInt(winPositionX, 10), winPositionY)
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (mainWindow.isVisible()) {
|
||||
sendData('datainfo', {
|
||||
type: 'windowShow',
|
||||
data: false
|
||||
})
|
||||
mainWindowHide()
|
||||
} else {
|
||||
sendData('datainfo', {
|
||||
type: 'windowShow',
|
||||
data: true
|
||||
})
|
||||
mainWindowShow()
|
||||
setMainWinPosition(mainWindow, bounds)
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.on('show', () => {
|
||||
appTray.setHighlightMode('never')
|
||||
})
|
||||
mainWindow.on('hide', () => {
|
||||
appTray.setHighlightMode('selection')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function appInit() {
|
||||
if (mainWindow == null) {
|
||||
createWindow() // 创建主窗口
|
||||
} else {
|
||||
mainWindowShow()
|
||||
}
|
||||
if (appTray == null) {
|
||||
createAppTray() // 创建系统托盘
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 给所有的的渲染进程发消息
|
||||
*/
|
||||
function sendData(...args){
|
||||
const fullWindowWindow = fullWindow.getWindow()
|
||||
const windows = [mainWindow, fullWindowWindow]
|
||||
windows.forEach((i) => {
|
||||
if (i){
|
||||
i.webContents.send(...args)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 主窗口显示,创建一个动画效果
|
||||
*/
|
||||
function mainWindowShow() {
|
||||
let opacity = 0
|
||||
mainWindow.show()
|
||||
const time = setInterval(() => {
|
||||
if (opacity >= 1) {
|
||||
opacity = 1
|
||||
clearInterval(time)
|
||||
}
|
||||
mainWindow.setOpacity(opacity)
|
||||
opacity = parseFloat((opacity + 0.1).toFixed(1))
|
||||
}, 80)
|
||||
}
|
||||
|
||||
/**
|
||||
* 主窗口隐藏,创建一个动画效果
|
||||
*/
|
||||
function mainWindowHide() {
|
||||
let opacity = 1
|
||||
const time = setInterval(() => {
|
||||
if (opacity <= 0) {
|
||||
opacity = 0.0
|
||||
clearInterval(time)
|
||||
mainWindow.hide()
|
||||
}
|
||||
mainWindow.setOpacity(opacity)
|
||||
opacity = parseFloat((opacity - 0.1).toFixed(1))
|
||||
}, 80)
|
||||
}
|
||||
|
||||
|
||||
function ipcMainInit() {
|
||||
/** * 主进程传一个字符串给渲染进程,渲染进程在传递事件给主进程 用于主进程中的一些函数回调 */
|
||||
ipcMain.on('maincallback', (event, data, argument) => {
|
||||
if (typeof mainCallBack[data] !== 'undefined') {
|
||||
mainCallBack[data](argument)
|
||||
}
|
||||
})
|
||||
|
||||
// 取消所有请求
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
ipcMain.on('cancelAllRequest', (event, data) => {
|
||||
cancelDownloadPic()
|
||||
cancelUrls()
|
||||
})
|
||||
|
||||
ipcMain.on('fullWindow', (event, data) => {
|
||||
if (data){
|
||||
fullWindow.openWindow()
|
||||
}
|
||||
else {
|
||||
fullWindow.closeWindow()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
ipcMain.on('dataWallpaper', (event, arg) => {
|
||||
downloadPic(arg.downloadUrl, sendData, arg.userConfig).then((filePath) => {
|
||||
const { options } = arg
|
||||
if (isMac() && options.autoSetAllScreens === false){
|
||||
setCurrentWallpaper(filePath, {
|
||||
...options,
|
||||
screen: currentScreenIndex,
|
||||
})
|
||||
}
|
||||
else {
|
||||
setCurrentWallpaper(filePath)
|
||||
}
|
||||
|
||||
log.info(`设置壁纸成功:${filePath}`)
|
||||
event.sender.send('dataWallpaper', 'success')
|
||||
}).catch((error) => {
|
||||
log.error(`设置壁纸失败:${arg.downloadUrl}`)
|
||||
log.error(error)
|
||||
event.sender.send('dataWallpaper', 'error')
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('getImageUrls', (event, data) => {
|
||||
getUrls(data).then((result) => {
|
||||
sendData('datainfo', {
|
||||
type: 'urls',
|
||||
data: result
|
||||
})
|
||||
}).catch(() => {
|
||||
sendData('datainfo', {
|
||||
type: 'urlsError',
|
||||
data: ''
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('btn', (event, data) => {
|
||||
if (data.type === 'quit') {
|
||||
// 窗口设置了closeable为false后不能退出程序,手动再设置一下
|
||||
mainWindow.setClosable(true)
|
||||
app.quit()
|
||||
// eslint-disable-next-line no-empty
|
||||
} else if (data.type === 'searchKey') {
|
||||
|
||||
} else if (data.type === 'openStart') {
|
||||
if (data.data) {
|
||||
openAutoStart()
|
||||
} else {
|
||||
openDisStart()
|
||||
}
|
||||
} else if (data.type === 'newEmail') {
|
||||
newEmail(data.data.data, data.data.telUser, {
|
||||
version: autoUpdater.currentVersion,
|
||||
emailType: data.data.emailType
|
||||
}).then(() => {
|
||||
event.sender.send('sendnewEmail', 'success', data.data.emailType)
|
||||
}).catch((error) => {
|
||||
event.sender.send('sendnewEmail', 'error', data.data.emailType, error)
|
||||
})
|
||||
} else if (data.type === 'checkNewVersion') {
|
||||
checkUpdater()
|
||||
}
|
||||
else if (data.type === 'setDefaultDownPath'){
|
||||
mainWindow.setAlwaysOnTop(false)
|
||||
dialog.showOpenDialog({
|
||||
properties: ['openDirectory', 'createDirectory', 'promptToCreate'],
|
||||
message: '选择要下载图片所在文件夹',
|
||||
defaultPath: data.data },
|
||||
(paths) => {
|
||||
mainWindow.setAlwaysOnTop(true)
|
||||
if (paths){
|
||||
// 清空原目录中的文件
|
||||
delPath(data.data)
|
||||
event.sender.send('defaultPath', paths[0])
|
||||
}
|
||||
}, mainWindow)
|
||||
}
|
||||
else if (data.type === 'deleteFile'){
|
||||
delPath(data.data)
|
||||
}
|
||||
|
||||
else if (data.type === 'changeWallpaperScale'){
|
||||
changeWallpaperScale({ scale: data.data })
|
||||
}
|
||||
})
|
||||
|
||||
// 渲染函数运行过来
|
||||
ipcMain.on('runFunc', async (event, data) => {
|
||||
// 存放一些函数
|
||||
const FUNCLIST = {
|
||||
getPaperSetting, // 获取paper的设置
|
||||
}
|
||||
if (FUNCLIST[data]){
|
||||
FUNCLIST[data]().then((result) => {
|
||||
event.returnValue = result
|
||||
}).catch(() => {
|
||||
event.returnValue = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function checkUpdater() {
|
||||
autoUpdater.checkForUpdates().then((result) => {
|
||||
}).catch((error) => {
|
||||
log.error(error)
|
||||
})
|
||||
}
|
||||
|
||||
function autoUpdaterInit() {
|
||||
/** * 下载完成 */
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
autoUpdater.quitAndInstall()
|
||||
})
|
||||
|
||||
autoUpdater.on('error', (info) => {
|
||||
if (openAppFlag) {
|
||||
openAppFlag = false
|
||||
return
|
||||
}
|
||||
dialog.showMessageBox({
|
||||
type: 'error',
|
||||
buttons: ['关闭'],
|
||||
title: '版本更新',
|
||||
message: '版本更新检测出错',
|
||||
detail: '可能是网路不好或者版本Bug,请提交意见反馈',
|
||||
// eslint-disable-next-line no-undef
|
||||
icon: path.resolve(__static, './img/banben.png')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
autoUpdater.on('update-available', (info) => {
|
||||
dialog.showMessageBox({
|
||||
type: 'info',
|
||||
buttons: ['是', '否'],
|
||||
title: '版本更新',
|
||||
message: `当前版本:${autoUpdater.currentVersion}`,
|
||||
detail: `检测到新版本:${info.version},是否升级?`,
|
||||
// eslint-disable-next-line no-undef
|
||||
icon: path.resolve(__static, './img/banben.png')
|
||||
}, (response) => {
|
||||
if (response === 0) {
|
||||
autoUpdater.downloadUpdate()
|
||||
} else if (response === 1) {
|
||||
console.log('1')
|
||||
}
|
||||
})
|
||||
log.info('检测到新版本', info)
|
||||
})
|
||||
|
||||
autoUpdater.on('checking-for-update', (info) => {
|
||||
log.info('检测更新已发出', info)
|
||||
})
|
||||
|
||||
|
||||
autoUpdater.on('update-not-available', (info) => {
|
||||
if (openAppFlag) {
|
||||
openAppFlag = false
|
||||
return
|
||||
}
|
||||
log.error('没有检测到新版本', info)
|
||||
dialog.showMessageBox({
|
||||
type: 'info',
|
||||
buttons: ['关闭'],
|
||||
title: '版本更新',
|
||||
message: `当前版本:${autoUpdater.currentVersion}`,
|
||||
detail: '当前已是最新版本,无需更新',
|
||||
// eslint-disable-next-line no-undef
|
||||
icon: path.resolve(__static, './img/banben.png')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// 更新下载进度
|
||||
autoUpdater.on('download-progress', (progressObj) => {
|
||||
sendData('datainfo', {
|
||||
type: 'updaterProgress',
|
||||
data: progressObj.percent
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定目录
|
||||
* @param {String} filePath
|
||||
*/
|
||||
function delPath(filePath){
|
||||
if (!fs.existsSync(filePath)){
|
||||
return '路径不存在'
|
||||
}
|
||||
const info = fs.statSync(filePath)
|
||||
if (info.isDirectory()){ // 目录
|
||||
const data = fs.readdirSync(filePath)
|
||||
if (data.length > 0){
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].match('SW-')){
|
||||
delPath(`${filePath}/${data[i]}`) // 使用递归
|
||||
if (i === data.length - 1){ // 删了目录里的内容就删掉这个目录
|
||||
delPath(`${filePath}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fs.rmdirSync(filePath)// 删除空目录
|
||||
}
|
||||
} else if (info.isFile()){
|
||||
fs.unlinkSync(filePath)// 删除文件
|
||||
}
|
||||
return true
|
||||
}
|
||||
56
src/main/mail.js
Executable file
@@ -0,0 +1,56 @@
|
||||
|
||||
import userConfig from '../../.user-config.js'
|
||||
|
||||
const nodemailer = require('nodemailer')
|
||||
|
||||
const { emailUserName, emailPassword } = userConfig
|
||||
|
||||
|
||||
/**
|
||||
* 发送一封邮件
|
||||
* @param {Object} data 邮件的主体内容
|
||||
* @param {*} telUser 主题中第三个框中的内容
|
||||
* @param {Object} appInfo 邮件的相关信息
|
||||
*/
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function newEmail(data, telUser, appInfo){
|
||||
return new Promise((resolve, reject) => {
|
||||
nodemailer.createTestAccount((err) => {
|
||||
// 建立一个邮箱连接
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: 'smtp.163.com', // 发件箱地址
|
||||
port: 465,
|
||||
secure: true, // true for 465, false for other ports
|
||||
auth: {
|
||||
user: emailUserName, // 用户名
|
||||
pass: emailPassword // 密码
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// 设置发件内容
|
||||
const mailOptions = {
|
||||
from: 'strawberrypaper@163.com', // 发件人地址
|
||||
to: 'strawberrypaper@163.com', // 收件人地址
|
||||
subject: `【${appInfo.emailType}:草莓壁纸】[${appInfo.version}]${telUser}`, // 主题
|
||||
text: '',
|
||||
html: (() => {
|
||||
let html = ''
|
||||
for (const [key, value] of Object.entries(data)){
|
||||
html += `<div><strong>${key}:</strong><span>${value}</span><div>`
|
||||
}
|
||||
return html
|
||||
})()
|
||||
}
|
||||
|
||||
// 发送
|
||||
transporter.sendMail(mailOptions, (error, info) => {
|
||||
if (error || !info) {
|
||||
reject(error.response)
|
||||
} else {
|
||||
resolve(info)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
1
src/renderer/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
61fa188d-1397-4a0e-b2f5-e09587c17998
|
||||
29
src/renderer/App.vue
Executable file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div class="app" id='app'>
|
||||
<keep-alive>
|
||||
<router-view></router-view>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app',
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.app{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
}
|
||||
</style>
|
||||
1
src/renderer/assets/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
71619b91-9748-432f-87e7-53e84fc82618
|
||||
1
src/renderer/assets/css/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
3b45e05a-7aeb-48d3-bd56-1f5499136726
|
||||
100
src/renderer/assets/css/base.css
Executable file
@@ -0,0 +1,100 @@
|
||||
*{
|
||||
margin: 0px;
|
||||
font-family: 'PingFang SC',"Microsoft YaHei";
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html,body,.app{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
}
|
||||
.el-input__inner {
|
||||
border: none;
|
||||
background-color: #383838;
|
||||
color: #a5a5a5;
|
||||
}
|
||||
|
||||
.el-textarea__inner{
|
||||
border: none;
|
||||
background-color: #383838;
|
||||
color: #a5a5a5;
|
||||
}
|
||||
input::-webkit-input-placeholder, textarea::-webkit-input-placeholder {
|
||||
color: #a5a5a5;
|
||||
font-size: 12px;
|
||||
}
|
||||
.el-button--primary{
|
||||
width: 100%;
|
||||
background-color: #383838;
|
||||
border: none;
|
||||
color: #a5a5a5;
|
||||
}
|
||||
|
||||
.el-button--primary:focus, .el-button--primary:hover{
|
||||
background-color: #4d4e4e;
|
||||
border: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
.popper__arrow {
|
||||
border-bottom-color: #383838;
|
||||
}
|
||||
|
||||
.el-popper[x-placement^="bottom"] .popper__arrow::after {
|
||||
border-bottom-color: #383838;
|
||||
}
|
||||
|
||||
.el-popper[x-placement^="bottom"] .popper__arrow {
|
||||
border-bottom-color: #383838;
|
||||
}
|
||||
|
||||
.el-select-dropdown {
|
||||
background-color: #383838;
|
||||
color: #000000;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item.selected {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item.hover,
|
||||
.el-select-dropdown__item:hover {
|
||||
background-color: #767676;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.el-message-box__wrapper{
|
||||
z-index:99999 !important;
|
||||
}
|
||||
.v-modal{
|
||||
z-index:99998 !important;
|
||||
}
|
||||
.el-message{
|
||||
z-index:99997 !important;
|
||||
}
|
||||
|
||||
.page-transition-enter-active,.page-transition-leave-active{
|
||||
transform: translateX(0);
|
||||
transition: transform .3s;
|
||||
}
|
||||
.page-transition-enter, .page-transition-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
transform: translateX(100%);
|
||||
transition: transform .3s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.el-loading-mask{
|
||||
background-color: rgba(255, 255, 255, 0.5) !important;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
.el-loading-spinner i {
|
||||
color: #fff;
|
||||
font-size: 50px;
|
||||
}
|
||||
.el-radio {
|
||||
line-height: 22px;
|
||||
}
|
||||
1
src/renderer/assets/js/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2286d94d-beb4-43dd-a353-4613439e13e4
|
||||
54
src/renderer/assets/js/common-fn.js
Executable file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* @Description: 常用工具函数合集
|
||||
* @Author: --
|
||||
* @Date: 2019-02-14 09:06:39
|
||||
* @LastEditTime: 2019-04-09 10:16:30
|
||||
*/
|
||||
|
||||
/**
|
||||
* 深度克隆一个对象
|
||||
* @param {*} obj
|
||||
* @param {*} cache
|
||||
*/
|
||||
export const deepClone = function (obj, cache = []) {
|
||||
if (obj === null || typeof obj !== 'object') {
|
||||
return obj
|
||||
}
|
||||
const hit = cache.find(c => c.original === obj)
|
||||
if (hit) {
|
||||
return hit.copy
|
||||
}
|
||||
|
||||
const copy = Array.isArray(obj) ? [] : {}
|
||||
cache.push({
|
||||
original: obj,
|
||||
copy
|
||||
})
|
||||
|
||||
Object.keys(obj).forEach((key) => {
|
||||
copy[key] = deepClone(obj[key], cache)
|
||||
})
|
||||
|
||||
return copy
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断类型
|
||||
* @param {*} obj
|
||||
*/
|
||||
export const typeOf = (obj) => {
|
||||
const { toString } = Object.prototype
|
||||
const map = {
|
||||
'[object Boolean]': 'boolean',
|
||||
'[object Number]': 'number',
|
||||
'[object String]': 'string',
|
||||
'[object Function]': 'function',
|
||||
'[object Array]': 'array',
|
||||
'[object Date]': 'date',
|
||||
'[object RegExp]': 'regExp',
|
||||
'[object Undefined]': 'undefined',
|
||||
'[object Null]': 'null',
|
||||
'[object Object]': 'object'
|
||||
}
|
||||
return map[toString.call(obj)]
|
||||
}
|
||||
53
src/renderer/assets/js/local-storage.js
Executable file
@@ -0,0 +1,53 @@
|
||||
|
||||
/**
|
||||
* 储存localStorage
|
||||
* @param {String} name
|
||||
* @param {Object|String|Boolearn|Number} value
|
||||
*/
|
||||
const setStore = (name, value) => {
|
||||
if (!name) {
|
||||
return false
|
||||
}
|
||||
if (typeof value !== 'string') {
|
||||
value = JSON.stringify(value)
|
||||
}
|
||||
window.localStorage.setItem(name, value)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的localstorage
|
||||
* @param {String} name
|
||||
*/
|
||||
const getStore = (name) => {
|
||||
if (!name) return false
|
||||
try {
|
||||
if (window.localStorage.getItem(name) && window.localStorage.getItem(name).length > 1) {
|
||||
const returnString = window.localStorage.getItem(name)
|
||||
try {
|
||||
return JSON.parse(returnString)
|
||||
} catch (error) {
|
||||
return returnString
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定的localStorage
|
||||
* @param {String} name
|
||||
*/
|
||||
const removeStore = (name) => {
|
||||
if (!name || !window.localStorage.getItem(name)) return false
|
||||
window.localStorage.removeItem(name)
|
||||
return true
|
||||
}
|
||||
|
||||
export {
|
||||
setStore,
|
||||
getStore,
|
||||
removeStore
|
||||
}
|
||||
23
src/renderer/assets/js/vue-fn.js
Executable file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* @Description: 函数注册
|
||||
* @Author: --
|
||||
* @Date: 2019-01-21 18:29:06
|
||||
* @LastEditTime: 2019-04-09 20:57:19
|
||||
*/
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
const { ipcRenderer } = require('electron')
|
||||
const localStorage = require('./local-storage')
|
||||
const { deepClone, typeOf } = require('./common-fn')
|
||||
|
||||
export default {
|
||||
version: '0.0.1',
|
||||
install(Vue) {
|
||||
Vue.prototype.$deepClone = deepClone
|
||||
Vue.prototype.$localStorage = localStorage
|
||||
Vue.prototype.$typeOf = typeOf
|
||||
Vue.prototype.$ipcRenderer = ipcRenderer
|
||||
Vue.prototype.$http = axios
|
||||
},
|
||||
}
|
||||
1
src/renderer/components/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
5e3ce05f-7d0c-44d9-b3d5-06da9c26335f
|
||||
1
src/renderer/components/chrome-icon/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
0548aa3a-ab35-420e-a82c-282f39eb3514
|
||||
56
src/renderer/components/chrome-icon/index.vue
Executable file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div :class="['chrome-icon',{nodisabled:!disabled}]" @click="handleClick" style="-webkit-app-region: no-drag">
|
||||
<i :class="['iconfont',icon]" ></i>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'chromeIcon',
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(){
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chrome-icon {
|
||||
background-color: transparent;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
margin-right:5px;
|
||||
border-radius: 100%;
|
||||
cursor:not-allowed;
|
||||
|
||||
.iconfont{
|
||||
font-size: 24px;
|
||||
color: #aaaaaa;
|
||||
|
||||
}
|
||||
|
||||
&.nodisabled {
|
||||
cursor: default;
|
||||
.iconfont{
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
&.nodisabled:hover {
|
||||
background-color: #aaaaaa;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
1
src/renderer/components/content-main/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
a9389a88-3049-40d9-a37f-a069d8792f77
|
||||
37
src/renderer/components/content-main/index.vue
Executable file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<div class="content-main" :class="{'content-win':osType=='win'}">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { osType } from '../../../utils/utils'
|
||||
|
||||
export default {
|
||||
name: 'content-div',
|
||||
data(){
|
||||
return {
|
||||
osType
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.content {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
.content-main {
|
||||
width: calc(~"100% + 15px");
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.content-win {
|
||||
width: calc(~"100% + 17px");
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1
src/renderer/components/icon/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
887c1011-8169-4561-afc2-d4bb71db9b0d
|
||||
25
src/renderer/components/icon/index.vue
Executable file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<i class="icon" @click.stop="handleClick"></i>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'icon',
|
||||
methods: {
|
||||
handleClick(){
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.icon {
|
||||
color: #dddddd;
|
||||
&:hover{
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1
src/renderer/components/image-match/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
885b5bac-6a22-4221-bfe0-5b0f532afc29
|
||||