背景
由于在本地存了很多markdown文档,上传到语雀上,特别麻烦,尤其是图片问题,这里我使用nodejs实现将本地markdown上传至语雀本地
为什么不用python?
因为python 的requests 库不支持http2,导致发包过去会报错,服务端不能正常响应
代码设计
api文档:https://www.yuque.com/yuque/developer/api
首先app.js 是封装的一个类,在构造函数里内置header头,里面存放必须的x-auth-token,以及UA头,并封装了get,post(application/json)的方法
// api.js
const axios = require('axios')
class YuqueApi{
constructor() {
this.headers = {
"X-Auth-Token": "<your_token>",
"User-Agent": "<your_UA>"
}
this.params = {}
}
set method(value) {
this.params.method = value
}
get method() {
return this.params.method
}
set uri(value) {
this.params.uri = value
}
get uri() {
return this.params.uri
}
set data(options) {
this.params.options = options
}
get data() {
return this.params.options
}
ajaxPostPromise() {
return axios({
url: this.uri,
method: this.method,
data: this.data,
headers :this.headers
}).then((response) => {
console.log(response.data)
return response.data
})
}
ajaxGetPromise() {
console.log(this.uri)
return axios({
url: this.uri,
method: this.method,
params: this.data,
headers :this.headers
}).then((response) => {
return response.data
})
}
}
module.exports = YuqueApi
在newPromise这个文件里,首先引入api.js里的类文件,并使用map这种的数据结构,存放key值,最后再拼接url,最后导出一个方法,供入口文件(app.js)使用,在此方法中,实例化该对象,并返回调用此方法的返回值
// newPromise.js
const Api = require('./api')
function searchMap(key,slug='') {
let map = new Map()
let baseUri = 'https://www.yuque.com/api/v2'
map.set('USER', '/user')
map.set('REPOS', '/users/da-labs/repos')
map.set('CREATE.DOC', '/repos/da-labs/secnotes/docs')
map.set('GET.DOCS', '/repos/da-labs/secnotes/docs')
map.set('GET.DOC', '/repos/da-labs/secnotes/docs')
return baseUri + map.get(key) + slug
}
module.exports = function askDataToServer({
url = '',
method = 'get',
params = {},
slug = '',
}) {
let api = new Api()
api.uri = searchMap(url,slug)
api.method = method
api.data = params
if (method === 'get')
return api.ajaxGetPromise()
else {
return api.ajaxPostPromise()
}
}
app.js 为 程序入口文件,在uploadImageAndReplace方法中(上传文件,这里是web端语雀,打开某一个文件,上传图片抓的包,这里使用的cookie,Referer,都是该文件的修改的时候抓包得到的,这里web端的cookie比较持久,而且上传的图片是在语雀的图床中,再将其转换为html时,上传到语雀里的时候,语雀就不会把它当作外链图片)
// app.js 入口文件
const http = require('./newPromise')
const fs = require('fs')
const marked = require('marked')
const axios = require('axios')
const FormData = require('form-data')
/*
@params
data = {
title:String,
slug: String (only one),
public: int(0,1)
format: String,
body:String( < 5 MB )
}
*/
async function createDoc(data) {
try {
return await http({
url: 'CREATE.DOC',
method: 'post',
params:data
})
} catch (e) {
return 'error'
}
}
/*
@params
filePath : String
@return array
*/
function getMarkDownFiles(filePath) {
var children = []
fs.readdirSync(filePath).forEach(function (filename) {
var path = filePath + "/" + filename
var stat = fs.statSync(path)
if (stat && stat.isDirectory()) {
children = children.concat(getMarkDownFiles(path))
}
else {
if (path.indexOf('.md') !== -1) {
children.push(path)
}
}
})
return children
}
/*
@params
markdown:String
@return Promise(markdown)
*/
function uploadImageAndReplace(markdown) {
return new Promise((reslove, reject) => {
let file = markdown
fs.readFile(file, encoding='UTF-8', async (err, data) => {
if (err) {
reject(err)
} else {
let oldImage = []
let oldImageChange = []
newData = data.replace(/\r|\n/ig,"")
reg = new RegExp(/!\[.*?\]\((.*?)\)/)
newData = data.match(/!\[.*?\]\((.*?)\)/mg)
for (let i = 0; i < newData.length; i++){
oldImage.push(reg.exec(newData[i])[1])
oldImageChange.push(reg.exec(newData[i])[1].replace(/\\/ig,'/'))
}
let newImage = []
for (let i = 0; i < oldImageChange.length; i++){
imgData = fs.createReadStream(oldImage[i])
let formData = new FormData()
formData.append('file', imgData)
headers = formData.getHeaders()
headers['Cookie'] = '<your_cookie>'
headers['Referer'] = '<your_Referer>'
headers['User-Agent'] = '<your_UA>'
let res = await axios({
url: '<your_url>',
method: 'post',
data: formData,
headers:headers
})
newImage.push(res.data.data.url)
}
for (let i = 0; i < oldImage.length; i++){
data = data.replace(oldImage[i], newImage[i])
}
reslove(data)
}
})
})
}
/*
@params
markdown:String
@return String(html)
*/
async function markdownToHtml(markdown) {
return marked.parse(markdown)
}
async function main() {
const filePath = '<your_dir>' // dir 最后结尾不带/
// 读取filepath 目录下所有markdown文档
let arrayFiles = getMarkDownFiles(filePath)
for (let i = 0; i < arrayFiles.length; i++){
// 将markdown文档中的所有图片抽取出来,并上传至图床,最后再将本机图片替换成上传到图床的图片
markdown = await uploadImageAndReplace(arrayFiles[i])
// 将markdown 文档转为html 格式的字符串
const html = await markdownToHtml(markdown)
// 随机生成6位字符串
let slug = Math.random().toString(36).slice(-6)
let title = arrayFiles[i].replace(filePath + '/', '').slice(0, -3)
if (title.indexOf('/') !== -1) {
reg = new RegExp(/\/(.*)/g)
title = reg.exec(title)[1]
}
data = {
title: title,
slug: slug,
public: 1,
format: 'markdown',
body:html
}
// 新增文档
res = await http({
url: 'CREATE.DOC',
method: 'post',
params:data
})
}
}
main()
效果
安装说明
# copy 代码
# 然后在该文档中,启动shell,执行命令,下载依赖
npm install
# 修改 app.js 里的filePath
# 修改 app.js 里的<your_cookie>,<your_Referer>,<your_Url>,<your_UA>,这些在抓包语雀的某一个文档上传时可以得到
node app