Explorar o código

***Add Image Cloud and Back Image to QiNiu or COS or Both them

zhuzhuyule %!s(int64=7) %!d(string=hai) anos
pai
achega
6e29561271

+ 5 - 19
app/moe-app.js

@@ -32,9 +32,7 @@ const MoeditorWindow = require('./moe-window'),
     path = require('path');
 
 let shellServer = false;
-let qiniuServer = false;
-let cosServer = false;
-let smmsServer = false;
+let uploadServer = false;
 
 class MoeditorApplication {
     constructor() {
@@ -56,22 +54,10 @@ class MoeditorApplication {
         return shellServer;
     }
 
-    getSmmsServer() {
-        if (!smmsServer)
-            smmsServer = new (require('./tool/hexo-smms'))();
-        return smmsServer;
-    }
-
-    getQiniuServer() {
-        if (!qiniuServer)
-            qiniuServer = new (require('./tool/hexo-qiniu'))();
-        return qiniuServer;
-    }
-
-    getCOSServer() {
-        if (!cosServer)
-            cosServer = new (require('./tool/hexo-cos'))();
-        return cosServer;
+    getUploadServer() {
+        if (!uploadServer)
+            uploadServer = new (require('./tool/hexo-uploadServer'))();
+        return uploadServer;
     }
 
     run() {

+ 1 - 0
app/moe-config-default.js

@@ -57,4 +57,5 @@ module.exports = {
     'image-cos-bucket':'|',
     'image-cos-url-protocol': 'http://',
     'image-cos-url':'',
+    'image-back-type': 2
 };

+ 2 - 0
app/moe-l10n.js

@@ -215,6 +215,7 @@ const strings = {
         "Web Type": "Web Type",
         "WebSM": "SM.MS",
         "QiNiu": "QiNiu",
+        "BackImage": "Back Image To Cloud",
         "WebCOS": "Tencent",
         "AccessKey": "Access Key",
         "SecretKey": "Secret Key",
@@ -390,6 +391,7 @@ const strings = {
         "WebSM": "SM.MS 图床",
         "QiNiu": "七牛云",
         "WebCOS": "腾讯云",
+        "BackImage": "备份到云",
         "AccessKey": "Access Key",
         "SecretKey": "Secret Key",
         "Bucket": "存储空间",

+ 9 - 6
app/tool/hexo-cos.js

@@ -111,7 +111,7 @@ class COSServer {
             Key: serverFile,
             Output: localName,
             onProgress: function (progressData) {
-                console.log(JSON.stringify(progressData));
+                // console.log(JSON.stringify(progressData));
             }
         }, function (err, data) {
             if (typeof cb === 'function')
@@ -155,7 +155,7 @@ class COSServer {
                 TaskId = tid;
             },
             onProgress: function (progressData) {
-                console.log(JSON.stringify(progressData));
+                // console.log(JSON.stringify(progressData));
             },
             // 格式1. 传入文件内容
             // Body: fs.readFileSync(filepath),
@@ -173,11 +173,13 @@ class COSServer {
                 cb(err || data);
 
             if (typeof cb === "function") {
-                let result = {id: localFile};
+                let result = {type: 100,id: localFile};
                 if (err){
+                    result.type = 100;
                     result.statusCode = err.statusCode;
                     result.msg = err.error.message;
                 } else{
+                    result.type = 200;
                     result.statusCode = data.statusCode;
                     result.data = {
                         localname: path.basename(localFile),
@@ -203,10 +205,10 @@ class COSServer {
                 TaskId = tid;
             },
             onHashProgress: function (progressData) {
-                console.log(JSON.stringify(progressData));
+                // console.log(JSON.stringify(progressData));
             },
             onProgress: function (progressData) {
-                console.log(JSON.stringify(progressData));
+                // console.log(JSON.stringify(progressData));
             },
         }, function (err, data) {
             /*data = {
@@ -218,11 +220,12 @@ class COSServer {
             *  headers: {}
             }*/
             if (typeof cb === "function") {
-                let result = {id: localFile};
+                let result = {type: 100,id: localFile};
                 if (err){
                     result.statusCode = err.statusCode;
                     result.msg = err.error.message;
                 } else{
+                    result.type = 200;
                     result.statusCode = data.statusCode;
                     result.data = {
                         localname: path.basename(localFile),

+ 4 - 1
app/tool/hexo-qiniu.js

@@ -4,6 +4,7 @@
 *  Copyright (c) 2018 zhuzhuyule
 */
 
+const path = require('path');
 class qiniuServer {
     constructor(acessKey, secretKey) {
         this.request = require('request');
@@ -159,8 +160,9 @@ class qiniuServer {
         formUploader.putFile(token, serverFileName, localFile, extra,
             function (respErr, respBody, respInfo) {
                 if (typeof  callback == 'function') {
-                    let result = {id: localFile};
+                    let result = {type:10,id: localFile};
                     if (respInfo.statusCode == 200 || respInfo.statusCode == 579) {
+                        result.type = 20;
                         result.statusCode = 200;
                         result.data = {
                             localname: path.basename(localFile),
@@ -174,6 +176,7 @@ class qiniuServer {
                         result.msg = respInfo.statusCode + respBody.error;
                         result.errorlist = 'https://developer.qiniu.com/kodo/api/3928/error-responses#2';
                     }
+                    callback(result)
                 } else {
                     console.log(respBody)
                 }

+ 6 - 3
app/tool/hexo-smms.js

@@ -50,7 +50,8 @@ class Smms {
      *        localname: 'abc.png',                           //本地文件名
      *        storename: '5a6bea876702d.png',                 //服务器文件名,SM.MS随机生成
      *        path: '/abc/abc/5a6bea876702d.png',             //服务器路径
-     *        url: 'https://...../abc/abc/5a6bea876702d.png'  //图片地址
+     *        url: 'https://...../abc/abc/5a6bea876702d.png', //图片地址
+     *        hash: 'sd8fsd8766d90sdf9'                       //删除hash
      *      },
      *      msg: 'error message'                              //一般只有报错才使用到
      *   }
@@ -64,15 +65,17 @@ class Smms {
         }, (error, res, body) => {
             if (typeof callback === "function") {
                 let response = JSON.parse(body);
-                let result = {id: localFile};
+                let result = {type:1,id: localFile};
                 if (res.statusCode == 200) {
                     result.statusCode = (response.code == 'success' ? 200 : -1);
                     if (result.statusCode == 200) {
+                        result.type = 2;
                         result.data = {
                             localname: response.data.filename,
                             storename: response.data.storename,
                             path: response.data.path,
-                            url: response.data.url
+                            url: response.data.url,
+                            hash: response.data.hash
                         }
                         result.msg = '';
                     } else {

+ 303 - 0
app/tool/hexo-uploadServer.js

@@ -0,0 +1,303 @@
+module.exports = (function () {
+    const path = require('path');
+    let isUploading = false;
+    let imgType = {
+        "png": '.png',
+        "jpg": '.jpg',
+        "jpeg": '.jpg',
+        "bmp": '.bmp',
+        ".png": '.png',
+        ".jpg": '.jpg',
+        ".jpeg": '.jpg',
+        ".bmp": '.bmp'
+    }
+    //help varible
+    let smmsServer, qiniuServer, cosServer;
+    let finishedCount, totalCount, pathIndex;
+    let statusList, successList, errorList;
+    let timeout,startDate;
+    let typeServer;
+    let typeBack;
+    //
+    let baseDir, uploadArray,finishedCallback;
+
+    function getSmmsServer() {
+        if (!smmsServer) {
+            smmsServer = new (require('./hexo-smms'))();
+        }
+        return smmsServer;
+    }
+
+    function getQiNiuServer() {
+        if (!qiniuServer) {
+            qiniuServer = new (require('./hexo-qiniu'))();
+            qiniuServer.update(
+                moeApp.config.get('image-qiniu-accessKey'),
+                moeApp.config.get('image-qiniu-secretKey'),
+                moeApp.config.get('image-qiniu-bucket'),
+                moeApp.config.get('image-qiniu-url-protocol') + moeApp.config.get('image-qiniu-url') + '/'
+            );
+        }
+        return qiniuServer;
+    }
+
+    function getCOSServer() {
+        if (!cosServer) {
+            cosServer = new (require('./hexo-cos'))();
+            let bucketObj = moeApp.config.get('image-cos-bucket');
+            bucketObj = (bucketObj || "|").split('|');
+            cosServer.update(
+                moeApp.config.get('image-cos-accessKey'),
+                moeApp.config.get('image-cos-secretKey'),
+                bucketObj[0],
+                bucketObj[1],
+                moeApp.config.get('image-cos-url-protocol')
+            );
+        }
+        return cosServer;
+    }
+
+    function asyncUploadToSmms(imgPath, callback) {
+        statusList[imgPath] = {type: 0};
+        getSmmsServer().uploadFile(imgPath, '', callback);
+    }
+
+    function asyncUploadToQiNiu(imgPath,serverName, callback) {
+        getQiNiuServer().uploadFile(imgPath, serverName, callback);
+    }
+
+    function asyncUploadToCOS(imgPath,serverName, callback) {
+        getCOSServer().sliceUploadFile(imgPath, serverName, callback);
+    }
+
+    function relativePath(p) {
+        return path.relative(baseDir, p).replace(/\\/g, '/');
+    }
+
+    function asyncUploadFile(imgPath, callback) {
+        switch (typeServer) {
+            case 'qiniu':
+                asyncUploadToQiNiu(imgPath,relativePath(imgPath), callback)
+                break;
+            case 'cos':
+                asyncUploadToCOS(imgPath,relativePath(imgPath), callback)
+                break;
+            default: {
+                if (typeBack > 2) {
+                    if (statusList[imgPath]) {
+                        if (statusList[imgPath].typeServer == 'qiniu') {
+                            asyncUploadToQiNiu(imgPath,statusList[imgPath].pathname , callback)
+                        } else {
+                            asyncUploadToCOS(imgPath,statusList[imgPath].pathname , callback)
+                        }
+                    } else {
+                        asyncUploadToSmms(imgPath, callback);
+                    }
+                }
+            }
+        }
+    }
+
+    function checktime(isBreak) {
+        clearTimeout(timeout);
+        if (!isBreak)
+            timeout = setTimeout(() => {
+                uploadEnd(true);
+            }, 30000)
+    }
+
+    /**
+     * 回调函数
+     * @param fileID
+     * @param result
+     *   response = {
+     *      id: 'localFileAbsolutePath',              //传入文件本地绝对路径
+     *      type: '1|2|10|20|100|200',                //1|2 Smms; 10|20 Qiniu; 100|200 Cos  (1:失败,2:成功)
+     *      statusCode: 200|int,                      //服务器代码,200:正常,其他:报错
+     *      data: {
+     *        localname: 'abc.png',                   //本地文件名
+     *        storename: '5a6bea876702d.png',         //服务器文件名,SM.MS随机生成
+     *        path: '/abc/abc/5a6bea876702d.png',     //服务器路径
+     *        url: 'https://...../abc/abc/5a6bea876702d.png'  //图片地址
+     *        hash: 'asdf7sdf8asdf78'                 //删除Hash
+     *      },
+     *      msg: 'error message'                      //一般只有报错才使用到
+     *      errorlist: 'url'                          //一般只有报错才使用到,报错列表是个官网地址
+     *   }
+     * }
+     */
+
+
+    function uploaded(response) {
+        let result = response;
+        let uploadNext = true;
+        let imgPath = result.id;
+        if (typeServer == 'smms' && typeBack > 2) {  //是否需要备份
+            console.log(result.statusCode,result.data.path,result.data.url)
+            statusList[imgPath].type += result.type;
+            if (statusList[imgPath].type == 2) {  //Smsm
+                statusList[imgPath].hash = result.data.hash;
+                statusList[imgPath].url = result.data.url;
+                if (result.data.path.startsWith('/'))
+                    statusList[imgPath].pathname = result.data.path.slice(1);
+                else
+                    statusList[imgPath].pathname = result.data.path;
+                uploadNext = backUpload(result)
+            } else if (statusList[imgPath].type == 22) {   //Qiniu
+                uploadNext = backUpload(result)
+            }
+
+            if (!uploadNext)
+                asyncUploadFile(imgPath, uploaded);
+        }
+
+        if (uploadNext){
+            finishedCount++;
+            console.log(finishedCount + '/' + totalCount);
+            if (typeServer == 'smms' && typeBack > 2){
+                if (statusList[imgPath].type == typeBack) {
+                    result.data.hash = statusList[imgPath].hash;
+                    result.data.url = statusList[imgPath].url;
+                    successList.set(imgPath, result)
+                } else {
+                    errorList.set(imgPath, result)
+                }
+            } else {
+                if (result.statusCode == 200) {
+                    successList.set(imgPath, result)
+                } else {
+                    errorList.set(imgPath, result)
+                }
+            }
+
+            if(pathIndex < totalCount){
+                asyncUploadFile(uploadArray[pathIndex], uploaded)
+                pathIndex++;
+            } else if (finishedCount == totalCount){
+                checktime(true);
+                uploadEnd();
+                return;
+            }
+        }
+        checktime();
+    }
+
+    function backUpload(response) {
+        let imgPath = response.id;
+        if (typeBack == 22) {
+            if (statusList[imgPath].type == 2) {
+                statusList[imgPath].typeServer = 'qiniu';
+                return false;
+            } else {
+                statusList[imgPath].typeServer = ''
+                return true;
+            }
+        } else if (typeBack == 202) {
+            if (statusList[imgPath].type == 2) {
+                statusList[imgPath].typeServer = 'cos';
+                return false;
+            } else {
+                statusList[imgPath].typeServer = ''
+                return true;
+            }
+        } else if (typeBack == 222) {
+            if (statusList[imgPath].type == 2) {
+                statusList[imgPath].typeServer = 'qiniu';
+                return false;
+            } else if (statusList[imgPath].type == 22) {
+                statusList[imgPath].typeServer = 'cos';
+                return false;
+            } else {
+                statusList[imgPath].typeServer = ''
+                return true;
+            }
+        }
+    }
+
+    function uploadEnd(isTimeout) {
+        try {
+            if (isTimeout)
+                errorList.set('Upload time out!',{msg:'Place check your net!'});
+        } finally {
+            console.log('upload end ! use time: ',new Date() - startDate)
+            console.log(successList.size,errorList.size)
+            finishedCallback(successList,errorList);
+            isUploading = false;
+        }
+    }
+
+    class UploadServer {
+        constructor() {
+            isUploading = false;
+        }
+        isLoading(){
+            return isUploading;
+        }
+        //Qiniu
+        updateQiniu(acessKey, secretKey, bucket, url) {
+            getQiNiuServer().update(acessKey, secretKey, bucket, url)
+        }
+        getQiniuAccessToken(url) {
+            getQiNiuServer().getAccessToken(url)
+        }
+        getQiniuBuckets(callback){
+            getQiNiuServer().getBuckets(callback)
+        }
+        getQiniuBucketsUrl(buketName, callback){
+            getQiNiuServer().getBucketsUrl(buketName, callback)
+        }
+
+        //Cos
+        updateCos(acessKey, secretKey, bucket, region,protocol){
+            getCOSServer().update(acessKey, secretKey, bucket, region,protocol)
+        }
+        getCosService(cb){
+            getCOSServer().getService(cb)
+        }
+        getCosFileURL(key, cb){
+            getCOSServer().getFileURL(key, cb)
+        }
+        getCosBucketLocation(cb){
+            getCOSServer(). getBucketLocation(cb)
+        }
+        deleteObject(fileanme, cb){
+            getCOSServer().deleteObject(fileanme, cb)
+        }
+
+        //upload file
+        upload(pathArray, srcDir, callback) {
+            if (isUploading || typeof callback !== 'function')
+                return;
+            if (!(pathArray instanceof Array))
+                return;
+            startDate = new Date();
+            isUploading = true;
+            baseDir = srcDir;
+            uploadArray = pathArray;
+            finishedCallback = callback;
+            totalCount = uploadArray.length;
+            finishedCount = 0;
+            timeout = 0;
+            typeServer = moeApp.config.get('image-web-type');
+            typeBack = moeApp.config.get('image-back-type');
+
+            if (!successList) successList = new Map();
+            successList.clear();
+            if (!errorList) errorList = new Map();
+            errorList.clear();
+            if (!statusList) statusList = new Map();
+            statusList.clear();
+
+            if (totalCount > 0) {
+                checktime();
+                let len = (totalCount > 5) ? 5 : totalCount;
+                for (pathIndex = 0; pathIndex < len; pathIndex++) {
+                    asyncUploadFile(uploadArray[pathIndex], uploaded)
+                }
+            } else {
+                uploadEnd();
+            }
+        }
+    }
+    return UploadServer;
+})();

+ 51 - 165
views/main/hexo-image.js

@@ -4,11 +4,11 @@ window.md5 = (text) => {
 
 class ImgManager {
     constructor() {
-        this.fileName = path.basename(hexoWindow.fileName, path.extname(hexoWindow.fileName)) || hexoWindow.ID || "";
-        this.imgPathToUrl = {};
-        this.imgPathToDel = {};
-        this.imgMD5IDList = {};
-        this.imgPathIDList = {};
+        this.postName = path.basename(hexoWindow.fileName, path.extname(hexoWindow.fileName)) || hexoWindow.ID || "";
+        this.imgMD5ToPath = {};
+        this.imgPathToUrlPath = {};
+        this.imgPathToMarkURL = {};
+        this.imgPathToDelHash = {};
         this.imgBaseDir = '';
         this.imgPathDir = '';
         this.type = {
@@ -30,9 +30,9 @@ class ImgManager {
             rootPaht = hexoWindow.directory;
         }
         rootPaht = rootPaht.replace(/\\/g, '/');
-        this.imgPathDir = path.join(rootPaht, this.fileName);
+        this.imgPathDir = path.join(rootPaht, this.postName);
         if (this.imgBaseDir && this.imgBaseDir !== rootPaht) {
-            const oldPath = path.join(this.imgBaseDir, this.fileName);
+            const oldPath = path.join(this.imgBaseDir, this.postName);
             if (fs.existsSync(oldPath)) {
                 try {
                     fs.renameSync(oldPath, this.imgPathDir);
@@ -81,52 +81,24 @@ class ImgManager {
         return path.resolve(this.imgBaseDir, p).replace(/\\/g, '/');
     }
 
-    getSmmsServer() {
-        if (!this.smmsServer) {
-            this.smmsServer = moeApp.getSmmsServer();
+    getUploadServer() {
+        if (!this.uploadServer) {
+            this.uploadServer = moeApp.getUploadServer();
         }
-        return this.smmsServer;
-    }
-    getQiNiuServer() {
-        if (!this.qiniuServer) {
-            this.qiniuServer = moeApp.getQiniuServer();
-            this.qiniuServer.update(
-                moeApp.config.get('image-qiniu-accessKey'),
-                moeApp.config.get('image-qiniu-secretKey'),
-                moeApp.config.get('image-qiniu-bucket'),
-                moeApp.config.get('image-qiniu-url-protocol') + moeApp.config.get('image-qiniu-url') + '/'
-            );
-        }
-        return this.qiniuServer;
-    }
-
-    getCOSServer() {
-        if (!this.cosServer) {
-            this.cosServer = moeApp.getCOSServer();
-            let bucketObj = moeApp.config.get('image-cos-bucket');
-            bucketObj = (bucketObj||"|").split('|');
-            this.cosServer.update(
-                moeApp.config.get('image-cos-accessKey'),
-                moeApp.config.get('image-cos-secretKey'),
-                bucketObj[0],
-                bucketObj[1],
-                moeApp.config.get('image-cos-url-protocol')
-            );
-        }
-        return this.cosServer;
+        return this.uploadServer;
     }
 
     getImageOfPath(imgPath, md5ID) {
         if (fs.existsSync(imgPath)) {
             imgPath = imgPath.replace(/\\/g, '/');
             let relativePath = '';
-            if (this.imgPathIDList[imgPath]) {
-                relativePath = this.imgPathIDList[imgPath];
+            if (this.imgPathToMarkURL[imgPath]) {
+                relativePath = this.imgPathToMarkURL[imgPath];
             } else {
                 relativePath = '/' + path.relative(this.imgBaseDir, imgPath).replace(/\\/g, '/');
-                this.imgPathIDList[imgPath] = relativePath;
+                this.imgPathToMarkURL[imgPath] = relativePath;
                 if (md5ID) {
-                    this.imgMD5IDList[md5ID] = imgPath;
+                    this.imgMD5ToPath[md5ID] = imgPath;
                 }
             }
             return relativePath
@@ -148,13 +120,13 @@ class ImgManager {
                 }
 
                 imgPath = imgPath.replace(/\\/g, '/');
-                if (this.imgPathIDList[imgPath]) {
-                    relativePath = this.imgPathIDList[imgPath];
+                if (this.imgPathToMarkURL[imgPath]) {
+                    relativePath = this.imgPathToMarkURL[imgPath];
                 } else {
                     relativePath = '/' + path.relative(this.imgBaseDir, imgPath).replace(/\\/g, '/');
-                    this.imgPathIDList[imgPath] = relativePath;
+                    this.imgPathToMarkURL[imgPath] = relativePath;
                     if (md5ID) {
-                        this.imgMD5IDList[md5ID] = imgPath;
+                        this.imgMD5ToPath[md5ID] = imgPath;
                     }
                 }
             } catch (e) {
@@ -176,8 +148,8 @@ class ImgManager {
         }
 
         let md5ID = md5(imgObject);
-        if (this.imgMD5IDList[md5ID]) {
-            return this.imgPathIDList[this.imgMD5IDList[md5ID]]
+        if (this.imgMD5ToPath[md5ID]) {
+            return this.imgPathToMarkURL[this.imgMD5ToPath[md5ID]]
         }
         let imageName = imgName || require('moment')().format('YYYYMMDDhhmmssSSS');
         ext = (ext && this.type[ext.toLowerCase().replace(/^\./, '')]) || '.png';
@@ -203,142 +175,46 @@ class ImgManager {
     }
 
     renameDirPath(fileName) {
-        this.updateDictionary('/' + this.filename + '/', '/' + fileName + '/')
-        this.filename = fileName;
+        this.updateDictionary('/' + this.postName + '/', '/' + fileName + '/')
+        this.postName = fileName;
     }
 
     updateDictionary(oldStr, newStr) {
-        if (Object.keys(this.imgPathIDList).length > 0) {
-            this.imgPathIDList = JSON.parse(JSON.stringify(this.imgPathIDList).replace(new RegExp(oldStr, 'g'), newStr));
-            if (Object.keys(this.imgMD5IDList).length > 0)
-                this.imgMD5IDList = JSON.parse(JSON.stringify(this.imgMD5IDList).replace(new RegExp(oldStr, 'g'), newStr));
+        if (Object.keys(this.imgPathToMarkURL).length > 0) {
+            this.imgPathToMarkURL = JSON.parse(JSON.stringify(this.imgPathToMarkURL).replace(new RegExp(oldStr, 'g'), newStr));
+            if (Object.keys(this.imgMD5ToPath).length > 0)
+                this.imgMD5ToPath = JSON.parse(JSON.stringify(this.imgMD5ToPath).replace(new RegExp(oldStr, 'g'), newStr));
         }
     }
 
     uploadDelAll() {
-        Object.keys(this.imgPathToDel).forEach(k => {
-            this.getSmmsServer().del(imgManager.imgPathToDel[k])
-            delete imgManager.imgPathToDel[k];
+        Object.keys(this.imgPathToDelHash).forEach(k => {
+            this.getSmmsServer().del(imgManager.imgPathToDelHash[k])
+            delete imgManager.imgPathToDelHash[k];
         })
     }
 
 
-    asyncUploadToSmms(imgPath, callback) {
-        this.getSmmsServer().uploadFile(imgPath,'',callback);
-    }
-
-    asyncUploadToQiNiu(imgPath, callback) {
-        this.getQiNiuServer().uploadFile(imgPath,this.relativePath(imgPath).slice(1),callback);
-    }
-
-    asyncUploadToCOS(imgPath, callback) {
-        this.getCOSServer().sliceUploadFile(imgPath,this.relativePath(imgPath).slice(1),callback);
-    }
-
-    asyncUploadFile(imgPath, callback) {
-        switch (this.type){
-            case 'qiniu':
-                this.asyncUploadToQiNiu(imgPath,callback)
-                break;
-            case 'cos':
-                this.asyncUploadToCOS(imgPath,callback)
-                break;
-            default:
-                this.asyncUploadToSmms(imgPath, callback);
-        }
-    }
-
     uploadLocalSrc() {
-        this.isUploading = true;
-        this.timeout = 0;
-        this.type = moeApp.config.get('image-web-type');
-
-        let finishedCount = 0;
-        let uploadList = new Map();
-        let successList = new Map();
-        let errorList = new Map();
-
-        function checktime(isBreak) {
-            clearTimeout(imgManager.timeout);
-            if (!isBreak)
-                imgManager.timeout = setTimeout(() => {
-                    uploadEnd(true);
-                }, 30000)
-        }
-
+        let arr = [];
         document.querySelector('#right-panel').querySelectorAll('img[localimg="true"]').forEach((item) => {
             let filePath = decodeURI(item.src).replace(/^file:\/\/\//, '');
             if (fs.existsSync(filePath)) {
-                uploadList.set(filePath, filePath);
+                arr.push(filePath);
             } else {
-                errorList.set(filePath, 'No Find File.');
             }
         })
 
-        if (uploadList.size > 0) {
-            checktime();
-            uploadList.forEach((filepath) => {
-                imgManager.asyncUploadFile(filepath, uploadRequest)
-            })
-        } else {
-            uploadEnd();
-        }
-
-        /**
-         * 回调函数
-         * @param fileID
-         * @param response
-         *   response = {
-         *      id: 'localFileAbsolutePath',                      //传入文件本地绝对路径
-         *      statusCode: 200|int,                              //服务器代码,200:正常,其他:报错
-         *      data: {
-         *        localname: 'abc.png',                           //本地文件名
-         *        storename: '5a6bea876702d.png',                 //服务器文件名,SM.MS随机生成
-         *        path: '/abc/abc/5a6bea876702d.png',             //服务器路径
-         *        url: 'https://...../abc/abc/5a6bea876702d.png'  //图片地址
-         *      },
-         *      msg: 'error message'                              //一般只有报错才使用到
-         *      errorlist: 'url'                                  //一般只有报错才使用到
-         *   }
-         * }
-         */
-        function uploadRequest(response) {
-            finishedCount++;
-            console.log(finishedCount + '/' + uploadList.size)
-            if (response.statusCode == 200) {
-                successList.set(response.id, response)
-            } else {
-                errorList.set(response.id, response)
-            }
-            if (finishedCount >= uploadList.size) {
-                checktime(true);
-                uploadEnd(false);
-                return;
-            }
-            checktime();
-        }
+        this.getUploadServer().upload(arr,this.imgBaseDir,(success,error)=>{
+            updateSrc(success)
+            updateError(error)
+        });
 
-        function updateSrc() {
-            let value = editor.getValue();
-            successList.forEach((response) => {
-                value = value.replace(new RegExp(imgManager.relativePath(response.id), 'g'), response.data.url);
-                imgManager.imgPathToUrl[response.id] = response.data.url;
-                imgManager.imgPathToDel[response.id] = response.data.hash;
-            })
-
-            editor.setValue(value);
-            hexoWindow.content = value;
-            hexoWindow.changed = true;
-        }
-
-        function uploadEnd(isTimeout) {
-            try {
-                updateSrc();
+        function updateError(errorList) {
                 let errMsg = '';
                 errorList.forEach((response) => {
                     errMsg += response.id + ':' + __(response.msg) + '</br>';
                 })
-                if (isTimeout) errMsg += 'Upload time out.';
                 if (errMsg) {
                     window.popMessageShell(null, {
                         content: errMsg,
@@ -347,15 +223,25 @@ class ImgManager {
                     })
                 } else {
                     window.popMessageShell(null, {
-                        content: __('All Files') + ' ' + __('Upload Finished') + ' (' + uploadList.size + ')',
+                        content: __('All Files') + ' ' + __('Upload Finished'),
                         type: 'success',
                         btnTip: 'check',
                         autoHide: true
                     });
                 }
-            } finally {
-                imgManager.isUploading = false;
-            }
+        }
+
+        function updateSrc(successList) {
+            var content = editor.getValue();
+            successList.forEach((response) => {
+                content = content.replace(new RegExp(imgManager.imgPathToMarkURL[response.id], 'g'), response.data.url);
+                imgManager.imgPathToUrlPath[response.id] = response.data.path;
+                imgManager.imgPathToMarkURL[response.id] = response.data.url;
+                imgManager.imgPathToDelHash[response.id] = response.data.hash||'';
+            })
+            editor.setValue(content);
+            hexoWindow.content = content;
+            hexoWindow.changed = true;
         }
     }
 }

+ 22 - 2
views/main/moe-contextmenu.js

@@ -30,6 +30,26 @@ document.addEventListener('DOMContentLoaded', () => {
         e.preventDefault();
         if (editor.contains(e.target) || containerWrapper.contains(e.target)) {
             const inEditor = editor.contains(e.target);
+            // label: (moeApp.config.get('image-web-type')=='qiniu')? __('UploadToQiNiu'):((moeApp.config.get('image-web-type')=='cos')?__('UploadToCOS'):__('UploadToSMMS')),
+            //     enabled: moeApp.config.get('image-web-type')&&!imgManager.isUploading,
+            //     click(item, w) {
+            //     !imgManager.uploadLocalSrc();
+            // }
+            let imageType = moeApp.config.get('image-web-type');
+            let imageMenuLable = '';
+            let imageMenuEnable = true;
+            if ( imageType=='qiniu') {
+                imageMenuLable =  __('UploadToQiNiu');
+                imageMenuEnable = !moeApp.getUploadServer().isLoading() && !!moeApp.config.get('image-qiniu-url')
+            }else
+            if ( imageType=='cos') {
+                imageMenuLable = __('UploadToCOS');
+                imageMenuEnable = !moeApp.getUploadServer().isLoading() && !!moeApp.config.get('image-cos-url')
+            }else {
+                imageMenuLable = __('UploadToSMMS');
+                imageMenuEnable = !moeApp.getUploadServer().isLoading()
+            }
+
             const template = [
                 {
                     label: __('Undo'),
@@ -114,8 +134,8 @@ document.addEventListener('DOMContentLoaded', () => {
                     type: 'separator',
                 },
                 {
-                    label: (moeApp.config.get('image-web-type')=='qiniu')? __('UploadToQiNiu'):((moeApp.config.get('image-web-type')=='cos')?__('UploadToCOS'):__('UploadToSMMS')),
-                    enabled: !imgManager.isUploading,
+                    label: imageMenuLable,
+                    enabled: imageMenuEnable,
                     click(item, w) {
                         !imgManager.uploadLocalSrc();
                     }

+ 5 - 0
views/settings/moe-settings.css

@@ -134,4 +134,9 @@ option.builtin{
 
 option.invalidFile {
     color: red;
+}
+
+span.checkbtn{
+    width: 15px;
+    display: inline-block;
 }

+ 109 - 56
views/settings/moe-settings.js

@@ -482,6 +482,10 @@ document.addEventListener('DOMContentLoaded', () => {
     let imageTabContents = document.querySelector('.panel[data-tab="image"]');
     let imageType = imageTabContents.querySelector('#image-web-type');
 
+    //SM.MS
+    let imageSmmsBackQiniu = imageTabContents.querySelector('#image-back-type-qiniu');
+    let imageSmmsBackCos = imageTabContents.querySelector('#image-back-type-cos');
+
     //QiNiu
     let imageAccessKey = imageTabContents.querySelector('#image-qiniu-accessKey');
     let imageSecretKey = imageTabContents.querySelector('#image-qiniu-secretKey');
@@ -498,12 +502,16 @@ document.addEventListener('DOMContentLoaded', () => {
 
     imageType.addEventListener('change', function (e) {
         moeApp.config.set(imageType.id, imageType.value);
+        let imageSmmsItems = imageTabContents.querySelectorAll('tr[data-type="image-smms"]')
         let imageQiNiuItems = imageTabContents.querySelectorAll('tr[data-type="image-qiniu"]')
         let imageCosItems = imageTabContents.querySelectorAll('tr[data-type="image-cos"]')
         if (imageType.value == 'qiniu') {
             imageAccessKey.value = moeApp.config.get(imageAccessKey.id);
             imageSecretKey.value = moeApp.config.get(imageSecretKey.id);
             checkBuckets();
+            imageSmmsItems.forEach((item) => {
+                item.style.display = 'none'
+            })
             imageCosItems.forEach((item) => {
                 item.style.display = 'none'
             })
@@ -514,6 +522,9 @@ document.addEventListener('DOMContentLoaded', () => {
             imageCosAccessKey.value = moeApp.config.get(imageCosAccessKey.id);
             imageCosSecretKey.value = moeApp.config.get(imageCosSecretKey.id);
             checkCosBuckets();
+            imageSmmsItems.forEach((item) => {
+                item.style.display = 'none'
+            })
             imageQiNiuItems.forEach((item) => {
                 item.style.display = 'none'
             })
@@ -527,36 +538,95 @@ document.addEventListener('DOMContentLoaded', () => {
             imageCosItems.forEach((item) => {
                 item.style.display = 'none'
             })
+            imageSmmsItems.forEach((item) => {
+                item.style.display = 'table-row'
+            })
             ipcRenderer.send('setting-changed', {key: imageType.id, val: imageType.value});
         }
         imageTabItem.click();
     })
 
-    //QiNiu
-    function hasQiNiuServer() {
-        if (imageAccessKey.value && imageSecretKey.value && !global.qiniuServer) {
-            global.qiniuServer = moeApp.getQiniuServer();
-            qiniuServer.update(
-                moeApp.config.get('image-qiniu-accessKey'),
-                moeApp.config.get('image-qiniu-secretKey'),
-                moeApp.config.get('image-qiniu-bucket'),
-                moeApp.config.get('image-qiniu-url-protocol') + moeApp.config.get('image-qiniu-url') + '/'
-            );
-            qiniuServer.update(
-                imageAccessKey.value,
-                imageSecretKey.value,
-                imageBucket.value,
-                imageBaseWebProtocol + imageBaseWeb + '/'
-            )
-            return true;
+    function hasUploadServer() {
+        if (!global.uploadServer) {
+            global.uploadServer = moeApp.getUploadServer();
+            return global.uploadServer;
         }
-        return global.qiniuServer;
+        return global.uploadServer;
     }
 
+    //SM.MS
+    var backtype = moeApp.config.get('image-back-type');
+    if ([222, 22].includes(backtype)) {
+        imageSmmsBackQiniu.value = 1;
+        imageSmmsBackQiniu.innerHTML = '<i class="fa fa-check-square-o" aria-hidden="true"></i>'
+    } else {
+        imageSmmsBackQiniu.value = 0;
+        imageSmmsBackQiniu.innerHTML = '<i class="fa fa-square-o" aria-hidden="true"></i>'
+    }
+    if ([222, 202].includes(backtype)) {
+        imageSmmsBackCos.value = 1;
+        imageSmmsBackCos.innerHTML = '<i class="fa fa-check-square-o" aria-hidden="true"></i>'
+    } else {
+        imageSmmsBackCos.value = 0;
+        imageSmmsBackCos.innerHTML = '<i class="fa fa-square-o" aria-hidden="true"></i>'
+    }
+
+    imageSmmsBackQiniu.addEventListener('click', () => {
+        var backtype = moeApp.config.get('image-back-type');
+        if (imageSmmsBackQiniu.value == 0) {
+            if (moeApp.config.get(imageBaseWeb.id)){
+                imageSmmsBackQiniu.value = 1;
+                imageSmmsBackQiniu.innerHTML = '<i class="fa fa-check-square-o" aria-hidden="true"></i>'
+                if (backtype> 200)
+                    backtype = 222;
+                else
+                    backtype = 22;
+            } else {
+                let imageQiNiuItems = imageTabContents.querySelectorAll('tr[data-type="image-qiniu"]');
+                imageQiNiuItems.forEach((item) => {
+                    item.style.display = 'table-row'
+                })
+                imageTabItem.click();
+            }
+        } else {
+            imageSmmsBackQiniu.value = 0;
+            imageSmmsBackQiniu.innerHTML = '<i class="fa fa-square-o" aria-hidden="true"></i>'
+            if (backtype> 200)
+                backtype = 202;
+            else
+                backtype = 2;
+        }
+        moeApp.config.set('image-back-type',backtype);
+    })
+    imageSmmsBackCos.addEventListener('click', () => {
+        var backtype = moeApp.config.get('image-back-type');
+        if (imageSmmsBackCos.value == 0) {
+            if (moeApp.config.get(imageBaseWeb.id)) {
+                imageSmmsBackCos.value = 1;
+                imageSmmsBackCos.innerHTML = '<i class="fa fa-check-square-o" aria-hidden="true"></i>'
+                if (backtype < 23)
+                    backtype += 200;
+            } else {
+                let imageCosItems = imageTabContents.querySelectorAll('tr[data-type="image-cos"]')
+                imageCosItems.forEach((item) => {
+                    item.style.display = 'table-row'
+                })
+                imageTabItem.click();
+            }
+        } else {
+            imageSmmsBackCos.value = 0;
+            imageSmmsBackCos.innerHTML = '<i class="fa fa-square-o" aria-hidden="true"></i>'
+            if (backtype> 200)
+                backtype -= 200;
+        }
+        moeApp.config.set('image-back-type',backtype);
+    })
+
+    //QiNiu
     function checkBuckets() {
-        if (hasQiNiuServer()) {
+        if (hasUploadServer()) {
             let oldBucket = moeApp.config.get(imageBucket.id);
-            qiniuServer.getBuckets((response) => {
+            uploadServer.getQiniuBuckets((response) => {
                 imageBucket.innerHTML = '';
                 if (response.statusCode == 200) {
                     response.data.forEach((name) => {
@@ -581,9 +651,9 @@ document.addEventListener('DOMContentLoaded', () => {
     }
 
     function checkURLs(bucket) {
-        if (hasQiNiuServer()) {
+        if (hasUploadServer()) {
             let oldurl = moeApp.config.get(imageBaseWeb.id);
-            qiniuServer.getBucketsUrl(bucket, (response) => {
+            uploadServer.getQiniuBucketsUrl(bucket, (response) => {
                 if (response.statusCode == 200) {
                     imageBaseWeb.innerHTML = '';
                     response.data.forEach((url) => {
@@ -614,8 +684,8 @@ document.addEventListener('DOMContentLoaded', () => {
             let oldKey = moeApp.config.get(imageAccessKey.id);
             if (oldKey != imageAccessKey.value) {
                 moeApp.config.set(imageAccessKey.id, imageAccessKey.value);
-                if (hasQiNiuServer()) {
-                    qiniuServer.update(imageAccessKey.value, imageSecretKey.value)
+                if (hasUploadServer()) {
+                    uploadServer.updateQiniu(imageAccessKey.value, imageSecretKey.value)
                     ipcRenderer.send('setting-changed', {key: imageAccessKey.id, val: imageAccessKey.value});
                     checkBuckets();
                 }
@@ -631,8 +701,8 @@ document.addEventListener('DOMContentLoaded', () => {
             let oldKey = moeApp.config.get(imageSecretKey.id);
             if (oldKey != imageSecretKey.value) {
                 moeApp.config.set(imageSecretKey.id, imageSecretKey.value);
-                if (hasQiNiuServer()) {
-                    qiniuServer.update(imageAccessKey.value, imageSecretKey.value)
+                if (hasUploadServer()) {
+                    uploadServer.updateQiniu(imageAccessKey.value, imageSecretKey.value)
                     ipcRenderer.send('setting-changed', {key: imageSecretKey.id, val: imageSecretKey.value});
                     checkBuckets();
                 }
@@ -652,7 +722,7 @@ document.addEventListener('DOMContentLoaded', () => {
 
 
     function protocolChange(type) {
-        if ((!type && imageBaseWebProtocol.value == 'http://') ||  type == 'https://') {
+        if ((!type && imageBaseWebProtocol.value == 'http://') || type == 'https://') {
             imageBaseWebProtocol.style.width = '53px';
             imageBaseWeb.style.width = 'calc(100% - 57px)';
             imageBaseWebProtocol.value = 'https://';
@@ -684,33 +754,16 @@ document.addEventListener('DOMContentLoaded', () => {
 
 
     //Tencent
-    function hasCosServer() {
-        if (imageCosAccessKey.value && imageCosSecretKey.value && !global.cosServer) {
-            global.cosServer = moeApp.getCOSServer();
-            let bucketObj = moeApp.config.get('image-cos-bucket');
-            bucketObj = (bucketObj||"|").split('|');
-            cosServer.update(
-                moeApp.config.get('image-cos-accessKey'),
-                moeApp.config.get('image-cos-secretKey'),
-                bucketObj[0],
-                bucketObj[1],
-                moeApp.config.get('image-cos-url-protocol')
-            );
-            return true;
-        }
-        return global.cosServer;
-    }
-
     function checkCosBuckets() {
-        if (hasCosServer()) {
+        if (hasUploadServer()) {
             let oldBucket = moeApp.config.get(imageCosBucket.id);
-            cosServer.getService((response) => {
+            uploadServer.getCosService((response) => {
                 imageCosBucket.innerHTML = '';
                 if (response.statusCode == 200) {
                     response.Buckets.forEach((bucket) => {
                         let option = document.createElement('option');
-                        option.value = bucket.Name + '|' +bucket.Location;
-                        option.innerText = '['+bucket.Location+']  ' + bucket.Name ;
+                        option.value = bucket.Name + '|' + bucket.Location;
+                        option.innerText = '[' + bucket.Location + ']  ' + bucket.Name;
                         imageCosBucket.appendChild(option);
                         if ((option.value == oldBucket)) {
                             option.selected = true;
@@ -720,12 +773,12 @@ document.addEventListener('DOMContentLoaded', () => {
                     if (!imageCosBucket.value && imageCosBucket.firstChild) {
                         imageCosBucket.value = imageCosBucket.firstChild.value;
                     }
-                    if(imageCosBucket.value) {
+                    if (imageCosBucket.value) {
                         let event = new Event('change');
                         imageCosBucket.dispatchEvent(event);
                     }
                 } else {
-                    console.log(response,response.error.Message) ;
+                    console.log(response, response.error.Message);
                 }
             })
         }
@@ -737,8 +790,8 @@ document.addEventListener('DOMContentLoaded', () => {
             let oldKey = moeApp.config.get(imageCosAccessKey.id);
             if (oldKey != imageCosAccessKey.value) {
                 moeApp.config.set(imageCosAccessKey.id, imageCosAccessKey.value);
-                if (hasCosServer()) {
-                    cosServer.update(imageCosAccessKey.value, imageCosSecretKey.value)
+                if (hasUploadServer()) {
+                    uploadServer.updateCos(imageCosAccessKey.value, imageCosSecretKey.value)
                     ipcRenderer.send('setting-changed', {key: imageCosAccessKey.id, val: imageCosAccessKey.value});
                     checkCosBuckets();
                 }
@@ -754,8 +807,8 @@ document.addEventListener('DOMContentLoaded', () => {
             let oldKey = moeApp.config.get(imageCosSecretKey.id);
             if (oldKey != imageCosSecretKey.value) {
                 moeApp.config.set(imageCosSecretKey.id, imageCosSecretKey.value);
-                if (hasCosServer()) {
-                    cosServer.update(imageCosAccessKey.value, imageCosSecretKey.value)
+                if (hasUploadServer()) {
+                    uploadServer.updateCos(imageCosAccessKey.value, imageCosSecretKey.value)
                     ipcRenderer.send('setting-changed', {key: imageCosSecretKey.id, val: imageCosSecretKey.value});
                     checkCosBuckets();
                 }
@@ -769,7 +822,7 @@ document.addEventListener('DOMContentLoaded', () => {
 
     imageCosBucket.addEventListener('change', function (e) {
         moeApp.config.set(imageCosBucket.id, imageCosBucket.value);
-        imageCosBaseWeb.value = imageCosBucket.value.replace('|','.cos.') + '.myqcloud.com' + '/';
+        imageCosBaseWeb.value = imageCosBucket.value.replace('|', '.cos.') + '.myqcloud.com' + '/';
         imageCosBaseWeb.title = imageCosBaseWeb.value;
         moeApp.config.set(imageCosBaseWeb.id, imageCosBaseWeb.value);
         ipcRenderer.send('setting-changed', {key: imageCosBucket.id, val: imageCosBucket.value});
@@ -778,7 +831,7 @@ document.addEventListener('DOMContentLoaded', () => {
 
 
     function protocolChange(type) {
-        if ((!type && imageCosBaseWebProtocol.value == 'http://') ||  type == 'https://') {
+        if ((!type && imageCosBaseWebProtocol.value == 'http://') || type == 'https://') {
             imageCosBaseWebProtocol.style.width = '53px';
             imageCosBaseWeb.style.width = 'calc(100% - 57px)';
             imageCosBaseWebProtocol.value = 'https://';

+ 10 - 1
views/settings/settings.html

@@ -302,12 +302,21 @@
                                 <td width="30%" class="l10n">Web Type</td>
                                 <td width="70%">
                                     <select class="settings-item-image" id="image-web-type">
-                                        <option value="sm" class="l10n">WebSM</option>
+                                        <option value="smms" class="l10n">WebSM</option>
                                         <option value="qiniu" class="l10n">QiNiu</option>
                                         <option value="cos" class="l10n">WebCOS</option>
                                     </select>
                                 </td>
                             </tr>
+                            <tr data-type="image-smms" style="display:table-row">
+                                <td width="30%" class="l10n">BackImage</td>
+                                <td width="70%">
+                                    <div id="image-back-type">
+                                        <span id="image-back-type-qiniu" class="checkbtn"></span><span class="l10n" >QiNiu</span>
+                                       <span id="image-back-type-cos" class="checkbtn"></span><span class="l10n" >WebCOS</span>
+                                    </div>
+                                </td>
+                            </tr>
                             <tr data-type="image-qiniu" style="display:none">
                                 <td width="30%" class="l10n">AccessKey</td>
                                 <td width="70%">