mirror of
https://github.com/Molunerfinn/PicGo.git
synced 2024-04-21 10:31:33 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0bb8480a2 | ||
|
|
d4c04ee1e6 | ||
|
|
4ab782e8dc | ||
|
|
a9ba87dc8e | ||
|
|
396faa2c60 | ||
|
|
930e4e663b | ||
|
|
ce9c2aed71 | ||
|
|
bba250b0d9 | ||
|
|
b74fe8676b | ||
|
|
8ad28f7fe5 | ||
|
|
1d91730eb9 | ||
|
|
5a25aa0b52 | ||
|
|
671c011feb | ||
|
|
62b616bfc7 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
test/unit/coverage/**
|
||||
test/unit/*.js
|
||||
test/e2e/*.js
|
||||
dist/
|
||||
dist/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<!--
|
||||
PicGo Issue 模板
|
||||
请依照该模板来提交,否则将会被关闭。
|
||||
**提问之前请注意你看过FAQ、配置手册以及那些被关闭的issues。否则同样的提问也会被关闭!**
|
||||
-->
|
||||
|
||||
## 问题类型
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ language: c
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
# - os: linux
|
||||
- os: linux
|
||||
env: CC=clang CXX=clang++ npm_config_clang=1
|
||||
compiler: clang
|
||||
cache:
|
||||
@@ -25,7 +25,7 @@ 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
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi
|
||||
install:
|
||||
#- export DISPLAY=':99.0'
|
||||
#- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
## 常见问题
|
||||
|
||||
> 在使用PicGo期间你会遇到很多问题,不过很多问题其实之前就有人提问过,也被解决,所以你可以先看看[使用文档](https://github.com/Molunerfinn/PicGo/wiki/%E8%AF%A6%E7%BB%86%E7%AA%97%E5%8F%A3%E7%9A%84%E4%BD%BF%E7%94%A8#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BF%AB%E6%8D%B7%E9%94%AE),这份FAQ,以及那些被关闭的[issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed),应该能找到答案。
|
||||
|
||||
## 1.七牛图床上传图片成功后无法显示或图片无`http://`前缀
|
||||
|
||||
通常是你的七牛图床配置里的`设定访问网址`没有加上`http://`或者`https//`头。
|
||||
|
||||
参考:[issue#79](https://github.com/Molunerfinn/PicGo/issues/79)
|
||||
|
||||
## 2.能否支持图床远端同步删除
|
||||
|
||||
不能。有些图床(比如微博图床、SM.MS、Imgur等)不支持后台管理,为了架构统一不支持远端删除。
|
||||
|
||||
## 3.能否支持上传视频文件
|
||||
|
||||
目前不能。2.0版本出来后将会支持插件系统,届时如果有人开发了相应的插件理论可以支持任意文件上传。
|
||||
|
||||
## 4.微博图床上传之后无法显示预览图
|
||||
|
||||
通常是挂了全局代理导致的。
|
||||
|
||||
参考:[issue36](https://github.com/Molunerfinn/PicGo/issues/36)
|
||||
|
||||
## 5.能否支持某某某图床
|
||||
|
||||
截止v1.6,PicGo支持了如下图床:
|
||||
|
||||
- `微博图床` v1.0
|
||||
- `七牛图床` v1.0
|
||||
- `腾讯云COS v4\v5版本` v1.1 & v1.5.0
|
||||
- `又拍云` v1.2.0
|
||||
- `GitHub` v1.5.0
|
||||
- `SM.MS` v1.5.1
|
||||
- `阿里云OSS` v1.6.0
|
||||
- `Imgur` v1.6.0
|
||||
|
||||
所以本体内将不会再支持其他图床。待2.0版本出来支持插件系统后可以由其他开发者开发相应的图床插件用以支持其他图床。
|
||||
|
||||
## 6.一个图床设置多个信息
|
||||
|
||||
不能。因为目前的架构只支持一个图床一份信息。
|
||||
|
||||
## 7.v2.0版本有什么新功能
|
||||
|
||||
在不改变PicGo现有使用界面和使用习惯的基础上,将会重构整个底层`传输->转换->上传`的架构,使其能够支持插件系统,方便其他开发者基于PicGo的底层进行二次开发。
|
||||
|
||||
理论上有了插件系统之后,其他开发者能够支持如下功能:
|
||||
|
||||
1. 能够实现上传前图片压缩
|
||||
2. 能够通过图片url实现上传图片 -> 更深入地可以批量地实现图床的迁移
|
||||
3. 能够支持其他图床甚至是自己的图床
|
||||
|
||||
等等。
|
||||
|
||||
届时底层架构将会独立出来成为一个独立的npm包,能够直接在命令行里调用。
|
||||
|
||||
目前开发进度可以参考[PicGo-Core](https://github.com/Molunerfinn/PicGo-Core)。
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
## 应用说明
|
||||
|
||||
**PicGo在上传图片之后自动会将图片链接复制到你的剪贴板里,可选5种复制的链接格式。**
|
||||
|
||||
PicGo目前支持了
|
||||
|
||||
- `微博图床` v1.0
|
||||
@@ -37,13 +39,11 @@ PicGo目前支持了
|
||||
|
||||
支持macOS、windows 64位(>= v1.3.1),linux(>= v1.6.0)。
|
||||
|
||||
支持快捷键`command+shift+p`(macOS)或者`control+shift+p`(windows\linux)用以支持快捷上传剪贴板里的图片(第一张)。
|
||||
支持快捷键`command+shift+p`(macOS)或者`control+shift+p`(windows\linux)用以支持快捷上传剪贴板里的图片(第一张)。PicGo v1.4.0版本及以上支持自定义快捷键,使用方法见[配置手册](https://github.com/Molunerfinn/PicGo/wiki/%E8%AF%A6%E7%BB%86%E7%AA%97%E5%8F%A3%E7%9A%84%E4%BD%BF%E7%94%A8#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BF%AB%E6%8D%B7%E9%94%AE)。
|
||||
|
||||
PicGo v1.4.0版本及以上支持自定义快捷键,使用方法见[配置手册](https://github.com/Molunerfinn/PicGo/wiki/%E8%AF%A6%E7%BB%86%E7%AA%97%E5%8F%A3%E7%9A%84%E4%BD%BF%E7%94%A8#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BF%AB%E6%8D%B7%E9%94%AE)。
|
||||
**如果第一次使用,请参考应用使用[手册](https://github.com/Molunerfinn/PicGo/wiki)。遇到问题了还可以看看[FAQ](https://github.com/Molunerfinn/PicGo/blob/dev/FAQ.md)以及被关闭的[issues](https://github.com/Molunerfinn/PicGo/issues?q=is%3Aissue+is%3Aclosed)。**
|
||||
|
||||
点击此处下载[应用](https://github.com/Molunerfinn/PicGo/releases),macOS用户请下载最新版本的`dmg`文件,windows用户请下载最新版本的`exe`文件。**如果是国内用户下载github release文件速度很慢的话,推荐使用[Free Download Manager](http://www.freedownloadmanager.org/download.htm)来下载,速度会快。**
|
||||
|
||||
如果第一次使用,请参考应用使用[手册](https://github.com/Molunerfinn/PicGo/wiki)。
|
||||
点击此处下载[应用](https://github.com/Molunerfinn/PicGo/releases),macOS用户请下载最新版本的`dmg`文件,windows用户请下载最新版本的`exe`文件,linux用户请下载`AppImage`文件。**如果是国内用户下载github release文件速度很慢的话,推荐使用[Free Download Manager](http://www.freedownloadmanager.org/download.htm)来下载,速度会快。**
|
||||
|
||||
开发进度可以查看[Projects](https://github.com/Molunerfinn/PicGo/projects),会同步更新开发进度。
|
||||
|
||||
@@ -88,7 +88,7 @@ npm run build
|
||||
|
||||
## 赞助
|
||||
|
||||
如果你喜欢PicGo并且它对你确实有帮助,欢迎给我打赏一杯咖啡的钱哈~
|
||||
如果你喜欢PicGo并且它对你确实有帮助,欢迎给我打赏一杯咖啡哈~
|
||||
|
||||
支付宝:
|
||||
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "picgo",
|
||||
"version": "1.6.0",
|
||||
"version": "1.6.2",
|
||||
"author": "Molunerfinn <marksz@teamsz.xyz>",
|
||||
"description": "Easy to upload your pic & copy to write",
|
||||
"license": "MIT",
|
||||
@@ -67,12 +67,12 @@
|
||||
"allowToChangeInstallationDirectory": true
|
||||
},
|
||||
"linux": {
|
||||
"icon": "build/icons/256x256.png"
|
||||
"icon": "build/icons/"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"ali-oss": "^5.3.0",
|
||||
"axios": "^0.16.1",
|
||||
"dateformat": "^3.0.3",
|
||||
"element-ui": "^2.0.5",
|
||||
"fecha": "^2.3.3",
|
||||
"fs-extra": "^4.0.2",
|
||||
@@ -111,7 +111,7 @@
|
||||
"css-loader": "^0.28.4",
|
||||
"del": "^3.0.0",
|
||||
"devtron": "^1.4.0",
|
||||
"electron": "^1.7.5",
|
||||
"electron": "1.8.7",
|
||||
"electron-builder": "^19.19.1",
|
||||
"electron-debug": "^1.4.0",
|
||||
"electron-devtools-installer": "^2.2.0",
|
||||
|
||||
@@ -354,6 +354,9 @@ const uploadClipboardFiles = async () => {
|
||||
notification.show()
|
||||
window.webContents.send('clipboardFiles', [])
|
||||
window.webContents.send('uploadFiles', img)
|
||||
if (settingWindow) {
|
||||
settingWindow.webContents.send('updateGallery')
|
||||
}
|
||||
} else {
|
||||
const notification = new Notification({
|
||||
title: '上传不成功',
|
||||
@@ -396,6 +399,9 @@ ipcMain.on('uploadClipboardFiles', async (evt, file) => {
|
||||
notification.show()
|
||||
window.webContents.send('clipboardFiles', [])
|
||||
window.webContents.send('uploadFiles', img)
|
||||
if (settingWindow) {
|
||||
settingWindow.webContents.send('updateGallery')
|
||||
}
|
||||
} else {
|
||||
uploadFailed()
|
||||
}
|
||||
@@ -423,6 +429,9 @@ ipcMain.on('uploadChoosedFiles', async (evt, files) => {
|
||||
}
|
||||
clipboard.writeText(pasteText)
|
||||
window.webContents.send('uploadFiles', imgs)
|
||||
if (settingWindow) {
|
||||
settingWindow.webContents.send('updateGallery')
|
||||
}
|
||||
} else {
|
||||
uploadFailed()
|
||||
}
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
import request from 'request-promise'
|
||||
import * as img2Base64 from './img2base64'
|
||||
import db from '../../datastore/index'
|
||||
import { Notification, clipboard } from 'electron'
|
||||
import { Wrapper as OSS } from 'ali-oss'
|
||||
import crypto from 'crypto'
|
||||
import mime from 'mime-types'
|
||||
|
||||
let client
|
||||
|
||||
// generate OSS Options
|
||||
const generateOSSOptions = () => {
|
||||
// generate OSS signature
|
||||
const generateSignature = (fileName) => {
|
||||
const options = db.read().get('picBed.aliyun').value()
|
||||
client = new OSS({
|
||||
region: `${options.area}`,
|
||||
accessKeyId: `${options.accessKeyId}`,
|
||||
accessKeySecret: `${options.accessKeySecret}`,
|
||||
bucket: `${options.bucket}`,
|
||||
secure: true
|
||||
})
|
||||
return client
|
||||
const date = new Date().toGMTString()
|
||||
const signString = `PUT\n\n${mime.lookup(fileName)}\n${date}\n/${options.bucket}/${options.path}${fileName}`
|
||||
|
||||
const signature = crypto.createHmac('sha1', options.accessKeySecret).update(signString).digest('base64')
|
||||
return `OSS ${options.accessKeyId}:${signature}`
|
||||
}
|
||||
|
||||
const postOptions = (fileName, signature, imgBase64) => {
|
||||
const options = db.read().get('picBed.aliyun').value()
|
||||
return {
|
||||
method: 'PUT',
|
||||
url: `https://${options.bucket}.${options.area}.aliyuncs.com/${encodeURI(options.path)}${encodeURI(fileName)}`,
|
||||
headers: {
|
||||
Host: `${options.bucket}.${options.area}.aliyuncs.com`,
|
||||
Authorization: signature,
|
||||
Date: new Date().toGMTString(),
|
||||
'content-type': mime.lookup(fileName)
|
||||
},
|
||||
body: Buffer.from(imgBase64, 'base64'),
|
||||
resolveWithFullResponse: true
|
||||
}
|
||||
}
|
||||
|
||||
const aliYunUpload = async (img, type, webContents) => {
|
||||
@@ -27,15 +40,17 @@ const aliYunUpload = async (img, type, webContents) => {
|
||||
const customUrl = aliYunOptions.customUrl
|
||||
const path = aliYunOptions.path
|
||||
const length = imgList.length
|
||||
generateOSSOptions()
|
||||
generateSignature()
|
||||
for (let i in imgList) {
|
||||
let body = await client.put(`${path}${imgList[i].fileName}`, Buffer.from(imgList[i].base64Image, 'base64'))
|
||||
if (body.res.status === 200) {
|
||||
const signature = generateSignature(imgList[i].fileName)
|
||||
const options = postOptions(imgList[i].fileName, signature, imgList[i].base64Image)
|
||||
let body = await request(options)
|
||||
if (body.statusCode === 200) {
|
||||
delete imgList[i].base64Image
|
||||
if (customUrl) {
|
||||
imgList[i]['imgUrl'] = `${customUrl}/${path}${imgList[i].fileName}`
|
||||
} else {
|
||||
imgList[i]['imgUrl'] = body.url
|
||||
imgList[i]['imgUrl'] = `https://${aliYunOptions.bucket}.${aliYunOptions.area}.aliyuncs.com/${path}${imgList[0].fileName}`
|
||||
}
|
||||
imgList[i]['type'] = 'aliyun'
|
||||
if (i - length === -1) {
|
||||
|
||||
@@ -50,7 +50,7 @@ const imgFromPath = async (imgPath) => {
|
||||
name = await waitForRename(window, window.webContents.id)
|
||||
}
|
||||
let buffer = await fs.readFile(item)
|
||||
let base64Image = Buffer.from(buffer, 'binary').toString('base64')
|
||||
let base64Image = Buffer.from(buffer).toString('base64')
|
||||
let imgSize = sizeOf(item)
|
||||
results.push({
|
||||
base64Image,
|
||||
@@ -105,7 +105,7 @@ const imgFromUploader = async (files) => {
|
||||
name = await waitForRename(window, window.webContents.id)
|
||||
}
|
||||
let buffer = await fs.readFile(item.path)
|
||||
let base64Image = Buffer.from(buffer, 'binary').toString('base64')
|
||||
let base64Image = Buffer.from(buffer).toString('base64')
|
||||
let imgSize = sizeOf(item.path)
|
||||
results.push({
|
||||
base64Image,
|
||||
|
||||
@@ -34,6 +34,7 @@ const smmsUpload = async function (img, type, webContents) {
|
||||
if (body.code === 'success') {
|
||||
delete imgList[i].base64Image
|
||||
imgList[i]['imgUrl'] = body.data.url
|
||||
imgList[i]['type'] = 'smms'
|
||||
} else {
|
||||
webContents.send('uploadProgress', -1)
|
||||
return new Error()
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as img2Base64 from './img2base64'
|
||||
import db from '../../datastore/index'
|
||||
import { Notification, clipboard } from 'electron'
|
||||
import crypto from 'crypto'
|
||||
import mime from 'mime-types'
|
||||
|
||||
// generate COS signature string
|
||||
const generateSignature = (fileName) => {
|
||||
@@ -67,7 +68,7 @@ const postOptions = (fileName, signature, imgBase64) => {
|
||||
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}`,
|
||||
contentType: 'multipart/form-data'
|
||||
contentType: mime.lookup(fileName)
|
||||
},
|
||||
body: Buffer.from(imgBase64, 'base64'),
|
||||
resolveWithFullResponse: true
|
||||
@@ -86,8 +87,8 @@ const tcYunUpload = async (img, type, webContents) => {
|
||||
const path = tcYunOptions.path
|
||||
const useV4 = !tcYunOptions.version || tcYunOptions.version === 'v4'
|
||||
for (let i in imgList) {
|
||||
const singature = generateSignature(imgList[i].fileName)
|
||||
const options = postOptions(imgList[i].fileName, singature, imgList[i].base64Image)
|
||||
const signature = generateSignature(imgList[i].fileName)
|
||||
const options = postOptions(imgList[i].fileName, signature, imgList[i].base64Image)
|
||||
const res = await request(options)
|
||||
.then(res => res)
|
||||
.catch(err => {
|
||||
|
||||
@@ -104,7 +104,12 @@ export default {
|
||||
if (this.dragging) {
|
||||
const xLoc = e.screenX - this.wX
|
||||
const yLoc = e.screenY - this.wY
|
||||
this.$electron.remote.BrowserWindow.getFocusedWindow().setPosition(xLoc, yLoc)
|
||||
this.$electron.remote.BrowserWindow.getFocusedWindow().setBounds({
|
||||
x: xLoc,
|
||||
y: yLoc,
|
||||
width: 64,
|
||||
height: 64
|
||||
})
|
||||
}
|
||||
},
|
||||
handleMouseUp (e) {
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
</el-row>
|
||||
<el-row class="handle-bar" :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-input placeholder="搜索" size="mini" v-model="searchText"></el-input>
|
||||
<el-input placeholder="搜索" size="mini" v-model="searchText">
|
||||
<i slot="suffix" class="el-input__icon el-icon-close" v-if="searchText" @click="cleanSearch" style="cursor: pointer"></i>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="item-base" @click="cleanSearch">
|
||||
清空搜索
|
||||
<div class="item-base copy" :class="{ active: isMultiple(choosedList)}" @click="multiCopy">
|
||||
<i class="el-icon-document"></i> 批量复制
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
@@ -101,10 +103,18 @@ export default {
|
||||
},
|
||||
created () {
|
||||
this.getGallery()
|
||||
this.$electron.ipcRenderer.on('updateGallery', (event) => {
|
||||
this.filterList = this.getGallery()
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
filterList (val) {
|
||||
return this.getGallery()
|
||||
filterList: {
|
||||
get () {
|
||||
return this.getGallery()
|
||||
},
|
||||
set (val) {
|
||||
return this.val
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -143,7 +153,7 @@ export default {
|
||||
this.idx = null
|
||||
},
|
||||
copy (url) {
|
||||
const style = this.$db.read().get('picBed.pasteStyle').value()
|
||||
const style = this.$db.read().get('picBed.pasteStyle').value() || 'markdown'
|
||||
const copyLink = pasteStyle(style, url)
|
||||
const obj = {
|
||||
title: '复制链接成功',
|
||||
@@ -239,9 +249,32 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
multiCopy () {
|
||||
if (Object.values(this.choosedList).some(item => item)) {
|
||||
let copyString = ''
|
||||
const style = this.$db.read().get('picBed.pasteStyle').value() || 'markdown'
|
||||
Object.keys(this.choosedList).forEach(key => {
|
||||
if (this.choosedList[key]) {
|
||||
copyString += pasteStyle(style, this.$db.read().get('uploaded').getById(key).value().imgUrl) + '\n'
|
||||
}
|
||||
})
|
||||
const obj = {
|
||||
title: '批量复制链接成功',
|
||||
body: copyString
|
||||
}
|
||||
const myNotification = new window.Notification(obj.title, obj)
|
||||
this.$electron.clipboard.writeText(copyString)
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleHandleBar () {
|
||||
this.handleBarActive = !this.handleBarActive
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$electron.ipcRenderer.removeAllListeners('updateGallery')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -266,13 +299,20 @@ export default {
|
||||
cursor pointer
|
||||
font-size 13px
|
||||
transition all .2s ease-in-out
|
||||
&.copy
|
||||
cursor not-allowed
|
||||
background #49B1F5
|
||||
&.active
|
||||
cursor pointer
|
||||
background #1B9EF3
|
||||
color #fff
|
||||
&.delete
|
||||
cursor not-allowed
|
||||
background #F47466
|
||||
&.delete.active
|
||||
cursor pointer
|
||||
background #F15140
|
||||
color #fff
|
||||
&.active
|
||||
cursor pointer
|
||||
background #F15140
|
||||
color #fff
|
||||
.long-list
|
||||
width: calc(83.3333333% - 6px)
|
||||
#gallery-view
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
this.notification.body = item.imgUrl
|
||||
this.notification.icon = item.imgUrl
|
||||
const myNotification = new window.Notification(this.notification.title, this.notification)
|
||||
const pasteStyle = this.$db.read().get('picBed.pasteStyle').value()
|
||||
const pasteStyle = this.$db.read().get('picBed.pasteStyle').value() || 'markdown'
|
||||
this.$electron.clipboard.writeText(pasteTemplate(pasteStyle, item.imgUrl))
|
||||
myNotification.onclick = () => {
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user