diff --git a/_config.yml b/_config.yml index 68c0d05..a658e64 100644 --- a/_config.yml +++ b/_config.yml @@ -79,6 +79,9 @@ pagination_dir: page ## Themes: https://hexo.io/themes/ theme: yilia +# 图片存储仓库地址 +picture_cdn: https://blog-cdn.nos-eastchina1.126.net + ### 站点地图 sitemap: path: sitemap.xml diff --git a/scripts/filter.js b/scripts/filter.js new file mode 100644 index 0000000..4ffb21e --- /dev/null +++ b/scripts/filter.js @@ -0,0 +1,9 @@ +hexo.extend.filter.register('before_post_render', function(data){ + // data.raw 是原始的文件内容 + // data.content 是处理过代码块语法高亮的内容 + if(hexo.config.picture_cdn) { + data.content = data.content.replace(/\]\s*\((?=(?!http).*?\))/gi, + `](${hexo.config.picture_cdn}`) + } + return data; +}); \ No newline at end of file diff --git a/source/_posts/linux/博客图片迁移记.md b/source/_posts/linux/博客图片迁移记.md index d582889..a9bda85 100644 --- a/source/_posts/linux/博客图片迁移记.md +++ b/source/_posts/linux/博客图片迁移记.md @@ -48,6 +48,7 @@ optimist这个包可以方便处理运行时的命令行参数 ```javascript const fs = require('fs') const path = require('path') +const crypto = require('crypto') /** * 递归遍历目录中的所有文件 @@ -63,7 +64,14 @@ function readDirSync(imageFolderPath, images, rootPath){ // 该文件是一个目录, 则遍历该目录内容 readDirSync(`${imageFolderPath}/${item}`, images, rootPath) }else{ - images.push(`${imageFolderPath}/${item}`.replace(rootPath, '')) + //读取一个Buffer + let buffer = fs.readFileSync(`${imageFolderPath}/${item}`) + let fsHash = crypto.createHash('md5') + fsHash.update(buffer) + images.push({ + name: `${imageFolderPath}/${item}`.replace(rootPath, ''), + md5: fsHash.digest('hex') + }) } }) return images @@ -73,11 +81,13 @@ module.exports = function (rootPath, imageFloder) { return readDirSync(path.resolve(rootPath, imageFloder), [], rootPath) } ``` -由于目录当中可能包含子目录, 所以需要进行递归遍历 +1. 由于目录当中可能包含子目录, 所以需要进行递归遍历 +2. 使用nodejs提供的`crypto`模块来计算文件的md5哈希值 +( 由于接口返回的数据也是md5的哈希值, 可以用它来比对文件差异 ) > 调用该模块暴露出的函数传入根目录和图片目录 比如imageFloder传入的是'images/' -获得的是形如 _['images/a.png','images/sub/b.jpg'...]_ 的一个数组 +获得的是形如 _\[{name:'images/a.png',hash:'xxx',...\]_ 的一个数组 #### auth_info.json 把访问对象仓库API需要的认证信息放在一个json文件当中 @@ -94,7 +104,8 @@ module.exports = function (rootPath, imageFloder) { #### index.js 在这个模块里面大概需要做以下几件事 1. 调用sdk当中提供的listObject接口获取到对象仓库里面已有的文件列表 -2. 将对象仓库的文件列表与本地文件列表进行比对, 找出本地有但是对象仓库里面没有的 +2. 将对象仓库的文件列表与本地文件列表进行比对, 包括文件名和hash值的比对 +找出本地有但是对象仓库里面没有的, 或者都有但是hash值不同, 就是文件有差别的 3. 调用sdk当中提供的putObject接口上传差异文件 ```javascript @@ -115,7 +126,7 @@ const imagesList = listImages(rootPath, prefix) const NosClient = require('@xgheaven/nos-node-sdk').NosClient const client = new NosClient(require('./auth_info.json')) -queryObjects.call(client, {limit: imagesList.length + 1, prefix}) +queryObjects.call(client, {limit: imagesList.length+1, prefix}) /** * 查询所有对象存储库已存在的文件 * @param {Object} params @@ -126,14 +137,23 @@ function queryObjects(params) { // ret 包括 items(元素),limit(请求的数量),nextMarker(下一个标记) let storageItems = ret.items.filter((item) => { return /^images.+?\.(png|jpg|gif)$/.test(item.key) - }).map(item => { - return item.key }) let notExistFiles = imagesList.filter((item) => { - return !storageItems.includes(item) + let index = storageItems.findIndex(storageItem => { + return storageItem.key === item.name + }) + if(index === -1) { + // 文件名不存在, 代表是新文件 + item.type = 'new' + return true + } else if(storageItems[index].eTag !== item.md5) { + // 文件名存在, 但是hash值不同, 代表有变化 + item.type = 'change' + return true + } + return false }) uploadObject.call(this, notExistFiles, 0) - // 所有的 List 操作接口返回的数据都是类似的,比如 listObject, listBucket, listParts, listMultipart }) } /** @@ -145,11 +165,16 @@ function uploadObject(filesList, index) { if(index >= filesList.length) return this.putObject({ - objectKey: filesList[index], - body: fs.createReadStream(path.resolve(rootPath, filesList[index])), // 支持 Buffer/Readable/string + objectKey: filesList[index].name, + body: fs.createReadStream(path.resolve(rootPath, filesList[index].name)), // 支持 Buffer/Readable/string }).then(result => { - // eTag是上传后远端校验的md5值, 可用于和本地进行比对 - console.log(`${filesList[index]} 上传成功, md5:${result.eTag}`) + // eTag是上传后远端校验的md5值, 用于和本地进行比对 + if(filesList[index].md5 === result.eTag) { + console.log(`${filesList[index].name} 上传成功, md5:${result.eTag} 类型: ${item.type}`) + } else { + console.warn(`${filesList[index].name} 上传出错, md5值不一致`) + console.warn(`===> 本地文件: ${item.md5}, 接口返回: ${result.eTag}`) + } uploadObject.call(this, filesList, ++index) }) } @@ -205,11 +230,24 @@ npm run start -- --rootPath ${workspacePath}/source/ 形如`/images/linux/nos/AccessKey.png`, 批量修改又不利于将来的迁移 所以参考了hexo的官方文档之后, 考虑在静态化过程当中添加一个过滤器 +#### 添加配置 +在根目录的`_config.yml`文件添加自定义的配置项 +```yaml +# 图片存储仓库地址 +picture_cdn: https://blog-cdn.nos-eastchina1.126.net +``` + +#### filter.js +创建**scripts**目录 ( 可以是根目录或者主题目录下, 均有效 ) +创建**filter.js**文件 ```javascript hexo.extend.filter.register('before_post_render', function(data){ // data.raw 是原始的文件内容 // data.content 是处理过代码块语法高亮的内容 - data.content = data.content.replace(/\]\s*\((?=(?!http).*?\))/gi, '](https://blog-cdn.nos-eastchina1.126.net') + if(hexo.config.picture_cdn) { + data.content = data.content.replace(/\]\s*\((?=(?!http).*?\))/gi, + `](${hexo.config.picture_cdn}`) + } return data; }); ``` @@ -224,9 +262,4 @@ hexo.extend.filter.register('before_post_render', function(data){ 之前的构建步骤没什么变化, 最后调用nodejs脚本只要成功把新图片上传上去就可以了 然后访问博客 查看文章页面中的图片路径是否正确 -![文章图片路径](/images/linux/nos/文章图片路径.png) - -### 未竟的事情 -1. 脚本当中只是简单比较文件路径和文件名来确定文件是否在对象仓库存在, 并没有精确比对文件是否有差异 -严格来说应该在本地读取文件获取到md5值, 然后根据listObject接口返回拿到的md5值进行比对 -2. 上传过程的成功未进行本地md5值与服务器回传的md5值的比对, 不能确定上传过程数据的完整性 \ No newline at end of file +![文章图片路径](/images/linux/nos/文章图片路径.png) \ No newline at end of file