diff --git a/.gitignore b/.gitignore index dcefdef..1b44f68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -node_modules -config.js +/node_modules/ +/config.json files* diff --git a/README.md b/README.md index 2b3f36b..0de37f2 100644 --- a/README.md +++ b/README.md @@ -7,22 +7,33 @@ - 思维导图 - 幻灯片 -## Usage +## Usage with exe + +1. 下载 shimoExporter.exe +2. 下载 config.example.json, 并重命名为 config.json +3. 在浏览器中登录石墨文档, 并使用 F12(开发者模式) 获取网页 Cookie +4. 将网页 Cookie 粘贴到 config.json 的"Cookie"字段中 +5. 修改 config.json 的"Path"字段为导出文档的保存路径 +6. 运行 shimoExporter.exe + +## Usage with NodeJS 填写配置文件 ```shell -cp config.example.js config.js +cp config.example.json config.json ``` -```js -export const config = { - Cookie: 'xxx', // 从浏览器中获取石墨文档的 Cookie - Path: 'files', // 存放导出文档的位置 - Folder: '', // 需要导出的文件夹 ID,从浏览器地址栏获取,https://shimo.im/folder/xxx 中 xxx,全部导出则留空 - Recursive: false, // 是否导出子目录 - Sleep: 1000 // 导出两个文档间的时间间隔,必须设置,否则会服务器忙,单位 ms -}; +```config.json +{ + "@Cookie": "从浏览器中获取石墨文档的 Cookie", + "@Path": "存放导出文档的位置", + "@Folder": "需要导出的文件夹 ID,从浏览器地址栏获取,https://shimo.im/folder/xxx 中 xxx,全部导出则留空", + "@Recursive": "是否导出子目录", + "@Sleep": "导出两个文档间的时间间隔,必须设置,否则会服务器忙,单位 ms", + "@Lasttime": "timeship you copy file(run this tool) last time, default 0 means to copy all files this time.", + "@Retry": "重试次数", +} ``` 安装依赖 @@ -37,6 +48,12 @@ yarn // or npm install node index.js ``` +导出可执行文件 + +```shell +npm run build +``` + ## 依赖 ``` diff --git a/config.example.js b/config.example.js deleted file mode 100644 index 027a2b6..0000000 --- a/config.example.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - Cookie: 'xxx', // 从浏览器中获取石墨文档的 Cookie - Path: 'files', // 存放导出文档的位置 - Folder: '', // 需要导出的文件夹 ID,从浏览器地址栏获取,https://shimo.im/folder/xxx 中 xxx,全部导出则留空 - Recursive: false, // 是否导出子目录 - Sleep: 1000, // 导出两个文档间的时间间隔,必须设置,否则会服务器忙,单位 ms - Lasttime: 0, // timeship you copy file(run this tool) last time, default 0 means to copy all files this time. - Retry: 3 // 重试次数 -}; diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..c994a4d --- /dev/null +++ b/config.example.json @@ -0,0 +1,16 @@ +{ + "@Cookie": "从浏览器中获取石墨文档的 Cookie", + "Cookie": "xxx", + "@Path": "存放导出文档的位置", + "Path": "F:/shimoExport/Export", + "@Folder": "需要导出的文件夹 ID,从浏览器地址栏获取,https://shimo.im/folder/xxx 中 xxx,全部导出则留空", + "Folder": "", + "@Recursive": "是否导出子目录", + "Recursive": true, + "@Sleep": "导出两个文档间的时间间隔,必须设置,否则会服务器忙,单位 ms", + "Sleep": 500, + "@Lasttime": "timeship you copy file(run this tool) last time, default 0 means to copy all files this time.", + "Lasttime": 0, + "@Retry": "重试次数", + "Retry": 3 +} diff --git a/index.js b/index.js index c21f8e0..8be6208 100644 --- a/index.js +++ b/index.js @@ -2,19 +2,35 @@ const axios = require('axios'); const Path = require('path'); const download = require('download'); const sleep = require('await-sleep'); -const config = require('./config.js'); +const fs = require('fs'); +let config = {}; +let fileData = fs.readFileSync('config.json', 'utf8'); +try { + config = JSON.parse(fileData); + // console.log('config: ', config); + console.log('Path: ', config.Path); + console.log('Folder: ', config.Folder); +} catch (err) { + console.error('解析配置文件出错:', err); +} +// const config = require('./config.js'); const headersOptions = { Cookie: config.Cookie, Referer: 'https://shimo.im/folder/123', }; +const desktopHeadersOptions = { + Cookie: config.Cookie, + Referer: 'https://shimo.im/desktop', +}; getFileList(config.Folder, config.Path); async function getFileList(folder = '', basePath = '') { try { + const paramsOptions = folder ? { collaboratorCount: 'true', folder: folder } : { collaboratorCount: 'true' }; const response = await axios.get('https://shimo.im/lizard-api/files', { - params: { collaboratorCount: 'true', folder: folder }, - headers: headersOptions + params: paramsOptions, + headers: folder ? headersOptions : desktopHeadersOptions }); for (let i = 0; i < response.data.length; i++) { @@ -29,15 +45,20 @@ async function getFileList(folder = '', basePath = '') { // } console.log(item.name, item.type, item.updatedAt); if (item.is_folder != 1) { - for (let j = 1; j <= config.Retry; j++) { - const res = await createExportTask(item, basePath); - if (res != 0) { + let res = -1; + for (let j = 0; j <= config.Retry; j++) { + if (j > 0) { console.error("retry " + j + " times..."); await sleep(config.Sleep * 2); - } else { + } + res = await createExportTask(item, basePath); + if (res == 0 || res == 1) { break; } } + if (res != 0) { + console.error('[Error] Failed to export: ' + item.name); + } } else { if (config.Recursive) { await getFileList(item.guid, Path.join(basePath, item.name)); @@ -50,7 +71,7 @@ async function getFileList(folder = '', basePath = '') { } } } catch (error) { - console.error(error); + console.error('[Error] ' + error); } } @@ -58,44 +79,58 @@ async function createExportTask(item, basePath = '') { try { let type = ''; const name = replaceBadChar(item.name); - if (item.type == 'newdoc' || item.type == 'document') { - type = 'docx'; - } else if (item.type == 'sheet' || item.type == 'mosheet' || item.type == 'spreadsheet') { - type = 'xlsx'; - } else if (item.type == 'slide') { - type = 'pptx'; - } else if (item.type == 'mindmap') { - type = 'xmind'; - } else { - console.error('unsupport type: ' + item.type); - return 1; + let downloadUrl = ''; + if (item.type == 'docx' || item.type == 'doc' || + item.type == 'pptx' || item.type == 'ppt' || + item.type == 'pdf') + { + downloadUrl = 'https://shimo.im/lizard-api/files/' + item.guid + '/download'; } + else + { + if (item.type == 'newdoc' || item.type == 'document' || item.type == 'modoc') { + type = 'docx'; + } else if (item.type == 'sheet' || item.type == 'mosheet' || item.type == 'spreadsheet') { + type = 'xlsx'; + } else if (item.type == 'slide' || item.type == 'presentation') { + type = 'pptx'; + } else if (item.type == 'mindmap') { + type = 'xmind'; + } else { + console.error('[Error] ' + item.name + ' has unsupported type: ' + item.type); + return 1; + } - const url = 'https://shimo.im/lizard-api/files/' + item.guid + '/export'; + const url = 'https://shimo.im/lizard-api/files/' + item.guid + '/export'; - const response = await axios.get(url, { - params: { - type: type, - file: item.guid, - returnJson: '1', - name: name, - isAsync: '0' - }, - headers: headersOptions - }); + const response = await axios.get(url, { + params: { + type: type, + file: item.guid, + returnJson: '1', + name: name, + isAsync: '0' + }, + headers: headersOptions + }); - // console.log(name, response.data) - // console.log(response.data.redirectUrl, Path.join(config.Path, basePath)); - if (!response.data.redirectUrl) { - console.error(item.name + ' failed, error: ', response.data); + //console.log(name, response.data) + // console.log(response.data.redirectUrl, Path.join(config.Path, basePath)); + downloadUrl = response.data.redirectUrl; + if (!downloadUrl) { + downloadUrl = response.data.data.downloadUrl; + } + } + if (!downloadUrl) { + console.error('[Error] ' + item.name + ' failed, error: ', response.data); return 2; } const options = { headers: headersOptions }; - await download(response.data.redirectUrl, basePath, options); + await download(downloadUrl, basePath, options); } catch (error) { - console.error(item.name + ' failed, error: ' + error.message); + console.error('[Error] ' + item.name + ' failed, error: ' + error.message); return 3; } return 0; diff --git a/package.json b/package.json index 95b11cb..4c6c764 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,9 @@ "name": "shimo", "version": "1.0.0", "main": "index.js", + "scripts": { + "build": "pkg index.js --output shimoExporter" + }, "license": "MIT", "dependencies": { "await-sleep": "^0.0.1",