Compare commits

..
14 Commits
16 changed files with 309 additions and 66 deletions
+5 -1
View File
@@ -22,7 +22,7 @@
## 应用说明
PicGo目前支持了`微博图床``七牛图床``腾讯云COS v4版本``又拍云`。未来将支持更多图床。
PicGo目前支持了`微博图床``七牛图床``腾讯云COS v4\v5版本``又拍云``GitHub`。未来将支持更多图床。
支持macOS、windows 64位(v1.3.0以上)系统,未来将支持linux。
@@ -32,6 +32,8 @@ PicGo目前支持了`微博图床`,`七牛图床`,`腾讯云COS v4版本`,
如果第一次使用,请参考应用使用[手册](https://github.com/Molunerfinn/PicGo/wiki)。
开发进度可以查看[Projects](https://github.com/Molunerfinn/PicGo/projects),会同步更新开发进度。
![](https://user-images.githubusercontent.com/12621342/34242857-d177930a-e658-11e7-9688-7405851dd5e5.gif)
![picgo-menubar](https://user-images.githubusercontent.com/12621342/34242310-b5056510-e655-11e7-8568-60ffd4f71910.gif)
@@ -42,6 +44,8 @@ PicGo目前支持了`微博图床`,`七牛图床`,`腾讯云COS v4版本`,
如果你想要学习、开发、修改或自行构建PicGo,可以依照下面的指示:
> 如果想学习Electron-vue的开发,可以查看我写的系列教程——[Electron-vue开发实战](https://molunerfinn.com/tags/Electron-vue/)
1. 你需要有node、git环境。需要了解npm的相关知识。
2. `git clone https://github.com/Molunerfinn/PicGo.git` 并进入项目
3. `npm install` 下载依赖
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "picgo",
"version": "1.5.0",
"version": "1.5.1",
"author": "Molunerfinn <marksz@teamsz.xyz>",
"description": "Easy to upload your pic & copy to write",
"license": "MIT",
+3 -1
View File
@@ -3,13 +3,15 @@ import qiniuUpload from '../main/utils/qiniuUpload'
import tcYunUpload from '../main/utils/tcYunUpload'
import upYunUpload from '../main/utils/upYunUpload'
import githubUpload from '../main/utils/githubUpload'
import smmsUpload from '../main/utils/smmsUpload'
const picBedHandler = {
weibo: weiboUpload,
qiniu: qiniuUpload,
tcyun: tcYunUpload,
upyun: upYunUpload,
github: githubUpload
github: githubUpload,
smms: smmsUpload
}
export default picBedHandler
+41 -30
View File
@@ -1,35 +1,46 @@
import db from './index'
let picBed = db.read().get('picBed.list').value()
let picBed = [
{
type: 'weibo',
name: '微博图床',
visible: true
},
{
type: 'qiniu',
name: '七牛图床',
visible: true
},
{
type: 'tcyun',
name: '腾讯云COS',
visible: true
},
{
type: 'upyun',
name: '又拍云图床',
visible: true
},
{
type: 'github',
name: 'GitHub图床',
visible: true
},
{
type: 'smms',
name: 'SM.MS图床',
visible: true
}
]
if (!picBed) {
picBed = [
{
type: 'weibo',
name: '微博图床',
visible: true
},
{
type: 'qiniu',
name: '七牛图床',
visible: true
},
{
type: 'tcyun',
name: '腾讯云COS',
visible: true
},
{
type: 'upyun',
name: '又拍云图床',
visible: true
},
{
type: 'github',
name: 'GitHub图床',
visible: true
}
]
let picBedFromDB = db.read().get('picBed.list').value() || []
let oldLength = picBedFromDB.length
let newLength = picBed.length
if (oldLength !== newLength) {
for (let i = oldLength; i < newLength; i++) {
picBedFromDB.push(picBed[i])
}
}
export default picBed
export default picBedFromDB
+6 -2
View File
@@ -8,7 +8,7 @@ const postOptions = (fileName, options, data) => {
const {token, repo} = options
return {
method: 'PUT',
url: `https://api.github.com/repos/${repo}/contents/${path}${encodeURI(fileName)}`,
url: `https://api.github.com/repos/${repo}/contents/${encodeURI(path)}${encodeURI(fileName)}`,
headers: {
Authorization: `token ${token}`,
'User-Agent': 'PicGo'
@@ -36,7 +36,11 @@ const githubUpload = async function (img, type, webContents) {
const body = await request(postConfig)
if (body) {
delete imgList[i].base64Image
imgList[i]['imgUrl'] = body.content.download_url
if (githubOptions.customUrl) {
imgList[i]['imgUrl'] = `${githubOptions.customUrl}/${githubOptions.path}${imgList[i].fileName}`
} else {
imgList[i]['imgUrl'] = body.content.download_url
}
imgList[i]['type'] = 'github'
if (i - length === -1) {
webContents.send('uploadProgress', 60)
+19 -6
View File
@@ -22,6 +22,7 @@ const createRenameWindow = () => {
if (process.platform === 'win32') {
options.show = true
options.backgroundColor = '#3f3c37'
options.autoHideMenuBar = true
}
const window = new BrowserWindow(options)
@@ -31,10 +32,16 @@ const createRenameWindow = () => {
const imgFromPath = async (imgPath) => {
let results = []
let rename = db.read().get('picBed.rename').value()
const rename = db.read().get('picBed.rename').value()
const autoRename = db.read().get('picBed.autoRename').value()
await Promise.all(imgPath.map(async item => {
let name
let fileName = path.basename(item)
let fileName
if (autoRename) {
fileName = fecha.format(new Date(), 'YYYYMMDDHHmmss') + path.extname(item)
} else {
fileName = path.basename(item)
}
if (rename) {
const window = createRenameWindow()
await waitForShow(window.webContents)
@@ -80,22 +87,28 @@ const imgFromClipboard = async (file) => {
const imgFromUploader = async (files) => {
let results = []
let rename = db.read().get('picBed.rename').value()
const rename = db.read().get('picBed.rename').value()
const autoRename = db.read().get('picBed.autoRename').value()
await Promise.all(files.map(async item => {
let name
let fileName
if (autoRename) {
fileName = fecha.format(new Date(), 'YYYYMMDDHHmmss') + path.extname(item.name)
} else {
fileName = path.basename(item.path)
}
if (rename) {
const window = createRenameWindow()
await waitForShow(window.webContents)
window.webContents.send('rename', item.name, window.webContents.id)
window.webContents.send('rename', fileName, window.webContents.id)
name = await waitForRename(window, window.webContents.id)
}
let buffer = await fs.readFile(item.path)
let base64Image = Buffer.from(buffer, 'binary').toString('base64')
let fileName = name || item.name
let imgSize = sizeOf(item.path)
results.push({
base64Image,
fileName,
fileName: name || fileName,
width: imgSize.width,
height: imgSize.height,
extname: path.extname(item.name)
+1 -1
View File
@@ -7,7 +7,7 @@ export default (style, url) => {
'HTML': `<img src="${url}"/>`,
'URL': url,
'UBB': `[IMG]${url}[/IMG]`,
'Custom': customLink.replace(/\$url/, url)
'Custom': customLink.replace(/\$url/g, url)
}
return tpl[style]
}
+55
View File
@@ -0,0 +1,55 @@
import request from 'request-promise'
import * as img2Base64 from './img2base64'
import { Notification } from 'electron'
const postOptions = (fileName, imgBase64) => {
return {
method: 'POST',
url: `https://sm.ms/api/upload`,
headers: {
contentType: 'multipart/form-data',
'User-Agent': 'PicGo'
},
formData: {
smfile: {
value: Buffer.from(imgBase64, 'base64'),
options: {
filename: fileName
}
},
ssl: 'true'
}
}
}
const smmsUpload = async function (img, type, webContents) {
try {
webContents.send('uploadProgress', 0)
const imgList = await img2Base64[type](img)
webContents.send('uploadProgress', 30)
for (let i in imgList) {
const postConfig = postOptions(imgList[i].fileName, imgList[i].base64Image)
let body = await request(postConfig)
body = JSON.parse(body)
if (body.code === 'success') {
delete imgList[i].base64Image
imgList[i]['imgUrl'] = body.data.url
} else {
webContents.send('uploadProgress', -1)
return new Error()
}
}
webContents.send('uploadProgress', 100)
return imgList
} catch (err) {
webContents.send('uploadProgress', -1)
const notification = new Notification({
title: '上传失败!',
body: '服务端出错,请重试'
})
notification.show()
throw new Error(err)
}
}
export default smmsUpload
+2 -2
View File
@@ -49,7 +49,7 @@ const postOptions = (fileName, signature, imgBase64) => {
if (!options.version || options.version === 'v4') {
return {
method: 'POST',
url: `http://${area}.file.myqcloud.com/files/v2/${signature.appId}/${signature.bucket}/${path}${fileName}`,
url: `http://${area}.file.myqcloud.com/files/v2/${signature.appId}/${signature.bucket}/${encodeURI(path)}${fileName}`,
headers: {
Host: `${area}.file.myqcloud.com`,
Authorization: signature.signature,
@@ -63,7 +63,7 @@ const postOptions = (fileName, signature, imgBase64) => {
} else {
return {
method: 'PUT',
url: `http://${options.bucket}.cos.${options.area}.myqcloud.com/${path}${encodeURI(fileName)}`,
url: `http://${options.bucket}.cos.${options.area}.myqcloud.com/${encodeURI(path)}${encodeURI(fileName)}`,
headers: {
Host: `${options.bucket}.cos.${options.area}.myqcloud.com`,
Authorization: `q-sign-algorithm=sha1&q-ak=${options.secretId}&q-sign-time=${signature.signTime}&q-key-time=${signature.signTime}&q-header-list=host&q-url-param-list=&q-signature=${signature.signature}`,
+2 -2
View File
@@ -13,7 +13,7 @@ const generateSignature = (fileName) => {
const password = options.password
const md5Password = MD5(password)
const date = new Date().toGMTString()
const uri = `/${options.bucket}/${path}${encodeURI(fileName)}`
const uri = `/${options.bucket}/${encodeURI(path)}${encodeURI(fileName)}`
const value = `PUT&${uri}&${date}`
const sign = crypto.createHmac('sha1', md5Password).update(value).digest('base64')
return `UPYUN ${operator}:${sign}`
@@ -25,7 +25,7 @@ const postOptions = (fileName, signature, imgBase64) => {
const path = options.path || ''
return {
method: 'PUT',
url: `https://v0.api.upyun.com/${bucket}/${path}${encodeURI(fileName)}`,
url: `https://v0.api.upyun.com/${bucket}/${encodeURI(path)}${encodeURI(fileName)}`,
headers: {
Authorization: signature,
Date: new Date().toGMTString()
+10 -17
View File
@@ -1,9 +1,6 @@
import weiboUpload from './weiboUpload'
import qiniuUpload from './qiniuUpload'
import tcYunUpload from './tcYunUpload'
import upYunUpload from './upYunUpload'
import githubUpload from './githubUpload'
import db from '../../datastore/index'
import { Notification } from 'electron'
import picBeds from '../../datastore/pic-bed-handler'
const checkUploader = (type) => {
const currentUploader = db.read().get(`picBed.${type}`).value()
@@ -15,20 +12,16 @@ const checkUploader = (type) => {
}
const uploader = (img, type, webContents) => {
if (db.read().get('picBed.uploadNotification').value()) {
const notification = new Notification({
title: '上传进度',
body: '正在上传'
})
notification.show()
}
const uploadType = db.read().get('picBed.current').value()
if (checkUploader(uploadType)) {
switch (uploadType) {
case 'weibo':
return weiboUpload(img, type, webContents)
case 'qiniu':
return qiniuUpload(img, type, webContents)
case 'tcyun':
return tcYunUpload(img, type, webContents)
case 'upyun':
return upYunUpload(img, type, webContents)
case 'github':
return githubUpload(img, type, webContents)
}
return picBeds[uploadType](img, type, webContents)
} else {
return false
}
+1 -1
View File
@@ -38,7 +38,7 @@
:index="item.type"
:key="item.type"
>
<i :class="`el-icon-ui-${item.type}`"></i>
<!-- <i :class="`el-icon-ui-${item.type}`"></i> -->
<span slot="title">{{ item.name }}</span>
</el-menu-item>
</template>
@@ -40,6 +40,11 @@
>
<el-input v-model="form.path" @keyup.native.enter="confirm" placeholder="例如img/"></el-input>
</el-form-item>
<el-form-item
label="设定自定义域名"
>
<el-input v-model="form.customUrl" @keyup.native.enter="confirm" placeholder="例如https://xxxx.com"></el-input>
</el-form-item>
<el-form-item>
<el-button-group>
<el-button type="primary" @click="confirm" round>确定</el-button>
@@ -62,6 +67,7 @@ export default {
repo: '',
token: '',
path: '',
customUrl: '',
branch: ''
}
}
@@ -21,6 +21,11 @@
>
<el-button type="primary" round size="mini" @click="customLinkVisible = true">点击设置</el-button>
</el-form-item>
<el-form-item
label="检查更新"
>
<el-button type="primary" round size="mini" @click="checkUpdate">点击设置</el-button>
</el-form-item>
<el-form-item
label="打开更新助手"
>
@@ -51,6 +56,26 @@
@change="handleRename"
></el-switch>
</el-form-item>
<el-form-item
label="时间戳重命名"
>
<el-switch
v-model="form.autoRename"
active-text=""
inactive-text=""
@change="handleAutoRename"
></el-switch>
</el-form-item>
<el-form-item
label="开启上传提示"
>
<el-switch
v-model="form.uploadNotification"
active-text=""
inactive-text=""
@change="handleUploadNotification"
></el-switch>
</el-form-item>
<el-form-item
label="选择显示的图床"
>
@@ -123,13 +148,44 @@
<el-button type="primary" @click="confirmCustomLink">确定</el-button>
</span>
</el-dialog>
<el-dialog
title="检查更新"
:visible.sync="checkUpdateVisible"
:modal-append-to-body="false"
>
<div>
当前版本{{ version }}
</div>
<div>
最新版本{{ latestVersion ? latestVersion : '正在获取中...' }}
</div>
<div v-if="needUpdate">
PicGo更新啦请点击确定打开下载页面
</div>
<span slot="footer">
<el-button @click="cancelCheckVersion">取消</el-button>
<el-button type="primary" @click="confirmCheckVersion">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import db from '../../../datastore'
import keyDetect from 'utils/key-binding'
import pkg from '../../../../package.json'
const release = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
export default {
name: 'picgo-setting',
computed: {
needUpdate () {
if (this.latestVersion) {
return this.compareVersion2Update(this.version, this.latestVersion)
} else {
return false
}
}
},
data () {
const customLinkRule = (rule, value, callback) => {
if (!/\$url/.test(value)) {
@@ -143,11 +199,14 @@ export default {
updateHelper: this.$db.get('picBed.showUpdateTip').value(),
showPicBedList: [],
autoStart: this.$db.get('picBed.autoStart').value() || false,
rename: this.$db.get('picBed.rename').value() || false
rename: this.$db.get('picBed.rename').value() || false,
autoRename: this.$db.get('picBed.autoRename').value() || false,
uploadNotification: this.$db.get('picBed.uploadNotification').value() || false
},
picBed: this.$picBed,
keyBindingVisible: false,
customLinkVisible: false,
checkUpdateVisible: false,
customLink: {
value: db.read().get('customLink').value() || '$url'
},
@@ -158,7 +217,9 @@ export default {
value: [
{ validator: customLinkRule, trigger: 'blur' }
]
}
},
version: pkg.version,
latestVersion: ''
}
},
created () {
@@ -217,6 +278,44 @@ export default {
},
handleRename (val) {
this.$db.read().set('picBed.rename', val).write()
},
handleAutoRename (val) {
this.$db.read().set('picBed.autoRename', val).write()
},
compareVersion2Update (current, latest) {
const currentVersion = current.split('.').map(item => parseInt(item))
const latestVersion = latest.split('.').map(item => parseInt(item))
for (let i = 0; i < 3; i++) {
if (currentVersion[i] < latestVersion[i]) {
return true
}
if (currentVersion[i] > latestVersion[i]) {
return false
}
}
return false
},
checkUpdate () {
this.checkUpdateVisible = true
this.$http.get(release)
.then(res => {
this.latestVersion = res.data.name
}).catch(err => {
console.log(err)
})
},
confirmCheckVersion () {
if (this.needUpdate) {
this.$electron.remote.shell.openExternal(downloadUrl)
}
this.checkUpdateVisible = false
},
cancelCheckVersion () {
this.checkUpdateVisible = false
},
handleUploadNotification (val) {
this.$db.read().set('picBed.uploadNotification', val).write()
}
},
beforeDestroy () {
@@ -0,0 +1,51 @@
<template>
<div id="smms-view">
<el-row :gutter="16">
<el-col :span="16" :offset="4">
<div class="view-title">
SM.MS设置
</div>
<div class="content">
感谢SM.MS提供的优质服务
</div>
<div style="text-align: center; margin-top: 20px;">
<el-button type="success" @click="confirm" round :disabled="defaultPicBed === 'smms'" size="mini">设为默认图床</el-button>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import mixin from '../mixin'
export default {
name: 'upyun',
mixins: [mixin],
data () {
return {}
},
methods: {
confirm () {
this.$db.set('picBed.smms', true).write()
this.setDefaultPicBed('smms')
const successNotification = new window.Notification('设置结果', {
body: '设置成功'
})
successNotification.onclick = () => {
return true
}
}
}
}
</script>
<style lang='stylus'>
.view-title
color #eee
font-size 20px
text-align center
margin 20px auto
#smms-view
.content
text-align center
font-size 14px
color #eee
</style>
+5
View File
@@ -50,6 +50,11 @@ export default new Router({
component: require('@/components/SettingView/GitHub').default,
name: 'github'
},
{
path: 'smms',
component: require('@/components/SettingView/SMMS').default,
name: 'smms'
},
{
path: 'gallery',
component: require('@/components/SettingView/Gallery').default,