yuque-dl 1.0.20 → 1.0.22
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-fe7237f7.js +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/es/cli.js +1 -1
- package/dist/es/index-573d9cde.js +1 -0
- package/dist/es/index.js +1 -1
- package/package.json +2 -2
- package/types/ProgressBar.d.ts +1 -1
- package/types/api.d.ts +25 -0
- package/types/constant.d.ts +19 -0
- package/types/index.d.ts +1 -11
- package/dist/cjs/index-8d8db60d.js +0 -1
- package/dist/es/index-7b2fb7ac.js +0 -1
package/dist/cjs/cli.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("node:fs"),r=require("cac"),o=require("./index-
|
|
1
|
+
"use strict";var e=require("node:fs"),r=require("cac"),o=require("./index-fe7237f7.js");require("node:fs/promises"),require("pull-md-img"),require("ora"),require("cli-progress"),require("log4js"),require("axios"),require("rand-user-agent");const i=r.cac("yuque-dl"),{version:n}=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>","语雀知识库url").option("-d, --distDir <dir>","下载的目录 eg: -d download",{default:"download"}).option("-i, --ignoreImg","忽略图片不下载",{default:!1}).option("-t, --token <token>",'语雀的cookie "_yuque_session"').action((async(e,r)=>{try{await o.main(e,r)}catch(e){o.logger.error(e.message||"unknown exception")}})),i.help(),i.version(n);try{i.parse()}catch(e){o.logger.error(e.message||"unknown exception"),process.exit(1)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("node:fs/promises"),t=require("pull-md-img"),r=require("ora"),o=require("cli-progress"),i=require("log4js"),s=require("axios"),n=require("rand-user-agent");var a,c,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 u{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(){this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.curr!==this.total&&(this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,l.info("根据上次数据继续断点下载")),this.bar=new o.SingleBar({format:"Download [{bar}] {percentage}% | {value}/{total}"},o.Presets.legacy),this.bar.start(this.total,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){this.curr=this.curr+1,r&&(this.progressInfo.push(t),await e.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"})),this.bar&&(this.bar.update(this.curr),this.curr>=this.total&&(this.bar.stop(),console.log("")))}pause(){this.bar&&this.bar.stop()}continue(){this.clearLine(2),this.bar?.start(this.total,this.curr)}clearLine(e){if(!(e<=0)){process.stderr.cursorTo(0);for(let t=0;t<e;t++)process.stderr.moveCursor(0,-1),process.stderr.clearLine(1)}}}class d{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 n=s;const a=[];i.forEach((e=>{const t=e.toc,r=t.parent_uuid,o=this.findTree(a,r),i={text:t.title.replace(/[\\\/:\*\?"<>\|\n\r]/g,"_").replace(/\s/,""),id:t.uuid,level:1,type:""},s=t.type.toLocaleLowerCase();"title"===s||""!==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,a.push(i))):(i.type="link",i.link="link"===s?e.toc.url:e.path,"boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,a.push(i)))})),n+=this.genSummaryContent(a,"");try{await e.writeFile(`${o}/SUMMARY.md`,n)}catch(e){l.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(e){e.TITLE="title",e.LINK="link",e.DOC="doc"}(a||(a={})),function(e){e.BOARD="board",e.TABLE="table",e.SHEET="sheet",e.DOC="doc"}(c||(c={}));const h=new Map([[c.BOARD,"画板类型"],[c.TABLE,"数据表类型"],[c.SHEET,"表格类型"],[c.DOC,"文档类型"]]);function p({browser:e="chrome",os:t="mac os",device:r="desktop"}){r=r.toLowerCase(),e=e.toLowerCase(),t=t.toLowerCase();let o=n(r,e,t);if("chrome"===e)for(;o.includes("Chrome-Lighthouse")||o.includes("Gener8")||o.includes("HeadlessChrome")||o.includes("SMTBot");)o=n(r,e,t);if("safari"===e)for(;o.includes("Applebot");)o=n(r,e,t);return o}function g(e){const t={"user-agent":p({browser:"chrome",device:"desktop"})};return e&&(t.cookie=`_yuque_session=${e}`),t}const f=e=>{const{articleUrl:t,bookId:r,token:o}=e;let i=`https://www.yuque.com/api/docs/${t}`;const n={book_id:String(r),merge_dynamic_data:String(!1),mode:"markdown"},a=new URLSearchParams(n).toString();return i=`${i}?${a}`,s.get(i,{headers:g(o)}).then((({data:e,status:t})=>({apiUrl:i,httpStatus:t,response:e})))};async function w(o,i,s){const{bookId:n,itemUrl:a,savePath:l,saveFilePath:u,uuid:d,articleUrl:p,articleTitle:g,ignoreImg:w}=o,{httpStatus:m,apiUrl:b,response:$}=await f({articleUrl:a,bookId:n,token:s}),k=$?.data?.type?.toLocaleLowerCase();if([c.BOARD,c.SHEET,c.TABLE].includes(k)){const e=h.get(k);throw new Error(`download article Error: 暂不支持“${e}”的文档`)}if("string"!=typeof $?.data?.sourcecode)throw new Error(`download article Error: ${b}, http status ${m}`);let y=$.data.sourcecode;if(!w){i.pause(),console.log("");const e=r({text:`下载 "${g}" 的图片中...`});e.start();try{y=await t.run(y,{dist:l,imgDir:`./img/${d}`,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)}finally{e.stop(),i.continue()}}y=y.replace(/<br(\s?)\/>/gm,"\n"),g&&(y=`# ${g}\n\x3c!--page header--\x3e\n\n${y}\n\n`),p&&(y+=`\x3c!--page footer--\x3e\n- 原文: <${p}>`);try{return await e.writeFile(u,y),!0}catch(e){throw new Error(`download article Error ${p}: ${e.message}`)}}function m(e){if(!e)return"";return e.replace(/[\\/:*?"<>|\n\r]/g,"_").replace(/\s/g,"")}exports.downloadArticle=w,exports.logger=l,exports.main=async function(t,r){const{bookId:o,tocList:i,bookName:n,bookDesc:c,bookSlug:h}=await((e,t)=>{const r=/decodeURIComponent\("(.+)"\)\);/m;return s.get(e,{headers:g(t)}).then((({data:e="",status:t})=>200===t?e:"")).then((e=>{const t=r.exec(e)??"";if(!t[1])return{};const o=JSON.parse(decodeURIComponent(t[1]));return o.book?{bookId:o.book.id,bookSlug:o.book.slug,tocList:o.book.toc||[],bookName:o.book.name||"",bookDesc:o.book.description||""}:{}}))})(t,r.token);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}/${n?m(n):o}`;await e.mkdir(p,{recursive:!0});const f=i.length,b=new u(p,f);if(await b.init(),b.curr===f)return b.bar&&b.bar.stop(),void l.info(`√ 已完成: ${process.cwd()}/${p}`);const $=new Map;b.isDownloadInterrupted&&b.progressInfo.forEach((e=>{$.set(e.toc.uuid,e)}));const k=t.replace(new RegExp(`(.*?/${h}).*`),"$1");await async function(t){const{articleUrlPrefix:r,total:o,uuidMap:i,tocList:s,bookPath:n,bookId:c,progressBar:u,options:d}=t;let h=0,p=0,g=0,f=[],b=[];for(let t=0;t<o;t++){const o=s[t];if("string"!=typeof o.type)continue;if(i.get(o.uuid))continue;const l=o.type.toLocaleLowerCase();if(l===a.TITLE||""!==o.child_uuid||l===a.LINK){let t=o,r=[],s=[];for(;t;)r.unshift(m(t.title)),s.unshift(t.uuid),t=i.get(t.parent_uuid)?i.get(t.parent_uuid).toc:void 0;const c={path:r.join("/"),pathTitleList:r,pathIdList:s,toc:o};l===a.LINK?(g+=1,b.push(c)):await e.mkdir(`${n}/${r.join("/")}`,{recursive:!0}),i.set(o.uuid,c),await u.updateProgress(c,l!==a.LINK)}else if(o.url){p+=1;let e={path:"",pathTitleList:[],pathIdList:[]};i.get(o.parent_uuid)&&(e=i.get(o.parent_uuid));const t=m(o.title),s=[...e.pathTitleList,`${t}.md`],a=[...e.pathIdList,o.uuid],l={path:s.join("/"),pathTitleList:s,pathIdList:a,toc:o};let g=!0;const b=`${r}/${o.url}`;try{await w({bookId:c,itemUrl:o.url,savePath:`${n}/${e.path}`,saveFilePath:`${n}/${l.path}`,uuid:o.uuid,articleUrl:b,articleTitle:o.title,ignoreImg:d.ignoreImg},u,d.token)}catch(e){g=!1,h+=1,f.push({articleUrl:b,errItem:l,errMsg:e.message,err:e})}i.set(o.uuid,l),await u.updateProgress(l,g)}}if(g>0){l.warn("该知识库存在以下外链文章");for(const e of b)l.warn(`———— ✕ ${e.path} ${e.toc.url}`)}if(h>0){l.error(`本次执行总数${p}篇,✕ 失败${h}篇`);for(const e of f)l.error(`${e.errItem.path} ———— ${e.articleUrl}`),l.error(`———— ✕ ${e.errMsg}`);l.error("o(╥﹏╥)o 由于网络波动或链接失效以上下载失败,可重新执行命令重试(PS:不会影响已下载成功的数据)")}}({articleUrlPrefix:k,total:f,uuidMap:$,tocList:i,bookPath:p,bookId:o,progressBar:b,options:r});const y=new d({bookPath:p,bookName:n,bookDesc:c,uuidMap:$});await y.genFile();const I=process.cwd();l.info(`√ 生成目录 ${I}/${p}/SUMMARY.md`),b.curr===f&&l.info(`√ 已完成: ${I}/${p}`),process.exit(0)};
|
package/dist/cjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";require("node:fs/promises"),require("
|
|
1
|
+
"use strict";require("node:fs/promises"),require("pull-md-img"),require("ora");var r=require("./index-fe7237f7.js");require("cli-progress"),require("log4js"),require("axios"),require("rand-user-agent"),exports.downloadArticle=r.downloadArticle,exports.main=r.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 i}from"./index-
|
|
1
|
+
import{readFileSync as o}from"node:fs";import{cac as r}from"cac";import{m as e,l as i}from"./index-573d9cde.js";import"node:fs/promises";import"pull-md-img";import"ora";import"cli-progress";import"log4js";import"axios";import"rand-user-agent";const t=r("yuque-dl"),{version:n}=JSON.parse(o(new URL("../../package.json",import.meta.url)).toString());t.command("<url>","语雀知识库url").option("-d, --distDir <dir>","下载的目录 eg: -d download",{default:"download"}).option("-i, --ignoreImg","忽略图片不下载",{default:!1}).option("-t, --token <token>",'语雀的cookie "_yuque_session"').action((async(o,r)=>{try{await e(o,r)}catch(o){i.error(o.message||"unknown exception")}})),t.help(),t.version(n);try{t.parse()}catch(o){i.error(o.message||"unknown exception"),process.exit(1)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import t,{writeFile as e,mkdir as r}from"node:fs/promises";import o from"pull-md-img";import i from"ora";import s from"cli-progress";import n from"log4js";import a from"axios";import c from"rand-user-agent";var l,u,h=(n.configure({appenders:{cheese:{type:"console",layout:{type:"pattern",pattern:"%[%c [%p]:%] %m%n"}}},categories:{default:{appenders:["cheese"],level:"trace"}}}),n.getLogger("yuque-dl"));class d{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(){this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.curr!==this.total&&(this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,h.info("根据上次数据继续断点下载")),this.bar=new s.SingleBar({format:"Download [{bar}] {percentage}% | {value}/{total}"},s.Presets.legacy),this.bar.start(this.total,this.curr))}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,r){this.curr=this.curr+1,r&&(this.progressInfo.push(e),await t.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"})),this.bar&&(this.bar.update(this.curr),this.curr>=this.total&&(this.bar.stop(),console.log("")))}pause(){this.bar&&this.bar.stop()}continue(){this.clearLine(2),this.bar?.start(this.total,this.curr)}clearLine(t){if(!(t<=0)){process.stderr.cursorTo(0);for(let e=0;e<t;e++)process.stderr.moveCursor(0,-1),process.stderr.clearLine(1)}}}class p{constructor(t){this.summaryInfo=t}async genFile(){const{bookName:e,bookDesc:r,bookPath:o,uuidMap:i}=this.summaryInfo;let s=`# ${e}\n\n`;r&&(s+=`> ${r}\n\n`);let n=s;const a=[];i.forEach((t=>{const e=t.toc,r=e.parent_uuid,o=this.findTree(a,r),i={text:e.title.replace(/[\\\/:\*\?"<>\|\n\r]/g,"_").replace(/\s/,""),id:e.uuid,level:1,type:""},s=e.type.toLocaleLowerCase();"title"===s||""!==e.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,a.push(i))):(i.type="link",i.link="link"===s?t.toc.url:t.path,"boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,a.push(i)))})),n+=this.genSummaryContent(a,"");try{await t.writeFile(`${o}/SUMMARY.md`,n)}catch(t){h.error("Generate Summary Error")}}genSummaryContent(t,e){for(let r=0;r<t.length;r++){const o=t[r];if("title"===o.type)e+=`\n${"".padStart(o.level+1,"#")} ${o.text}\n\n`;else if("link"===o.type){const t=o.link?o.link.replace(/\s/g,"%20"):o.link;e+=`- [${o.text}](${t})\n`}Array.isArray(o.children)&&(e+=this.genSummaryContent(o.children,""))}return e}findIdItem(t,e){if(t.id===e)return t;if(t.children){const r=this.findTree(t.children,e);if(r)return r}return!1}findTree(t,e){if(!e)return!1;for(let r=0;r<t.length;r++){const o=this.findIdItem(t[r],e);if(o)return o}return!1}}!function(t){t.TITLE="title",t.LINK="link",t.DOC="doc"}(l||(l={})),function(t){t.BOARD="board",t.TABLE="table",t.SHEET="sheet",t.DOC="doc"}(u||(u={}));const g=new Map([[u.BOARD,"画板类型"],[u.TABLE,"数据表类型"],[u.SHEET,"表格类型"],[u.DOC,"文档类型"]]);function f({browser:t="chrome",os:e="mac os",device:r="desktop"}){r=r.toLowerCase(),t=t.toLowerCase(),e=e.toLowerCase();let o=c(r,t,e);if("chrome"===t)for(;o.includes("Chrome-Lighthouse")||o.includes("Gener8")||o.includes("HeadlessChrome")||o.includes("SMTBot");)o=c(r,t,e);if("safari"===t)for(;o.includes("Applebot");)o=c(r,t,e);return o}function m(t){const e={"user-agent":f({browser:"chrome",device:"desktop"})};return t&&(e.cookie=`_yuque_session=${t}`),e}const w=t=>{const{articleUrl:e,bookId:r,token:o}=t;let i=`https://www.yuque.com/api/docs/${e}`;const s={book_id:String(r),merge_dynamic_data:String(!1),mode:"markdown"},n=new URLSearchParams(s).toString();return i=`${i}?${n}`,a.get(i,{headers:m(o)}).then((({data:t,status:e})=>({apiUrl:i,httpStatus:e,response:t})))};async function b(t,r,s){const{bookId:n,itemUrl:a,savePath:c,saveFilePath:l,uuid:h,articleUrl:d,articleTitle:p,ignoreImg:f}=t,{httpStatus:m,apiUrl:b,response:$}=await w({articleUrl:a,bookId:n,token:s}),k=$?.data?.type?.toLocaleLowerCase();if([u.BOARD,u.SHEET,u.TABLE].includes(k)){const t=g.get(k);throw new Error(`download article Error: 暂不支持“${t}”的文档`)}if("string"!=typeof $?.data?.sourcecode)throw new Error(`download article Error: ${b}, http status ${m}`);let y=$.data.sourcecode;if(!f){r.pause(),console.log("");const t=i({text:`下载 "${p}" 的图片中...`});t.start();try{y=await o.run(y,{dist:c,imgDir:`./img/${h}`,isIgnoreConsole:!0})}catch(t){let e=`download article image Error: ${t.message}`;throw t.error&&t.url&&(e=`download article image Error ${t.url}: ${t.error?.message}`),new Error(e)}finally{t.stop(),r.continue()}}y=y.replace(/<br(\s?)\/>/gm,"\n"),p&&(y=`# ${p}\n\x3c!--page header--\x3e\n\n${y}\n\n`),d&&(y+=`\x3c!--page footer--\x3e\n- 原文: <${d}>`);try{return await e(l,y),!0}catch(t){throw new Error(`download article Error ${d}: ${t.message}`)}}function $(t){if(!t)return"";return t.replace(/[\\/:*?"<>|\n\r]/g,"_").replace(/\s/g,"")}async function k(t,e){const{bookId:o,tocList:i,bookName:s,bookDesc:n,bookSlug:c}=await((t,e)=>{const r=/decodeURIComponent\("(.+)"\)\);/m;return a.get(t,{headers:m(e)}).then((({data:t="",status:e})=>200===e?t:"")).then((t=>{const e=r.exec(t)??"";if(!e[1])return{};const o=JSON.parse(decodeURIComponent(e[1]));return o.book?{bookId:o.book.id,bookSlug:o.book.slug,tocList:o.book.toc||[],bookName:o.book.name||"",bookDesc:o.book.description||""}:{}}))})(t,e.token);if(!o)throw new Error("No found book id");if(!i||0===i.length)throw new Error("No found toc list");const u=`${e.distDir}/${s?$(s):o}`;await r(u,{recursive:!0});const g=i.length,f=new d(u,g);if(await f.init(),f.curr===g)return f.bar&&f.bar.stop(),void h.info(`√ 已完成: ${process.cwd()}/${u}`);const w=new Map;f.isDownloadInterrupted&&f.progressInfo.forEach((t=>{w.set(t.toc.uuid,t)}));const k=t.replace(new RegExp(`(.*?/${c}).*`),"$1");await async function(t){const{articleUrlPrefix:e,total:o,uuidMap:i,tocList:s,bookPath:n,bookId:a,progressBar:c,options:u}=t;let d=0,p=0,g=0,f=[],m=[];for(let t=0;t<o;t++){const o=s[t];if("string"!=typeof o.type)continue;if(i.get(o.uuid))continue;const h=o.type.toLocaleLowerCase();if(h===l.TITLE||""!==o.child_uuid||h===l.LINK){let t=o,e=[],s=[];for(;t;)e.unshift($(t.title)),s.unshift(t.uuid),t=i.get(t.parent_uuid)?i.get(t.parent_uuid).toc:void 0;const a={path:e.join("/"),pathTitleList:e,pathIdList:s,toc:o};h===l.LINK?(g+=1,m.push(a)):await r(`${n}/${e.join("/")}`,{recursive:!0}),i.set(o.uuid,a),await c.updateProgress(a,h!==l.LINK)}else if(o.url){p+=1;let t={path:"",pathTitleList:[],pathIdList:[]};i.get(o.parent_uuid)&&(t=i.get(o.parent_uuid));const r=$(o.title),s=[...t.pathTitleList,`${r}.md`],l=[...t.pathIdList,o.uuid],h={path:s.join("/"),pathTitleList:s,pathIdList:l,toc:o};let g=!0;const m=`${e}/${o.url}`;try{await b({bookId:a,itemUrl:o.url,savePath:`${n}/${t.path}`,saveFilePath:`${n}/${h.path}`,uuid:o.uuid,articleUrl:m,articleTitle:o.title,ignoreImg:u.ignoreImg},c,u.token)}catch(t){g=!1,d+=1,f.push({articleUrl:m,errItem:h,errMsg:t.message,err:t})}i.set(o.uuid,h),await c.updateProgress(h,g)}}if(g>0){h.warn("该知识库存在以下外链文章");for(const t of m)h.warn(`———— ✕ ${t.path} ${t.toc.url}`)}if(d>0){h.error(`本次执行总数${p}篇,✕ 失败${d}篇`);for(const t of f)h.error(`${t.errItem.path} ———— ${t.articleUrl}`),h.error(`———— ✕ ${t.errMsg}`);h.error("o(╥﹏╥)o 由于网络波动或链接失效以上下载失败,可重新执行命令重试(PS:不会影响已下载成功的数据)")}}({articleUrlPrefix:k,total:g,uuidMap:w,tocList:i,bookPath:u,bookId:o,progressBar:f,options:e});const y=new p({bookPath:u,bookName:s,bookDesc:n,uuidMap:w});await y.genFile();const I=process.cwd();h.info(`√ 生成目录 ${I}/${u}/SUMMARY.md`),f.curr===g&&h.info(`√ 已完成: ${I}/${u}`),process.exit(0)}export{b as d,h as l,k as m};
|
package/dist/es/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"node:fs/promises";import"
|
|
1
|
+
import"node:fs/promises";import"pull-md-img";import"ora";export{d as downloadArticle,m as main}from"./index-573d9cde.js";import"cli-progress";import"log4js";import"axios";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.22",
|
|
4
4
|
"description": "yuque 知识库下载",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"cli-progress": "^3.12.0",
|
|
61
61
|
"log4js": "^6.9.1",
|
|
62
62
|
"ora": "^7.0.1",
|
|
63
|
-
"pull-md-img": "^0.0.
|
|
63
|
+
"pull-md-img": "^0.0.25",
|
|
64
64
|
"rand-user-agent": "1.0.109"
|
|
65
65
|
},
|
|
66
66
|
"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
|
|
9
|
+
export type IProgress = IProgressItem[];
|
|
10
10
|
export default class ProgressBar {
|
|
11
11
|
bookPath: string;
|
|
12
12
|
progressFilePath: string;
|
package/types/api.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ArticleResponse } from './types/ArticleResponse';
|
|
2
|
+
import type { KnowledgeBase } from './types/KnowledgeBaseResponse';
|
|
3
|
+
interface IKnowledgeBaseInfo {
|
|
4
|
+
bookId?: number;
|
|
5
|
+
bookSlug?: string;
|
|
6
|
+
tocList?: KnowledgeBase.Toc[];
|
|
7
|
+
bookName?: string;
|
|
8
|
+
bookDesc?: string;
|
|
9
|
+
}
|
|
10
|
+
type TGetKnowledgeBaseInfo = (url: string, token?: string) => Promise<IKnowledgeBaseInfo>;
|
|
11
|
+
/** 获取知识库数据信息 */
|
|
12
|
+
export declare const getKnowledgeBaseInfo: TGetKnowledgeBaseInfo;
|
|
13
|
+
interface GetMdDataParams {
|
|
14
|
+
articleUrl: string;
|
|
15
|
+
bookId: number;
|
|
16
|
+
token?: string;
|
|
17
|
+
}
|
|
18
|
+
interface IGetDocsMdDataRes {
|
|
19
|
+
apiUrl: string;
|
|
20
|
+
httpStatus: number;
|
|
21
|
+
response?: ArticleResponse.RootObject;
|
|
22
|
+
}
|
|
23
|
+
type TGetMdData = (params: GetMdDataParams) => Promise<IGetDocsMdDataRes>;
|
|
24
|
+
export declare const getDocsMdData: TGetMdData;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** 语雀toc菜单类型 */
|
|
2
|
+
declare enum ARTICLE_TOC_TYPE {
|
|
3
|
+
TITLE = "title",
|
|
4
|
+
LINK = "link",
|
|
5
|
+
DOC = "doc"
|
|
6
|
+
}
|
|
7
|
+
/** 语雀档类型 */
|
|
8
|
+
declare enum ARTICLE_CONTENT_TYPE {
|
|
9
|
+
/** 画板 */
|
|
10
|
+
BOARD = "board",
|
|
11
|
+
/** 数据表 */
|
|
12
|
+
TABLE = "table",
|
|
13
|
+
/** 表格 */
|
|
14
|
+
SHEET = "sheet",
|
|
15
|
+
/** 文档 */
|
|
16
|
+
DOC = "doc"
|
|
17
|
+
}
|
|
18
|
+
declare const articleContentMap: Map<ARTICLE_CONTENT_TYPE, string>;
|
|
19
|
+
export { ARTICLE_TOC_TYPE, ARTICLE_CONTENT_TYPE, articleContentMap };
|
package/types/index.d.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import ProgressBar from './ProgressBar';
|
|
2
|
-
import type { KnowledgeBase } from './types/KnowledgeBaseResponse';
|
|
3
2
|
import type { IOptions } from './cli';
|
|
4
|
-
interface IKnowledgeBaseInfo {
|
|
5
|
-
bookId?: number;
|
|
6
|
-
bookSlug?: string;
|
|
7
|
-
tocList?: KnowledgeBase.Toc[];
|
|
8
|
-
bookName?: string;
|
|
9
|
-
bookDesc?: string;
|
|
10
|
-
}
|
|
11
3
|
interface IDownloadArticleParams {
|
|
12
4
|
bookId: number;
|
|
13
5
|
itemUrl: string;
|
|
@@ -18,9 +10,7 @@ interface IDownloadArticleParams {
|
|
|
18
10
|
articleUrl: string;
|
|
19
11
|
ignoreImg: boolean;
|
|
20
12
|
}
|
|
21
|
-
/** 获取知识库数据信息 */
|
|
22
|
-
declare function getKnowledgeBaseInfo(url: string, token?: string): Promise<IKnowledgeBaseInfo>;
|
|
23
13
|
/** 下载单篇文章 */
|
|
24
14
|
declare function downloadArticle(params: IDownloadArticleParams, progressBar: ProgressBar, token?: string): Promise<boolean>;
|
|
25
15
|
declare function main(url: string, options: IOptions): Promise<void>;
|
|
26
|
-
export {
|
|
16
|
+
export { downloadArticle, main };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";var e=require("node:fs/promises"),t=require("axios"),r=require("pull-md-img"),o=require("ora"),i=require("cli-progress"),s=require("log4js"),n=require("rand-user-agent");var a,c=(s.configure({appenders:{cheese:{type:"console",layout:{type:"pattern",pattern:"%[%c [%p]:%] %m%n"}}},categories:{default:{appenders:["cheese"],level:"trace"}}}),s.getLogger("yuque-dl"));class l{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(){this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.curr!==this.total&&(this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,c.info("根据上次数据继续断点下载")),this.bar=new i.SingleBar({format:"Download [{bar}] {percentage}% | {value}/{total}"},i.Presets.legacy),this.bar.start(this.total,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){this.curr=this.curr+1,r&&(this.progressInfo.push(t),await e.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"})),this.bar&&(this.bar.update(this.curr),this.curr>=this.total&&(this.bar.stop(),console.log("")))}pause(){this.bar&&this.bar.stop()}continue(){this.clearLine(2),this.bar?.start(this.total,this.curr)}clearLine(e){if(!(e<=0)){process.stderr.cursorTo(0);for(let t=0;t<e;t++)process.stderr.moveCursor(0,-1),process.stderr.clearLine(1)}}}class u{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 n=s;const a=[];i.forEach((e=>{const t=e.toc,r=t.parent_uuid,o=this.findTree(a,r),i={text:t.title.replace(/[\\\/:\*\?"<>\|\n\r]/g,"_").replace(/\s/,""),id:t.uuid,level:1,type:""},s=t.type.toLocaleLowerCase();"title"===s||""!==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,a.push(i))):(i.type="link",i.link="link"===s?e.toc.url:e.path,"boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,a.push(i)))})),n+=this.genSummaryContent(a,"");try{await e.writeFile(`${o}/SUMMARY.md`,n)}catch(e){c.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 d({browser:e="chrome",os:t="mac os",device:r="desktop"}){r=r.toLowerCase(),e=e.toLowerCase(),t=t.toLowerCase();let o=n(r,e,t);if("chrome"===e)for(;o.includes("Chrome-Lighthouse")||o.includes("Gener8")||o.includes("HeadlessChrome")||o.includes("SMTBot");)o=n(r,e,t);if("safari"===e)for(;o.includes("Applebot");)o=n(r,e,t);return o}!function(e){e.BOARD="board",e.TABLE="table",e.SHEET="sheet",e.DOC="doc"}(a||(a={}));const h=new Map([[a.BOARD,"画板类型"],[a.TABLE,"数据表类型"],[a.SHEET,"表格类型"],[a.DOC,"文档类型"]]);var p;function g(e){const t={"user-agent":d({browser:"chrome",device:"desktop"})};return e&&(t.cookie=`_yuque_session=${e}`),t}function f(e,r){const o=/decodeURIComponent\("(.+)"\)\);/m;return t.get(e,{headers:g(r)}).then((({data:e="",status:t})=>200===t?e:"")).then((e=>{const t=o.exec(e)??"";if(!t[1])return{};const r=JSON.parse(decodeURIComponent(t[1]));if(!r.book)return{};return{bookId:r.book.id,bookSlug:r.book.slug,tocList:r.book.toc||[],bookName:r.book.name||"",bookDesc:r.book.description||""}}))}async function w(i,s,n){const{bookId:c,itemUrl:l,savePath:u,saveFilePath:d,uuid:p,articleUrl:f,articleTitle:w,ignoreImg:m}=i;let $=`https://www.yuque.com/api/docs/${l}`;const b={book_id:String(c),merge_dynamic_data:String(!1),mode:"markdown"},y=new URLSearchParams(b).toString();$=`${$}?${y}`;let k=(await t.get($,{headers:g(n)}).then((({data:e,status:t})=>{if(200===t){const t=e,r=t?.data?.type?.toLocaleLowerCase();if([a.BOARD,a.SHEET,a.TABLE].includes(r)){const e=h.get(r);throw new Error(`download article Error: 暂不支持“${e}”的文档`)}if(!t?.data?.sourcecode)throw new Error(`download article Error: ${$}`);return t}throw new Error(`download article Error: ${$} http status ${t}`)}))).data.sourcecode;if(!m){s.pause(),console.log("");const e=o({text:`下载 "${w}" 的图片中...`});e.start();try{k=await r.run(k,{dist:u,imgDir:`./img/${p}`,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)}finally{e.stop(),s.continue()}}k=k.replace(/<br(\s?)\/>/gm,"\n"),w&&(k=`# ${w}\n\x3c!--page header--\x3e\n\n${k}\n\n`),f&&(k+=`\x3c!--page footer--\x3e\n- 原文: <${f}>`);try{return await e.writeFile(d,k),!0}catch(e){throw new Error(`download article Error ${f}: ${e.message}`)}}function m(e){if(!e)return"";return e.replace(/[\\/:*?"<>|\n\r]/g,"_").replace(/\s/,"")}!function(e){e.TITLE="title",e.LINK="link",e.DOC="doc"}(p||(p={})),exports.downloadArticle=w,exports.getKnowledgeBaseInfo=f,exports.logger=c,exports.main=async function(t,r){const{bookId:o,tocList:i,bookName:s,bookDesc:n,bookSlug:a}=await f(t,r.token);if(!o)throw new Error("No found book id");if(!i||0===i.length)throw new Error("No found toc list");const d=`${r.distDir}/${s?m(s):o}`;await e.mkdir(d,{recursive:!0});const h=i.length,g=new l(d,h);if(await g.init(),g.curr===h)return g.bar&&g.bar.stop(),void c.info(`√ 已完成: ${process.cwd()}/${d}`);const $=new Map;g.isDownloadInterrupted&&g.progressInfo.forEach((e=>{$.set(e.toc.uuid,e)}));const b=t.replace(new RegExp(`(.*?/${a}).*`),"$1");let y=0,k=0,I=0,L=[],E=[];for(let t=0;t<h;t++){const s=i[t];if("string"!=typeof s.type)continue;if($.get(s.uuid))continue;const n=s.type.toLocaleLowerCase();if(n===p.TITLE||""!==s.child_uuid||n===p.LINK){let t=s,r=[],o=[];for(;t;)r.unshift(m(t.title)),o.unshift(t.uuid),t=$.get(t.parent_uuid)?$.get(t.parent_uuid).toc:void 0;const i={path:r.join("/"),pathTitleList:r,pathIdList:o,toc:s};n===p.LINK?(I+=1,E.push(i)):await e.mkdir(`${d}/${r.join("/")}`,{recursive:!0}),$.set(s.uuid,i),await g.updateProgress(i,n!==p.LINK)}else if(s.url){k+=1;let e={path:"",pathTitleList:[],pathIdList:[]};$.get(s.parent_uuid)&&(e=$.get(s.parent_uuid));const t=m(s.title),i=[...e.pathTitleList,`${t}.md`],n=[...e.pathIdList,s.uuid],a={path:i.join("/"),pathTitleList:i,pathIdList:n,toc:s};let c=!0;const l=`${b}/${s.url}`;try{await w({bookId:o,itemUrl:s.url,savePath:`${d}/${e.path}`,saveFilePath:`${d}/${a.path}`,uuid:s.uuid,articleUrl:l,articleTitle:s.title,ignoreImg:r.ignoreImg},g,r.token)}catch(e){c=!1,y+=1,L.push({articleUrl:l,errItem:a,errMsg:e.message,err:e})}$.set(s.uuid,a),await g.updateProgress(a,c)}}if(I>0){c.warn("该知识库存在以下外链文章");for(const e of E)c.warn(`———— ✕ ${e.path} ${e.toc.url}`)}if(y>0){c.error(`本次执行总数${k}篇,✕ 失败${y}篇`);for(const e of L)c.error(`${e.errItem.path} ———— ${e.articleUrl}`),c.error(`———— ✕ ${e.errMsg}`);c.error("o(╥﹏╥)o 由于网络波动或链接失效以上下载失败,可重新执行命令重试(不会影响已下载成功的数据)~~")}const v=new u({bookPath:d,bookName:s,bookDesc:n,uuidMap:$});await v.genFile();const S=process.cwd();c.info(`√ 生成目录 ${S}/${d}/SUMMARY.md`),g.curr===h&&c.info(`√ 已完成: ${S}/${d}`),process.exit(0)};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import t,{writeFile as e,mkdir as r}from"node:fs/promises";import o from"axios";import i from"pull-md-img";import s from"ora";import n from"cli-progress";import a from"log4js";import c from"rand-user-agent";var l,u=(a.configure({appenders:{cheese:{type:"console",layout:{type:"pattern",pattern:"%[%c [%p]:%] %m%n"}}},categories:{default:{appenders:["cheese"],level:"trace"}}}),a.getLogger("yuque-dl"));class h{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(){this.progressInfo=await this.getProgress(),this.curr=this.progressInfo.length,this.curr!==this.total&&(this.curr>0&&this.curr!==this.total&&(this.isDownloadInterrupted=!0,u.info("根据上次数据继续断点下载")),this.bar=new n.SingleBar({format:"Download [{bar}] {percentage}% | {value}/{total}"},n.Presets.legacy),this.bar.start(this.total,this.curr))}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,r){this.curr=this.curr+1,r&&(this.progressInfo.push(e),await t.writeFile(this.progressFilePath,JSON.stringify(this.progressInfo),{encoding:"utf8"})),this.bar&&(this.bar.update(this.curr),this.curr>=this.total&&(this.bar.stop(),console.log("")))}pause(){this.bar&&this.bar.stop()}continue(){this.clearLine(2),this.bar?.start(this.total,this.curr)}clearLine(t){if(!(t<=0)){process.stderr.cursorTo(0);for(let e=0;e<t;e++)process.stderr.moveCursor(0,-1),process.stderr.clearLine(1)}}}class d{constructor(t){this.summaryInfo=t}async genFile(){const{bookName:e,bookDesc:r,bookPath:o,uuidMap:i}=this.summaryInfo;let s=`# ${e}\n\n`;r&&(s+=`> ${r}\n\n`);let n=s;const a=[];i.forEach((t=>{const e=t.toc,r=e.parent_uuid,o=this.findTree(a,r),i={text:e.title.replace(/[\\\/:\*\?"<>\|\n\r]/g,"_").replace(/\s/,""),id:e.uuid,level:1,type:""},s=e.type.toLocaleLowerCase();"title"===s||""!==e.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,a.push(i))):(i.type="link",i.link="link"===s?t.toc.url:t.path,"boolean"!=typeof o?(Array.isArray(o.children)||(o.children=[]),i.level=o.level+1,o.children.push(i)):(i.level=1,a.push(i)))})),n+=this.genSummaryContent(a,"");try{await t.writeFile(`${o}/SUMMARY.md`,n)}catch(t){u.error("Generate Summary Error")}}genSummaryContent(t,e){for(let r=0;r<t.length;r++){const o=t[r];if("title"===o.type)e+=`\n${"".padStart(o.level+1,"#")} ${o.text}\n\n`;else if("link"===o.type){const t=o.link?o.link.replace(/\s/g,"%20"):o.link;e+=`- [${o.text}](${t})\n`}Array.isArray(o.children)&&(e+=this.genSummaryContent(o.children,""))}return e}findIdItem(t,e){if(t.id===e)return t;if(t.children){const r=this.findTree(t.children,e);if(r)return r}return!1}findTree(t,e){if(!e)return!1;for(let r=0;r<t.length;r++){const o=this.findIdItem(t[r],e);if(o)return o}return!1}}function p({browser:t="chrome",os:e="mac os",device:r="desktop"}){r=r.toLowerCase(),t=t.toLowerCase(),e=e.toLowerCase();let o=c(r,t,e);if("chrome"===t)for(;o.includes("Chrome-Lighthouse")||o.includes("Gener8")||o.includes("HeadlessChrome")||o.includes("SMTBot");)o=c(r,t,e);if("safari"===t)for(;o.includes("Applebot");)o=c(r,t,e);return o}!function(t){t.BOARD="board",t.TABLE="table",t.SHEET="sheet",t.DOC="doc"}(l||(l={}));const g=new Map([[l.BOARD,"画板类型"],[l.TABLE,"数据表类型"],[l.SHEET,"表格类型"],[l.DOC,"文档类型"]]);var f;function m(t){const e={"user-agent":p({browser:"chrome",device:"desktop"})};return t&&(e.cookie=`_yuque_session=${t}`),e}function w(t,e){const r=/decodeURIComponent\("(.+)"\)\);/m;return o.get(t,{headers:m(e)}).then((({data:t="",status:e})=>200===e?t:"")).then((t=>{const e=r.exec(t)??"";if(!e[1])return{};const o=JSON.parse(decodeURIComponent(e[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 $(t,r,n){const{bookId:a,itemUrl:c,savePath:u,saveFilePath:h,uuid:d,articleUrl:p,articleTitle:f,ignoreImg:w}=t;let $=`https://www.yuque.com/api/docs/${c}`;const b={book_id:String(a),merge_dynamic_data:String(!1),mode:"markdown"},y=new URLSearchParams(b).toString();$=`${$}?${y}`;let k=(await o.get($,{headers:m(n)}).then((({data:t,status:e})=>{if(200===e){const e=t,r=e?.data?.type?.toLocaleLowerCase();if([l.BOARD,l.SHEET,l.TABLE].includes(r)){const t=g.get(r);throw new Error(`download article Error: 暂不支持“${t}”的文档`)}if(!e?.data?.sourcecode)throw new Error(`download article Error: ${$}`);return e}throw new Error(`download article Error: ${$} http status ${e}`)}))).data.sourcecode;if(!w){r.pause(),console.log("");const t=s({text:`下载 "${f}" 的图片中...`});t.start();try{k=await i.run(k,{dist:u,imgDir:`./img/${d}`,isIgnoreConsole:!0})}catch(t){let e=`download article image Error: ${t.message}`;throw t.error&&t.url&&(e=`download article image Error ${t.url}: ${t.error?.message}`),new Error(e)}finally{t.stop(),r.continue()}}k=k.replace(/<br(\s?)\/>/gm,"\n"),f&&(k=`# ${f}\n\x3c!--page header--\x3e\n\n${k}\n\n`),p&&(k+=`\x3c!--page footer--\x3e\n- 原文: <${p}>`);try{return await e(h,k),!0}catch(t){throw new Error(`download article Error ${p}: ${t.message}`)}}function b(t){if(!t)return"";return t.replace(/[\\/:*?"<>|\n\r]/g,"_").replace(/\s/,"")}async function y(t,e){const{bookId:o,tocList:i,bookName:s,bookDesc:n,bookSlug:a}=await w(t,e.token);if(!o)throw new Error("No found book id");if(!i||0===i.length)throw new Error("No found toc list");const c=`${e.distDir}/${s?b(s):o}`;await r(c,{recursive:!0});const l=i.length,p=new h(c,l);if(await p.init(),p.curr===l)return p.bar&&p.bar.stop(),void u.info(`√ 已完成: ${process.cwd()}/${c}`);const g=new Map;p.isDownloadInterrupted&&p.progressInfo.forEach((t=>{g.set(t.toc.uuid,t)}));const m=t.replace(new RegExp(`(.*?/${a}).*`),"$1");let y=0,k=0,I=0,L=[],E=[];for(let t=0;t<l;t++){const s=i[t];if("string"!=typeof s.type)continue;if(g.get(s.uuid))continue;const n=s.type.toLocaleLowerCase();if(n===f.TITLE||""!==s.child_uuid||n===f.LINK){let t=s,e=[],o=[];for(;t;)e.unshift(b(t.title)),o.unshift(t.uuid),t=g.get(t.parent_uuid)?g.get(t.parent_uuid).toc:void 0;const i={path:e.join("/"),pathTitleList:e,pathIdList:o,toc:s};n===f.LINK?(I+=1,E.push(i)):await r(`${c}/${e.join("/")}`,{recursive:!0}),g.set(s.uuid,i),await p.updateProgress(i,n!==f.LINK)}else if(s.url){k+=1;let t={path:"",pathTitleList:[],pathIdList:[]};g.get(s.parent_uuid)&&(t=g.get(s.parent_uuid));const r=b(s.title),i=[...t.pathTitleList,`${r}.md`],n=[...t.pathIdList,s.uuid],a={path:i.join("/"),pathTitleList:i,pathIdList:n,toc:s};let l=!0;const u=`${m}/${s.url}`;try{await $({bookId:o,itemUrl:s.url,savePath:`${c}/${t.path}`,saveFilePath:`${c}/${a.path}`,uuid:s.uuid,articleUrl:u,articleTitle:s.title,ignoreImg:e.ignoreImg},p,e.token)}catch(t){l=!1,y+=1,L.push({articleUrl:u,errItem:a,errMsg:t.message,err:t})}g.set(s.uuid,a),await p.updateProgress(a,l)}}if(I>0){u.warn("该知识库存在以下外链文章");for(const t of E)u.warn(`———— ✕ ${t.path} ${t.toc.url}`)}if(y>0){u.error(`本次执行总数${k}篇,✕ 失败${y}篇`);for(const t of L)u.error(`${t.errItem.path} ———— ${t.articleUrl}`),u.error(`———— ✕ ${t.errMsg}`);u.error("o(╥﹏╥)o 由于网络波动或链接失效以上下载失败,可重新执行命令重试(不会影响已下载成功的数据)~~")}const v=new d({bookPath:c,bookName:s,bookDesc:n,uuidMap:g});await v.genFile();const S=process.cwd();u.info(`√ 生成目录 ${S}/${c}/SUMMARY.md`),p.curr===l&&u.info(`√ 已完成: ${S}/${c}`),process.exit(0)}!function(t){t.TITLE="title",t.LINK="link",t.DOC="doc"}(f||(f={}));export{$ as d,w as g,u as l,y as m};
|