yuque-dl 1.0.10 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli.js +1 -1
- package/dist/cjs/index-13483ea3.js +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/es/cli.js +1 -1
- package/dist/es/index-f024e870.js +1 -0
- package/dist/es/index.js +1 -1
- package/package.json +2 -2
- package/types/ProgressBar.d.ts +2 -2
- package/types/Summary.d.ts +24 -0
- package/types/index.d.ts +14 -1
- package/dist/cjs/index-b758b4ba.js +0 -1
- package/dist/es/index-7580521b.js +0 -1
- package/types/config.d.ts +0 -5
package/dist/cjs/cli.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("node:fs"),r=require("cac"),n=require("./index-
|
|
1
|
+
"use strict";var e=require("node:fs"),r=require("cac"),n=require("./index-13483ea3.js");require("node:fs/promises"),require("axios"),require("log4js"),require("progress"),require("rand-user-agent"),require("pull-md-img");const i=r.cac("yuque-dl"),{version:o}=JSON.parse(e.readFileSync(new URL("../../package.json","undefined"==typeof document?require("url").pathToFileURL(__filename).href:document.currentScript&&document.currentScript.src||new URL("cli.js",document.baseURI).href)).toString());i.command("<url>","request url").option("-d, --distDir <dir>","下载的目录 eg: -d download",{default:"download"}).action((async(e,r)=>{try{await n.main(e,r)}catch(e){n.logger.error(e.message||"unknown exception")}})),i.help(),i.version(o);try{i.parse()}catch(e){n.logger.error(e.message||"unknown exception"),process.exit(1)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("node:fs/promises"),t=require("axios"),r=require("log4js"),o=require("progress"),i=require("rand-user-agent"),s=require("pull-md-img");var n=(r.configure({appenders:{cheese:{type:"console",layout:{type:"pattern",pattern:"%[%c [%p]:%] %m%n"}}},categories:{default:{appenders:["cheese"],level:"trace"}}}),r.getLogger("yuque-dl"));class a{constructor(e,t){this.bookPath="",this.progressFilePath="",this.progressInfo=[],this.curr=0,this.total=0,this.isDownloadInterrupted=!1,this.bar=null,this.completePromise=null,this.bookPath=e,this.progressFilePath=`${e}/progress.json`,this.total=t}async init(){let e;this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.completePromise=new Promise((t=>{e=t})),this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,n.info("断点下载")),this.bar=new o("downloading [:bar] :rate/bps :percent :etas",{width:100,total:this.total,curr:0,callback(){e()}}),this.curr>0&&this.bar.tick(this.curr)}async getProgress(){let t=[];try{const r=await e.readFile(this.progressFilePath,{encoding:"utf8"});t=JSON.parse(r)}catch(r){r&&"ENOENT"===r.code&&await e.writeFile(this.progressFilePath,JSON.stringify(t),{encoding:"utf8"})}return t}async updateProgress(t,r){r&&(this.progressInfo.push(t),await e.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"})),this.curr=this.curr+1,this.bar&&this.bar?.tick()}}function l({browser:e="chrome",os:t="mac os",device:r="desktop"}){r=r.toLowerCase(),e=e.toLowerCase(),t=t.toLowerCase();let o=i(r,e,t);if("chrome"===e)for(;o.includes("Chrome-Lighthouse")||o.includes("Gener8")||o.includes("HeadlessChrome")||o.includes("SMTBot");)o=i(r,e,t);if("safari"===e)for(;o.includes("Applebot");)o=i(r,e,t);return o}class c{constructor(e){this.summaryInfo=e}async genFile(){const{bookName:t,bookDesc:r,bookPath:o,uuidMap:i}=this.summaryInfo;let s=`# ${t}\n\n`;r&&(s+=`> ${r}\n\n`);let a=s;const l=[];i.forEach((e=>{const t=e.toc,r=t.parent_uuid,o=this.findTree(l,r),i={text:t.title.replace(/[\\\/:\*\?"<>\|\n\r]/g,"_").replace(/\s/,""),id:t.uuid,level:1,type:""};"title"===t.type.toLocaleLowerCase()||""!==t.child_uuid?(i.type="title","boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,l.push(i))):(i.type="link",i.link=e.path,"boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,l.push(i)))})),a+=this.genSummaryContent(l,"");try{await e.writeFile(`${o}/SUMMARY.md`,a)}catch(e){n.error("Generate Summary Error")}}genSummaryContent(e,t){for(let r=0;r<e.length;r++){const o=e[r];if("title"===o.type)t+=`\n${"".padStart(o.level+1,"#")} ${o.text}\n\n`;else if("link"===o.type){const e=o.link?o.link.replace(/\s/g,"%20"):o.link;t+=`- [${o.text}](${e})\n`}Array.isArray(o.children)&&(t+=this.genSummaryContent(o.children,""))}return t}findIdItem(e,t){if(e.id===t)return e;if(e.children){const r=this.findTree(e.children,t);if(r)return r}return!1}findTree(e,t){if(!t)return!1;for(let r=0;r<e.length;r++){const o=this.findIdItem(e[r],t);if(o)return o}return!1}}function u(e){const r=/decodeURIComponent\(\"(.+)\"\)\);/m;return t.get(e,{headers:{"user-agent":l({browser:"chrome",device:"desktop"})}}).then((({data:e="",status:t})=>200===t?e:"")).then((e=>{const t=e.match(r)||"";if(!t[1])return{};const o=JSON.parse(decodeURIComponent(t[1]));if(!o.book)return{};return{bookId:o.book.id,bookSlug:o.book.slug,tocList:o.book.toc||[],bookName:o.book.name||"",bookDesc:o.book.description||""}}))}async function d(r){const{bookId:o,itemUrl:i,savePath:n,saveFilePath:a,uuid:c,articleUrl:u,articleTitle:d}=r;let h=`https://www.yuque.com/api/docs/${i}`;const p={book_id:String(o),merge_dynamic_data:String(!1),mode:"markdown"},g=new URLSearchParams(p).toString();h=`${h}?${g}`;let f=(await t.get(h,{headers:{"user-agent":l({browser:"chrome",device:"desktop"})}}).then((({data:e,status:t})=>{if(200===t){const t=e;if(!t||!t.data||!t.data.sourcecode)throw new Error(`download article Error: ${h}`);return t}throw new Error(`download article Error: ${h} http status ${t}`)})).catch((e=>{throw new Error(`download article Error: ${h} ${e.message}`)}))).data.sourcecode;try{f=await s.run(f,{dist:n,imgDir:`img/${c}`,isIgnoreConsole:!0})}catch(e){let t=`download article image Error: ${e.message}`;throw e.error&&e.url&&(t=`download article image Error ${e.url}: ${e.error?.message}`),new Error(t)}f=f.replace(/<br(\s?)\/>/gm,"\n"),d&&(f=`# ${d}\n\x3c!--page header--\x3e\n\n${f}\n\n`),u&&(f+=`\x3c!--page footer--\x3e\n- 原文: <${u}>`);try{return await e.writeFile(a,f),!0}catch(e){throw new Error(`download article Error ${u}: ${e.message}`)}}exports.downloadArticle=d,exports.getKnowledgeBaseInfo=u,exports.logger=n,exports.main=async function(t,r){const{bookId:o,tocList:i,bookName:s,bookDesc:l,bookSlug:h}=await u(t);if(!o)throw new Error("No found book id");if(!i||0===i.length)throw new Error("No found toc list");const p=`${r.distDir}/${o}`;await e.mkdir(p,{recursive:!0});const g=i.length,f=new a(p,g);if(await f.init(),f.curr===g)return void n.info("√ 已完成");const m=new Map;f.isDownloadInterrupted&&f.progressInfo.forEach((e=>{m.set(e.toc.uuid,e)}));const w=t.replace(new RegExp(`(.*?/${h}).*`),"$1");let y=0,b=0,$=[];for(let t=0;t<g;t++){const r=i[t];if("string"!=typeof r.type)continue;if(m.get(r.uuid))continue;const s=/[\\\/:\*\?"<>\|\n\r]/g;if("title"===r.type.toLocaleLowerCase()||""!==r.child_uuid){let t=r,o=[],i=[];for(;t;)o.unshift(t.title.replace(s,"_").replace(/\s/,"")),i.unshift(t.uuid),t=m.get(t.parent_uuid)?m.get(t.parent_uuid).toc:void 0;const n={path:o.join("/"),pathTitleList:o,pathIdList:i,toc:r};await e.mkdir(`${p}/${o.join("/")}`,{recursive:!0}),m.set(r.uuid,n),f.updateProgress(n,!0)}else if(r.url){b+=1;let e={path:"",pathTitleList:[],pathIdList:[]};m.get(r.parent_uuid)&&(e=m.get(r.parent_uuid));const t=r.title.replace(s,"_").replace(/\s/,""),i=[...e.pathTitleList,`${t}.md`],n=[...e.pathIdList,r.uuid],a={path:i.join("/"),pathTitleList:i,pathIdList:n,toc:r};let l=!0;try{await d({bookId:o,itemUrl:r.url,savePath:`${p}/${e.path}`,saveFilePath:`${p}/${a.path}`,uuid:r.uuid,articleUrl:`${w}/${r.url}`,articleTitle:r.title})}catch(e){l=!1,y+=1,$.push(a),f.bar?.interrupt(`✕ ${e.message}`)}m.set(r.uuid,a),f.updateProgress(a,l)}}if(await(f.completePromise?.finally((()=>console.log("")))),y>0){n.info(`本次执行总数${b}篇,✕ 失败${y}篇`);for(let e=0;e<$.length;e++)n.error(`✕ ${$[e].path}`);n.info("o(╥﹏╥)o 由于网络波动以上下载失败,请重新执行命令")}const k=new c({bookPath:p,bookName:s,bookDesc:l,uuidMap:m});await k.genFile(),n.info("√ 生成目录 SUMMARY.md"),f.curr!==g||n.info("√ 已完成")};
|
package/dist/cjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";require("node:fs/promises"),require("
|
|
1
|
+
"use strict";require("node:fs/promises"),require("axios");var e=require("./index-13483ea3.js");require("pull-md-img"),require("log4js"),require("progress"),require("rand-user-agent"),exports.downloadArticle=e.downloadArticle,exports.getKnowledgeBaseInfo=e.getKnowledgeBaseInfo,exports.main=e.main;
|
package/dist/es/cli.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as o}from"node:fs";import{cac as r}from"cac";import{m as e,l as t}from"./index-
|
|
1
|
+
import{readFileSync as o}from"node:fs";import{cac as r}from"cac";import{m as e,l as t}from"./index-f024e870.js";import"node:fs/promises";import"axios";import"log4js";import"progress";import"rand-user-agent";import"pull-md-img";const s=r("yuque-dl"),{version:i}=JSON.parse(o(new URL("../../package.json",import.meta.url)).toString());s.command("<url>","request url").option("-d, --distDir <dir>","下载的目录 eg: -d download",{default:"download"}).action((async(o,r)=>{try{await e(o,r)}catch(o){t.error(o.message||"unknown exception")}})),s.help(),s.version(i);try{s.parse()}catch(o){t.error(o.message||"unknown exception"),process.exit(1)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"node:fs/promises";import t from"axios";import r from"log4js";import o from"progress";import i from"rand-user-agent";import s from"pull-md-img";var n=(r.configure({appenders:{cheese:{type:"console",layout:{type:"pattern",pattern:"%[%c [%p]:%] %m%n"}}},categories:{default:{appenders:["cheese"],level:"trace"}}}),r.getLogger("yuque-dl"));class a{constructor(e,t){this.bookPath="",this.progressFilePath="",this.progressInfo=[],this.curr=0,this.total=0,this.isDownloadInterrupted=!1,this.bar=null,this.completePromise=null,this.bookPath=e,this.progressFilePath=`${e}/progress.json`,this.total=t}async init(){let e;this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.completePromise=new Promise((t=>{e=t})),this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,n.info("断点下载")),this.bar=new o("downloading [:bar] :rate/bps :percent :etas",{width:100,total:this.total,curr:0,callback(){e()}}),this.curr>0&&this.bar.tick(this.curr)}async getProgress(){let t=[];try{const r=await e.readFile(this.progressFilePath,{encoding:"utf8"});t=JSON.parse(r)}catch(r){r&&"ENOENT"===r.code&&await e.writeFile(this.progressFilePath,JSON.stringify(t),{encoding:"utf8"})}return t}async updateProgress(t,r){r&&(this.progressInfo.push(t),await e.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"})),this.curr=this.curr+1,this.bar&&this.bar?.tick()}}function l({browser:e="chrome",os:t="mac os",device:r="desktop"}){r=r.toLowerCase(),e=e.toLowerCase(),t=t.toLowerCase();let o=i(r,e,t);if("chrome"===e)for(;o.includes("Chrome-Lighthouse")||o.includes("Gener8")||o.includes("HeadlessChrome")||o.includes("SMTBot");)o=i(r,e,t);if("safari"===e)for(;o.includes("Applebot");)o=i(r,e,t);return o}class c{constructor(e){this.summaryInfo=e}async genFile(){const{bookName:t,bookDesc:r,bookPath:o,uuidMap:i}=this.summaryInfo;let s=`# ${t}\n\n`;r&&(s+=`> ${r}\n\n`);let a=s;const l=[];i.forEach((e=>{const t=e.toc,r=t.parent_uuid,o=this.findTree(l,r),i={text:t.title.replace(/[\\\/:\*\?"<>\|\n\r]/g,"_").replace(/\s/,""),id:t.uuid,level:1,type:""};"title"===t.type.toLocaleLowerCase()||""!==t.child_uuid?(i.type="title","boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,l.push(i))):(i.type="link",i.link=e.path,"boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,l.push(i)))})),a+=this.genSummaryContent(l,"");try{await e.writeFile(`${o}/SUMMARY.md`,a)}catch(e){n.error("Generate Summary Error")}}genSummaryContent(e,t){for(let r=0;r<e.length;r++){const o=e[r];if("title"===o.type)t+=`\n${"".padStart(o.level+1,"#")} ${o.text}\n\n`;else if("link"===o.type){const e=o.link?o.link.replace(/\s/g,"%20"):o.link;t+=`- [${o.text}](${e})\n`}Array.isArray(o.children)&&(t+=this.genSummaryContent(o.children,""))}return t}findIdItem(e,t){if(e.id===t)return e;if(e.children){const r=this.findTree(e.children,t);if(r)return r}return!1}findTree(e,t){if(!t)return!1;for(let r=0;r<e.length;r++){const o=this.findIdItem(e[r],t);if(o)return o}return!1}}function u(e){const r=/decodeURIComponent\(\"(.+)\"\)\);/m;return t.get(e,{headers:{"user-agent":l({browser:"chrome",device:"desktop"})}}).then((({data:e="",status:t})=>200===t?e:"")).then((e=>{const t=e.match(r)||"";if(!t[1])return{};const o=JSON.parse(decodeURIComponent(t[1]));if(!o.book)return{};return{bookId:o.book.id,bookSlug:o.book.slug,tocList:o.book.toc||[],bookName:o.book.name||"",bookDesc:o.book.description||""}}))}async function d(r){const{bookId:o,itemUrl:i,savePath:n,saveFilePath:a,uuid:c,articleUrl:u,articleTitle:d}=r;let h=`https://www.yuque.com/api/docs/${i}`;const p={book_id:String(o),merge_dynamic_data:String(!1),mode:"markdown"},g=new URLSearchParams(p).toString();h=`${h}?${g}`;let f=(await t.get(h,{headers:{"user-agent":l({browser:"chrome",device:"desktop"})}}).then((({data:e,status:t})=>{if(200===t){const t=e;if(!t||!t.data||!t.data.sourcecode)throw new Error(`download article Error: ${h}`);return t}throw new Error(`download article Error: ${h} http status ${t}`)})).catch((e=>{throw new Error(`download article Error: ${h} ${e.message}`)}))).data.sourcecode;try{f=await s.run(f,{dist:n,imgDir:`img/${c}`,isIgnoreConsole:!0})}catch(e){let t=`download article image Error: ${e.message}`;throw e.error&&e.url&&(t=`download article image Error ${e.url}: ${e.error?.message}`),new Error(t)}f=f.replace(/<br(\s?)\/>/gm,"\n"),d&&(f=`# ${d}\n\x3c!--page header--\x3e\n\n${f}\n\n`),u&&(f+=`\x3c!--page footer--\x3e\n- 原文: <${u}>`);try{return await e.writeFile(a,f),!0}catch(e){throw new Error(`download article Error ${u}: ${e.message}`)}}async function h(t,r){const{bookId:o,tocList:i,bookName:s,bookDesc:l,bookSlug:h}=await u(t);if(!o)throw new Error("No found book id");if(!i||0===i.length)throw new Error("No found toc list");const p=`${r.distDir}/${o}`;await e.mkdir(p,{recursive:!0});const g=i.length,f=new a(p,g);if(await f.init(),f.curr===g)return void n.info("√ 已完成");const m=new Map;f.isDownloadInterrupted&&f.progressInfo.forEach((e=>{m.set(e.toc.uuid,e)}));const w=t.replace(new RegExp(`(.*?/${h}).*`),"$1");let y=0,b=0,$=[];for(let t=0;t<g;t++){const r=i[t];if("string"!=typeof r.type)continue;if(m.get(r.uuid))continue;const s=/[\\\/:\*\?"<>\|\n\r]/g;if("title"===r.type.toLocaleLowerCase()||""!==r.child_uuid){let t=r,o=[],i=[];for(;t;)o.unshift(t.title.replace(s,"_").replace(/\s/,"")),i.unshift(t.uuid),t=m.get(t.parent_uuid)?m.get(t.parent_uuid).toc:void 0;const n={path:o.join("/"),pathTitleList:o,pathIdList:i,toc:r};await e.mkdir(`${p}/${o.join("/")}`,{recursive:!0}),m.set(r.uuid,n),f.updateProgress(n,!0)}else if(r.url){b+=1;let e={path:"",pathTitleList:[],pathIdList:[]};m.get(r.parent_uuid)&&(e=m.get(r.parent_uuid));const t=r.title.replace(s,"_").replace(/\s/,""),i=[...e.pathTitleList,`${t}.md`],n=[...e.pathIdList,r.uuid],a={path:i.join("/"),pathTitleList:i,pathIdList:n,toc:r};let l=!0;try{await d({bookId:o,itemUrl:r.url,savePath:`${p}/${e.path}`,saveFilePath:`${p}/${a.path}`,uuid:r.uuid,articleUrl:`${w}/${r.url}`,articleTitle:r.title})}catch(e){l=!1,y+=1,$.push(a),f.bar?.interrupt(`✕ ${e.message}`)}m.set(r.uuid,a),f.updateProgress(a,l)}}if(await(f.completePromise?.finally((()=>console.log("")))),y>0){n.info(`本次执行总数${b}篇,✕ 失败${y}篇`);for(let e=0;e<$.length;e++)n.error(`✕ ${$[e].path}`);n.info("o(╥﹏╥)o 由于网络波动以上下载失败,请重新执行命令")}const k=new c({bookPath:p,bookName:s,bookDesc:l,uuidMap:m});await k.genFile(),n.info("√ 生成目录 SUMMARY.md"),f.curr!==g||n.info("√ 已完成")}export{d,u as g,n as l,h as m};
|
package/dist/es/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"node:fs/promises";import"
|
|
1
|
+
import"node:fs/promises";import"axios";export{d as downloadArticle,g as getKnowledgeBaseInfo,m as main}from"./index-f024e870.js";import"pull-md-img";import"log4js";import"progress";import"rand-user-agent";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yuque-dl",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "yuque 知识库下载",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"cac": "^6.7.14",
|
|
59
59
|
"log4js": "^6.9.1",
|
|
60
60
|
"progress": "^2.0.3",
|
|
61
|
-
"pull-md-img": "^0.0.
|
|
61
|
+
"pull-md-img": "^0.0.22",
|
|
62
62
|
"rand-user-agent": "1.0.109"
|
|
63
63
|
},
|
|
64
64
|
"engines": {
|
package/types/ProgressBar.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface IProgressItem {
|
|
|
6
6
|
pathIdList: string[];
|
|
7
7
|
pathTitleList: string[];
|
|
8
8
|
}
|
|
9
|
-
export type IProgress = IProgressItem[];
|
|
9
|
+
export declare type IProgress = IProgressItem[];
|
|
10
10
|
export default class ProgressBar {
|
|
11
11
|
bookPath: string;
|
|
12
12
|
progressFilePath: string;
|
|
@@ -19,5 +19,5 @@ export default class ProgressBar {
|
|
|
19
19
|
constructor(bookPath: string, total: number);
|
|
20
20
|
init(): Promise<void>;
|
|
21
21
|
getProgress(): Promise<IProgress>;
|
|
22
|
-
updateProgress(progressItem: IProgressItem): Promise<void>;
|
|
22
|
+
updateProgress(progressItem: IProgressItem, isSuccess: boolean): Promise<void>;
|
|
23
23
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IProgressItem } from './ProgressBar';
|
|
2
|
+
interface IGenSummaryFile {
|
|
3
|
+
bookPath: string;
|
|
4
|
+
bookName?: string;
|
|
5
|
+
bookDesc?: string;
|
|
6
|
+
uuidMap: Map<string, IProgressItem>;
|
|
7
|
+
}
|
|
8
|
+
interface SummaryItem {
|
|
9
|
+
id: string;
|
|
10
|
+
children?: SummaryItem[];
|
|
11
|
+
type: string;
|
|
12
|
+
text: string;
|
|
13
|
+
level: number;
|
|
14
|
+
link?: string;
|
|
15
|
+
}
|
|
16
|
+
export default class Summary {
|
|
17
|
+
summaryInfo: IGenSummaryFile;
|
|
18
|
+
constructor(summaryInfo: IGenSummaryFile);
|
|
19
|
+
genFile(): Promise<void>;
|
|
20
|
+
genSummaryContent(summary: SummaryItem[], summaryContent: string): string;
|
|
21
|
+
findIdItem(node: SummaryItem, id: string): boolean | SummaryItem;
|
|
22
|
+
findTree(tree: SummaryItem[], id: string): SummaryItem | boolean;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
package/types/index.d.ts
CHANGED
|
@@ -2,10 +2,23 @@ import type { IOptions } from './cli';
|
|
|
2
2
|
import type { KnowledgeBase } from './types/KnowledgeBaseResponse';
|
|
3
3
|
interface IKnowledgeBaseInfo {
|
|
4
4
|
bookId?: number;
|
|
5
|
+
bookSlug?: string;
|
|
5
6
|
tocList?: KnowledgeBase.Toc[];
|
|
6
7
|
bookName?: string;
|
|
7
8
|
bookDesc?: string;
|
|
8
9
|
}
|
|
10
|
+
interface IDownloadArticleParams {
|
|
11
|
+
bookId: number;
|
|
12
|
+
itemUrl: string;
|
|
13
|
+
savePath: string;
|
|
14
|
+
saveFilePath: string;
|
|
15
|
+
uuid: string;
|
|
16
|
+
articleTitle: string;
|
|
17
|
+
articleUrl: string;
|
|
18
|
+
}
|
|
19
|
+
/** 获取知识库数据信息 */
|
|
9
20
|
declare function getKnowledgeBaseInfo(url: string): Promise<IKnowledgeBaseInfo>;
|
|
21
|
+
/** 下载单篇文章 */
|
|
22
|
+
declare function downloadArticle(params: IDownloadArticleParams): Promise<boolean>;
|
|
10
23
|
declare function main(url: string, options: IOptions): Promise<void>;
|
|
11
|
-
export { getKnowledgeBaseInfo, main };
|
|
24
|
+
export { getKnowledgeBaseInfo, downloadArticle, main };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";var e=require("node:fs/promises"),t=require("node:path"),r=require("axios"),i=require("log4js"),o=require("progress"),s=require("rand-user-agent"),n=require("pull-md-img"),a={knowledgeBaseReg:/decodeURIComponent\(\"(.+)\"\)\);/m,dist:"./download"};var l=(i.configure({appenders:{cheese:{type:"console",layout:{type:"pattern",pattern:"%[%c [%p]:%] %m%n"}}},categories:{default:{appenders:["cheese"],level:"trace"}}}),i.getLogger("yuque-dl"));class c{constructor(e,t){this.bookPath="",this.progressFilePath="",this.progressInfo=[],this.curr=0,this.total=0,this.isDownloadInterrupted=!1,this.bar=null,this.completePromise=null,this.bookPath=e,this.progressFilePath=`${e}/progress.json`,this.total=t}async init(){let e;this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.completePromise=new Promise((t=>{e=t})),this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,l.info("断点下载")),this.bar=new o("[:bar] :rate/bps :percent :etas",{total:this.total,curr:this.curr,callback(){e()}})}async getProgress(){let t=[];try{const r=await e.readFile(this.progressFilePath,{encoding:"utf8"});t=JSON.parse(r)}catch(r){r&&"ENOENT"===r.code&&await e.writeFile(this.progressFilePath,JSON.stringify(t),{encoding:"utf8"})}return t}async updateProgress(t){this.progressInfo.push(t),await e.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"}),this.curr=this.curr+1,this.bar&&this.bar?.tick()}}function u({browser:e="chrome",os:t="mac os",device:r="desktop"}){r=r.toLowerCase(),e=e.toLowerCase(),t=t.toLowerCase();let i=s(r,e,t);if("chrome"===e)for(;i.includes("Chrome-Lighthouse")||i.includes("Gener8")||i.includes("HeadlessChrome")||i.includes("SMTBot");)i=s(r,e,t);if("safari"===e)for(;i.includes("Applebot");)i=s(r,e,t);return i}function d(e){return r.get(e,{headers:{"user-agent":u({browser:"chrome",device:"desktop"})}}).then((({data:e="",status:t})=>200===t?e:"")).then((e=>{const t=e.match(a.knowledgeBaseReg)||"";if(!t[1])return{};const r=JSON.parse(decodeURIComponent(t[1]));return{bookId:r.book.id,tocList:r.book.toc||[],bookName:r.book.name||"",bookDesc:r.book.description||""}}))}async function h(t){const{bookId:i,itemUrl:o,savePath:s,saveFilePath:a,uuid:c,articleUrl:d,articleTitle:h}=t,p=`https://www.yuque.com/api/docs/${o}`,g=await r.get(p,{headers:{"user-agent":u({browser:"chrome",device:"desktop"})},params:{book_id:i,merge_dynamic_data:!1,mode:"markdown"}}).then((({data:e,status:t})=>200===t?e:(l.error(`download article error: ${p} http status ${t}`),null)));if(!g||!g.data||!g.data.sourcecode)return!1;let f=g.data.sourcecode;try{f=await n.run(f,{dist:s,imgDir:`img/${c}`,isIgnoreConsole:!0})}catch(e){return l.error(`download article img Error (api: ${p})`),!1}f=f.replace(/<br(\s?)\/>/gm,"\n"),h&&(f=`# ${h}\n\x3c!--page header--\x3e\n\n${f}\n\n`),d&&(f+=`\x3c!--page footer--\x3e\n- 原文: <${d}>`);try{return await e.writeFile(a,f),!0}catch(e){return l.error(`download article write file Error (api: ${p})`),!1}}function p(e,t){for(let r=0;r<e.length;r++){const i=e[r];if("title"===i.type)t+=`\n${"".padStart(i.level+1,"#")} ${i.text}\n\n`;else if("link"===i.type){const e=i.link?i.link.replace(/\s/g,"%20"):i.link;t+=`- [${i.text}](${e})\n`}Array.isArray(i.children)&&(t+=p(i.children,""))}return t}function g(e,t){if(e.id===t)return e;if(e.children){const r=f(e.children,t);if(r)return r}return!1}function f(e,t){if(!t)return!1;for(let r=0;r<e.length;r++){const i=g(e[r],t);if(i)return i}return!1}exports.getKnowledgeBaseInfo=d,exports.logger=l,exports.main=async function(r,i){const{bookId:o,tocList:s,bookName:n,bookDesc:a}=await d(r);if(!o)throw new Error("No found book id");if(!s||0===s.length)throw new Error("No found toc list");const u=`${i.distDir}/${o}`;await e.mkdir(u,{recursive:!0});const g=s.length,w=new c(u,g);if(await w.init(),w.curr===g)return void l.info("√ 已完成");const m=new Map;w.isDownloadInterrupted&&w.progressInfo.forEach((e=>{m.set(e.toc.uuid,e)}));const k=t.parse(r).dir;let y=0,b=0;for(let t=0;t<g;t++){const r=s[t];if("string"!=typeof r.type)continue;if(m.get(r.uuid))continue;const i=/[\\\/:\*\?"<>\|\n\r]/g;if("title"===r.type.toLocaleLowerCase()||""!==r.child_uuid){let t=r,o=[],s=[];for(;t;)o.unshift(t.title.replace(i,"_")),s.unshift(t.uuid),t=m.get(t.parent_uuid)?m.get(t.parent_uuid).toc:void 0;const n={path:o.join("/"),pathTitleList:o,pathIdList:s,toc:r};await e.mkdir(`${u}/${o.join("/")}`,{recursive:!0}),m.set(r.uuid,n),w.updateProgress(n)}else if(r.url){b+=1;let e={path:"",pathTitleList:[],pathIdList:[]};m.get(r.parent_uuid)&&(e=m.get(r.parent_uuid));const t=r.title.replace(i,"_"),s=[...e.pathTitleList,`${t}.md`],n=[...e.pathIdList,r.uuid],a={path:s.join("/"),pathTitleList:s,pathIdList:n,toc:r};await h({bookId:o,itemUrl:r.url,savePath:`${u}/${e.path}`,saveFilePath:`${u}/${a.path}`,uuid:r.uuid,articleUrl:`${k}/${r.url}`,articleTitle:r.title})?(m.set(r.uuid,a),w.updateProgress(a)):y+=1}}await w.completePromise,l.info(`本次执行总数${b}篇,✕ 失败${y}篇`),l.info("生成目录 SUMMARY.md"),await async function(t){const{bookName:r,bookDesc:i,bookPath:o,uuidMap:s}=t,n=`# ${r}\n\n > ${i}\n\n`;let a=n;const c=[];s.forEach((e=>{const t=e.toc,r=t.parent_uuid,i=f(c,r);"title"===t.type.toLocaleLowerCase()||""!==t.child_uuid?"boolean"!=typeof i?(Array.isArray(i.children)||(i.children=[]),i.children.push({id:t.uuid,type:"title",level:i.level+1,text:t.title})):c.push({id:t.uuid,type:"title",text:t.title,level:1}):"boolean"!=typeof i?(Array.isArray(i.children)||(i.children=[]),i.children.push({id:t.uuid,type:"link",level:i.level+1,link:e.path,text:t.title})):c.push({id:t.uuid,type:"link",text:t.title,link:e.path,level:1})}));let u=p(c,"");a+=u;try{await e.writeFile(`${o}/SUMMARY.md`,a)}catch(e){l.error("Generate Summary Error")}}({bookPath:u,bookName:n,bookDesc:a,uuidMap:m}),w.curr!==g||l.info("√ 已完成")};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import t from"node:fs/promises";import e from"node:path";import r from"axios";import i from"log4js";import o from"progress";import s from"rand-user-agent";import a from"pull-md-img";var n={knowledgeBaseReg:/decodeURIComponent\(\"(.+)\"\)\);/m,dist:"./download"};var l=(i.configure({appenders:{cheese:{type:"console",layout:{type:"pattern",pattern:"%[%c [%p]:%] %m%n"}}},categories:{default:{appenders:["cheese"],level:"trace"}}}),i.getLogger("yuque-dl"));class c{constructor(t,e){this.bookPath="",this.progressFilePath="",this.progressInfo=[],this.curr=0,this.total=0,this.isDownloadInterrupted=!1,this.bar=null,this.completePromise=null,this.bookPath=t,this.progressFilePath=`${t}/progress.json`,this.total=e}async init(){let t;this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.completePromise=new Promise((e=>{t=e})),this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,l.info("断点下载")),this.bar=new o("[:bar] :rate/bps :percent :etas",{total:this.total,curr:this.curr,callback(){t()}})}async getProgress(){let e=[];try{const r=await t.readFile(this.progressFilePath,{encoding:"utf8"});e=JSON.parse(r)}catch(r){r&&"ENOENT"===r.code&&await t.writeFile(this.progressFilePath,JSON.stringify(e),{encoding:"utf8"})}return e}async updateProgress(e){this.progressInfo.push(e),await t.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"}),this.curr=this.curr+1,this.bar&&this.bar?.tick()}}function u({browser:t="chrome",os:e="mac os",device:r="desktop"}){r=r.toLowerCase(),t=t.toLowerCase(),e=e.toLowerCase();let i=s(r,t,e);if("chrome"===t)for(;i.includes("Chrome-Lighthouse")||i.includes("Gener8")||i.includes("HeadlessChrome")||i.includes("SMTBot");)i=s(r,t,e);if("safari"===t)for(;i.includes("Applebot");)i=s(r,t,e);return i}function d(t){return r.get(t,{headers:{"user-agent":u({browser:"chrome",device:"desktop"})}}).then((({data:t="",status:e})=>200===e?t:"")).then((t=>{const e=t.match(n.knowledgeBaseReg)||"";if(!e[1])return{};const r=JSON.parse(decodeURIComponent(e[1]));return{bookId:r.book.id,tocList:r.book.toc||[],bookName:r.book.name||"",bookDesc:r.book.description||""}}))}async function h(r,i){const{bookId:o,tocList:s,bookName:a,bookDesc:n}=await d(r);if(!o)throw new Error("No found book id");if(!s||0===s.length)throw new Error("No found toc list");const u=`${i.distDir}/${o}`;await t.mkdir(u,{recursive:!0});const h=s.length,g=new c(u,h);if(await g.init(),g.curr===h)return void l.info("√ 已完成");const w=new Map;g.isDownloadInterrupted&&g.progressInfo.forEach((t=>{w.set(t.toc.uuid,t)}));const k=e.parse(r).dir;let y=0,b=0;for(let e=0;e<h;e++){const r=s[e];if("string"!=typeof r.type)continue;if(w.get(r.uuid))continue;const i=/[\\\/:\*\?"<>\|\n\r]/g;if("title"===r.type.toLocaleLowerCase()||""!==r.child_uuid){let e=r,o=[],s=[];for(;e;)o.unshift(e.title.replace(i,"_")),s.unshift(e.uuid),e=w.get(e.parent_uuid)?w.get(e.parent_uuid).toc:void 0;const a={path:o.join("/"),pathTitleList:o,pathIdList:s,toc:r};await t.mkdir(`${u}/${o.join("/")}`,{recursive:!0}),w.set(r.uuid,a),g.updateProgress(a)}else if(r.url){b+=1;let t={path:"",pathTitleList:[],pathIdList:[]};w.get(r.parent_uuid)&&(t=w.get(r.parent_uuid));const e=r.title.replace(i,"_"),s=[...t.pathTitleList,`${e}.md`],a=[...t.pathIdList,r.uuid],n={path:s.join("/"),pathTitleList:s,pathIdList:a,toc:r};await p({bookId:o,itemUrl:r.url,savePath:`${u}/${t.path}`,saveFilePath:`${u}/${n.path}`,uuid:r.uuid,articleUrl:`${k}/${r.url}`,articleTitle:r.title})?(w.set(r.uuid,n),g.updateProgress(n)):y+=1}}await g.completePromise,l.info(`本次执行总数${b}篇,✕ 失败${y}篇`),l.info("生成目录 SUMMARY.md"),await async function(e){const{bookName:r,bookDesc:i,bookPath:o,uuidMap:s}=e,a=`# ${r}\n\n > ${i}\n\n`;let n=a;const c=[];s.forEach((t=>{const e=t.toc,r=e.parent_uuid,i=m(c,r);"title"===e.type.toLocaleLowerCase()||""!==e.child_uuid?"boolean"!=typeof i?(Array.isArray(i.children)||(i.children=[]),i.children.push({id:e.uuid,type:"title",level:i.level+1,text:e.title})):c.push({id:e.uuid,type:"title",text:e.title,level:1}):"boolean"!=typeof i?(Array.isArray(i.children)||(i.children=[]),i.children.push({id:e.uuid,type:"link",level:i.level+1,link:t.path,text:e.title})):c.push({id:e.uuid,type:"link",text:e.title,link:t.path,level:1})}));let u=f(c,"");n+=u;try{await t.writeFile(`${o}/SUMMARY.md`,n)}catch(t){l.error("Generate Summary Error")}}({bookPath:u,bookName:a,bookDesc:n,uuidMap:w}),g.curr!==h||l.info("√ 已完成")}async function p(e){const{bookId:i,itemUrl:o,savePath:s,saveFilePath:n,uuid:c,articleUrl:d,articleTitle:h}=e,p=`https://www.yuque.com/api/docs/${o}`,f=await r.get(p,{headers:{"user-agent":u({browser:"chrome",device:"desktop"})},params:{book_id:i,merge_dynamic_data:!1,mode:"markdown"}}).then((({data:t,status:e})=>200===e?t:(l.error(`download article error: ${p} http status ${e}`),null)));if(!f||!f.data||!f.data.sourcecode)return!1;let g=f.data.sourcecode;try{g=await a.run(g,{dist:s,imgDir:`img/${c}`,isIgnoreConsole:!0})}catch(t){return l.error(`download article img Error (api: ${p})`),!1}g=g.replace(/<br(\s?)\/>/gm,"\n"),h&&(g=`# ${h}\n\x3c!--page header--\x3e\n\n${g}\n\n`),d&&(g+=`\x3c!--page footer--\x3e\n- 原文: <${d}>`);try{return await t.writeFile(n,g),!0}catch(t){return l.error(`download article write file Error (api: ${p})`),!1}}function f(t,e){for(let r=0;r<t.length;r++){const i=t[r];if("title"===i.type)e+=`\n${"".padStart(i.level+1,"#")} ${i.text}\n\n`;else if("link"===i.type){const t=i.link?i.link.replace(/\s/g,"%20"):i.link;e+=`- [${i.text}](${t})\n`}Array.isArray(i.children)&&(e+=f(i.children,""))}return e}function g(t,e){if(t.id===e)return t;if(t.children){const r=m(t.children,e);if(r)return r}return!1}function m(t,e){if(!e)return!1;for(let r=0;r<t.length;r++){const i=g(t[r],e);if(i)return i}return!1}export{d as g,l,h as m};
|