├── .gitignore ├── LICENSE ├── README.md ├── package.json └── src ├── main.js ├── request └── index.js ├── template └── read.html └── work └── dd.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | *.idea 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # TypeScript v1 declaration files 46 | typings/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | # dotenv environment variables file 73 | .env 74 | .env.test 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 三闻书店 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dangdang-bug 2 | 3 | 离线下载当当html格式图书,支持离线阅读,html转pdf阅读 4 | 5 |  6 | 7 | ## 优点 8 | * 30m左右的html格式图书压缩后大约3m左右 9 | * 电脑离线阅读 10 | * 转换pdf后可以在ipad上做笔记 11 | * 支持断点下载 12 | * 免费图书可直接下载 13 | 14 | ## 须知 15 | 本程序适用于以下场景 16 | 17 | * 您已经购买过该云图书 18 | * 您需要离线阅读的需求 19 | * 您不会私自分享,侵犯著作人权利 20 | 21 | ## 安装 22 | ```shell script 23 | npm install dangdang-bug -g 24 | ``` 25 | 26 | ## 使用 27 | ```shell script 28 | dangdang [epubID] [token] [mode] 29 | ``` 30 | * epubID 是电子书阅读时候的ID,您在阅读的时候可以在url中看到 31 | 32 |  33 | 34 | * token 是下载完整书籍的钥匙,如果您不传token则只能下载试读章节,token可以在网页`F12`网页控制台的请求中查看到 35 | 36 |  37 | 38 | * mode 下载模式, 有三种下载模式 slow | normal | fast 默认为 normal, 对于章节少的书可以用fast 或者 normal, 章节多的书请用slow 39 | 40 | 示例 41 | ```shell script 42 | dangdang 1900386571 43 | ``` 44 | 45 | 无token更改模式输入`null` 46 | ```shell script 47 | dangdang 1900386571 null slow 48 | ``` 49 | 50 | 默认下载到当前命令行运行文件目录,生成格式如下 51 | ```shell script 52 | |-root 53 | |- [数据] 54 | |- data 55 | |- chapter-0.js 56 | |- chapter-1.js 57 | |- ... 58 | |- [阅读目录] 59 | |- chapter-0.html 60 | |- chapter-1.html 61 | |- ... 62 | ``` 63 | 64 | ## Q&A 65 | 66 | #### 如何转换pdf? 67 | 直接点击书中的`打印转换pdf`按钮,使用chrome转换pdf 68 | 69 | #### 如何合并pdf? 70 | 由于转换的pdf都是按章节一节一节的,您可以在网上使用第三方工具转换 71 | 72 | #### 下载不完整? 73 | 由于token过期时间短,请每隔一段时间查看更新一下你输入的token 74 | 75 | ## 声明 76 | 请您遵循上述须知协议,书籍宝贵,请勿盗用 77 | 78 |  79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dangdang-bug", 3 | "version": "1.1.0", 4 | "description": "当当云阅读下载器", 5 | "bin": { 6 | "dangdang": "./src/main.js" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/Jon-Millent/dangdang-bug.git" 11 | }, 12 | "author": "jon millent", 13 | "license": "MIT", 14 | "bugs": { 15 | "url": "https://github.com/Jon-Millent/dangdang-bug/issues" 16 | }, 17 | "homepage": "https://github.com/Jon-Millent/dangdang-bug#readme", 18 | "dependencies": { 19 | "axios": "^0.20.0", 20 | "progress": "^2.0.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const DD = require('./work/dd') 4 | const argv = process.argv 5 | 6 | if(argv.length <= 2) { 7 | console.log(` 8 | help 9 | 10 | dangdang [epubID] [token] 11 | 12 | @epubID[required] 13 | @token 如果不传只能下载试读章节 14 | 15 | [more] 16 | 更多帮助请访问 https://github.com/Jon-Millent/dangdang-bug 17 | `) 18 | return 19 | } 20 | 21 | argv.forEach((item, index)=> { 22 | if(item === 'null') { 23 | argv[index] = null 24 | } 25 | }) 26 | 27 | let dd = new DD({ 28 | epubID: argv[2], 29 | token: argv[3] || '', 30 | mode: argv[4] || 'normal' 31 | }) 32 | 33 | dd.bug() 34 | -------------------------------------------------------------------------------- /src/request/index.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | const request = axios.create({ 4 | timeout: 20000, 5 | headers: { 6 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36', 7 | } 8 | }) 9 | 10 | request.interceptors.response.use( 11 | response => { //成功请求到数据 12 | let rawData = null 13 | if (response.status !== 200) { 14 | rawData = {code: 1, err: response.data, msg: '请求失败', isSuccess: false} 15 | } else { 16 | rawData = response.data 17 | } 18 | rawData.isSuccess = rawData.status && rawData.status.code === 0 19 | return rawData 20 | }, 21 | error => { //响应错误处理 22 | return { 23 | error, 24 | code: 500, 25 | msg: '请求失败:' + (error.response ? error.response.status : '未知错误') 26 | } 27 | } 28 | ) 29 | 30 | function get(api, params = {}, config = {}){ 31 | let beforeConfig = {} 32 | 33 | return request(Object.assign( 34 | { 35 | url: api, 36 | method: 'GET', 37 | params: Object.assign(params, {t: new Date().getTime()}), 38 | }, 39 | beforeConfig 40 | )) 41 | } 42 | 43 | 44 | function post(api, params = {}, config = {}){ 45 | let beforeConfig = {} 46 | 47 | return request(Object.assign( 48 | { 49 | url: api, 50 | method: 'POST', 51 | data: params 52 | }, 53 | beforeConfig 54 | )) 55 | } 56 | 57 | function go (data) { 58 | return get('http://e.dangdang.com/media/api.go', data) 59 | } 60 | 61 | // 获取目录 62 | function getPcMediaInfo(data) { 63 | /* 64 | need 65 | * epubID 66 | */ 67 | return go(Object.assign({ 68 | action: 'getPcMediaInfo', 69 | consumeType: 1, 70 | platform: 3, 71 | deviceType: 'Android', 72 | deviceVersion: '5.0.0', 73 | platformSource: 'DDDS-P', 74 | fromPaltform: 'ds_android', 75 | deviceSerialNo: 'html5', 76 | clientVersionNo: '5.8.4', 77 | wordSize: 2, 78 | style: 2 79 | }, data)) 80 | } 81 | 82 | // 获取章节信息 83 | function getPcChapterInfo(data) { 84 | /* 85 | need 86 | * epubID 87 | * chapterID 88 | * pageIndex 89 | */ 90 | return go(Object.assign({ 91 | action: 'getPcChapterInfo', 92 | consumeType: 1, 93 | platform: 3, 94 | deviceType: 'Android', 95 | deviceVersion: '5.0.0', 96 | platformSource: 'DDDS-P', 97 | fromPaltform: 'ds_android', 98 | deviceSerialNo: 'html5', 99 | clientVersionNo: '5.8.4', 100 | wordSize: 2, 101 | style: 2, 102 | }, data)) 103 | } 104 | 105 | module.exports = { 106 | get, 107 | post, 108 | go, 109 | getPcMediaInfo, 110 | getPcChapterInfo 111 | } 112 | -------------------------------------------------------------------------------- /src/template/read.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 7 | 8 |