Skip to content

Instantly share code, notes, and snippets.

@Aaron-Bird
Last active April 5, 2024 12:31
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Aaron-Bird/30a16c162218db4315dfd2d11f5c2f0b to your computer and use it in GitHub Desktop.
Save Aaron-Bird/30a16c162218db4315dfd2d11f5c2f0b to your computer and use it in GitHub Desktop.
yuque-markdown-download
!(async () => {
// 配置
//是否下载储存在语雀上的图片
const DOWNLOAD_IMAGE = true;
// 修改 markdown 的图片路径
// 示例:MARKDOWN_IMAGE_PATH = "/image/";
// 效果:![](foo.png) -> ![](/image/foo.png)
const MARKDOWN_IMAGE_PATH = "";
class YuqueMarkdownDownload {
sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
randomNumStr() {
return "" + Date.now() + Math.ceil(Math.random() * 100000);
}
getBooks() {
return fetch("https://www.yuque.com/api/mine/book_stacks")
.then((resp) => resp.json())
.then(({ data: [{ books }] }) => books);
}
getDocs(bookId) {
return fetch(`https://www.yuque.com/api/docs?book_id=${bookId}`)
.then((resp) => resp.json())
.then(({ data }) => data);
}
downloadDoc({ login, bookSlug, slug }) {
return fetch(
`https://www.yuque.com/${login}/${bookSlug}/${slug}/markdown?plain=true&linebreak=false&anchor=false`
).then((resp) => resp.text());
}
downloadBlob(blob, filename) {
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
window.URL.revokeObjectURL(link.href);
}
async processMarkdownImage(markdown) {
const reg = /\!\[.*?\]\((https:\/\/cdn\.nlark.com\/yuque\/.*?)\)/gi;
const imgs = [...markdown.matchAll(reg)];
for (const img of imgs) {
const url = img?.[1];
const filename =
this.randomNumStr() +
"-" +
url.match(/[^\/]*?\.([^\.]*?)(?=#)/i)?.[0];
const imgBlob = await fetch(url).then((res) => res.blob());
this.downloadBlob(imgBlob, filename);
markdown = markdown.replace(img[0], (match) =>
match.replace(url, MARKDOWN_IMAGE_PATH + filename)
);
}
return markdown;
}
async downloadDocAll() {
const books = await this.getBooks();
for (const book of books) {
const {
id: bookId,
user: { login },
slug: bookSlug,
items_count,
name,
} = book;
const docs = await this.getDocs(bookId).then((docs) => {
return docs.filter((i) => i.type === "Doc");
});
console.log(`正在下载 ${name}, 共 ${docs.length} 篇文章`);
for (const doc of docs) {
const { slug, title } = doc;
try {
let markdown = await this.downloadDoc({ login, bookSlug, slug });
if (DOWNLOAD_IMAGE) {
markdown = await this.processMarkdownImage(markdown);
}
const markdownBlob = new Blob([markdown], { type: "text/plain" });
this.downloadBlob(markdownBlob, `${title}.md`);
} catch (err) {
console.log(err);
}
await this.sleep(1000 * Math.ceil(Math.random() * 10));
}
}
console.log("end");
}
}
const yuque = new YuqueMarkdownDownload();
yuque.downloadDocAll();
})();
@Celestial32085
Copy link

md+assets的方式保存图片也许会更方便

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment