├── assets
├── mimetype
├── container.xml
├── toc.ejs
├── content.ejs
└── Style.css
├── .gitignore
├── package.json
├── README.md
├── uuid.js
└── jianhelper.js
/assets/mimetype:
--------------------------------------------------------------------------------
1 | application/epub+zip
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | out
3 | out.epub
--------------------------------------------------------------------------------
/assets/container.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jianhelper",
3 | "version": "1.0.0",
4 | "description": "A downloader for articles in jianshu.com.",
5 | "main": "jianhelper.js",
6 | "author": "wizardforcel",
7 | "license": "MIT",
8 | "dependencies": {
9 | "cheerio": "^0.19.0",
10 | "ejs": "^2.4.1",
11 | "jszip": "^2.5.0",
12 | "sync-request": "^2.1.0"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 简书助手
2 |
3 | 爬取简书的文章,并生成EPUB格式。
4 |
5 | ## 用法
6 |
7 | 首先到[官网](https://nodejs.org/en/download/)下载并安装node.js。
8 |
9 | ```
10 | git clone https://github.com/wizardforcel/jianhelper.git
11 | cd jianhelper
12 | npm install
13 | node jianhelper url [start [end]]
14 | ```
15 |
16 | url:支持三种类型
17 |
18 | + http://www.jianshu.com/users/{id} 用户
19 | + http://www.jianshu.com/notebooks/{id} 文集
20 | + http://www.jianshu.com/collection/{id} 专题
21 |
22 | start:起始页,默认为第一页
23 |
24 | end:终止页,默认为最后一页
25 |
26 | ## TODO
27 |
28 | + 添加标题、封面
29 |
30 | ## 协议
31 |
32 | MIT-LICENSE
33 |
--------------------------------------------------------------------------------
/assets/toc.ejs:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Unknown
12 |
13 |
14 | <% for(var i = 0; i < toc.length; i++) {%>
15 |
16 |
17 | <%- toc[i].title %>
18 |
19 |
20 |
21 | <% } %>
22 |
23 |
--------------------------------------------------------------------------------
/assets/content.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | urn:uuid:<%- uuid %>
5 |
6 | zh-CN
7 | <%- date %>
8 |
9 |
10 |
11 | <% for(var i = 0; i < toc.length; i++) {%>
12 |
13 | <% } %>
14 |
15 |
16 | <% for(var i = 0; i < toc.length; i++) {%>
17 |
18 | <% } %>
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/uuid.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Math.uuid.js (v1.4)
3 |
4 | http://www.broofa.com
5 |
6 | mailto:robert@broofa.com
7 |
8 | Copyright (c) 2010 Robert Kieffer
9 | Dual licensed under the MIT and GPL licenses.
10 | */
11 |
12 | /*
13 | * Generate a random uuid.
14 | *
15 | * USAGE: Math.uuid(length, radix)
16 | * length - the desired number of characters
17 | * radix - the number of allowable values for each character.
18 | *
19 | * EXAMPLES:
20 | * // No arguments - returns RFC4122, version 4 ID
21 | * >>> Math.uuid()
22 | * "92329D39-6F5C-4520-ABFC-AAB64544E172"
23 | *
24 | * // One argument - returns ID of the specified length
25 | * >>> Math.uuid(15) // 15 character ID (default base=62)
26 | * "VcydxgltxrVZSTV"
27 | *
28 | * // Two arguments - returns ID of the specified length, and radix. (Radix must be <= 62)
29 | * >>> Math.uuid(8, 2) // 8 character ID (base=2)
30 | * "01001010"
31 | * >>> Math.uuid(8, 10) // 8 character ID (base=10)
32 | * "47473046"
33 | * >>> Math.uuid(8, 16) // 8 character ID (base=16)
34 | * "098F4D35"
35 | */
36 |
37 | var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
38 |
39 | exports.uuid = function (len, radix) {
40 | var chars = CHARS, uuid = [], i;
41 | radix = radix || chars.length;
42 |
43 | if (len) {
44 | // Compact form
45 | for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
46 | } else {
47 | // rfc4122, version 4 form
48 | var r;
49 |
50 | // rfc4122 requires these characters
51 | uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
52 | uuid[14] = '4';
53 |
54 | // Fill in random data. At i==19 set the high bits of clock sequence as
55 | // per rfc4122, sec. 4.1.5
56 | for (i = 0; i < 36; i++) {
57 | if (!uuid[i]) {
58 | r = 0 | Math.random()*16;
59 | uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
60 | }
61 | }
62 | }
63 |
64 | return uuid.join('');
65 | };
66 |
67 | // A more performant, but slightly bulkier, RFC4122v4 solution. We boost performance
68 | // by minimizing calls to random()
69 | exports.uuidFast = function() {
70 | var chars = CHARS, uuid = new Array(36), rnd=0, r;
71 | for (var i = 0; i < 36; i++) {
72 | if (i==8 || i==13 || i==18 || i==23) {
73 | uuid[i] = '-';
74 | } else if (i==14) {
75 | uuid[i] = '4';
76 | } else {
77 | if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0;
78 | r = rnd & 0xf;
79 | rnd = rnd >> 4;
80 | uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
81 | }
82 | }
83 | return uuid.join('');
84 | };
85 |
86 | // A more compact, but less performant, RFC4122v4 solution:
87 | exports.uuidCompact = function() {
88 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
89 | var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
90 | return v.toString(16);
91 | });
92 | };
--------------------------------------------------------------------------------
/assets/Style.css:
--------------------------------------------------------------------------------
1 | /* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
2 | /* Author: Nicolas Hery - http://nicolashery.com */
3 | /* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
4 | /* Source: https://github.com/nicolahery/markdownpad-github */
5 |
6 | /* RESET
7 | =============================================================================*/
8 |
9 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
10 | margin: 0;
11 | padding: 0;
12 | border: 0;
13 | }
14 |
15 | /* BODY
16 | =============================================================================*/
17 |
18 | body {
19 | font-family: Helvetica, arial, freesans, clean, sans-serif;
20 | font-size: 14px;
21 | line-height: 1.6;
22 | color: #333;
23 | background-color: #fff;
24 | padding: 20px;
25 | max-width: 960px;
26 | margin: 0 auto;
27 | }
28 |
29 | body>*:first-child {
30 | margin-top: 0 !important;
31 | }
32 |
33 | body>*:last-child {
34 | margin-bottom: 0 !important;
35 | }
36 |
37 | /* BLOCKS
38 | =============================================================================*/
39 |
40 | p, blockquote, ul, ol, dl, table, pre {
41 | margin: 15px 0;
42 | }
43 |
44 | /* HEADERS
45 | =============================================================================*/
46 |
47 | h1, h2, h3, h4, h5, h6 {
48 | margin: 20px 0 10px;
49 | padding: 0;
50 | font-weight: bold;
51 | -webkit-font-smoothing: antialiased;
52 | }
53 |
54 | h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
55 | font-size: inherit;
56 | }
57 |
58 | h1 {
59 | font-size: 24px;
60 | border-bottom: 1px solid #ccc;
61 | color: #000;
62 | }
63 |
64 | h2 {
65 | font-size: 18px;
66 | color: #000;
67 | }
68 |
69 | h3 {
70 | font-size: 14px;
71 | }
72 |
73 | h4 {
74 | font-size: 14px;
75 | }
76 |
77 | h5 {
78 | font-size: 14px;
79 | }
80 |
81 | h6 {
82 | color: #777;
83 | font-size: 14px;
84 | }
85 |
86 | body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
87 | margin-top: 0;
88 | padding-top: 0;
89 | }
90 |
91 | a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
92 | margin-top: 0;
93 | padding-top: 0;
94 | }
95 |
96 | h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
97 | margin-top: 10px;
98 | }
99 |
100 | /* LINKS
101 | =============================================================================*/
102 |
103 | a {
104 | color: #4183C4;
105 | text-decoration: none;
106 | }
107 |
108 | a:hover {
109 | text-decoration: underline;
110 | }
111 |
112 | /* LISTS
113 | =============================================================================*/
114 |
115 | ul, ol {
116 | padding-left: 30px;
117 | }
118 |
119 | ul li > :first-child,
120 | ol li > :first-child,
121 | ul li ul:first-of-type,
122 | ol li ol:first-of-type,
123 | ul li ol:first-of-type,
124 | ol li ul:first-of-type {
125 | margin-top: 0px;
126 | }
127 |
128 | ul ul, ul ol, ol ol, ol ul {
129 | margin-bottom: 0;
130 | }
131 |
132 | dl {
133 | padding: 0;
134 | }
135 |
136 | dl dt {
137 | font-size: 14px;
138 | font-weight: bold;
139 | font-style: italic;
140 | padding: 0;
141 | margin: 15px 0 5px;
142 | }
143 |
144 | dl dt:first-child {
145 | padding: 0;
146 | }
147 |
148 | dl dt>:first-child {
149 | margin-top: 0px;
150 | }
151 |
152 | dl dt>:last-child {
153 | margin-bottom: 0px;
154 | }
155 |
156 | dl dd {
157 | margin: 0 0 15px;
158 | padding: 0 15px;
159 | }
160 |
161 | dl dd>:first-child {
162 | margin-top: 0px;
163 | }
164 |
165 | dl dd>:last-child {
166 | margin-bottom: 0px;
167 | }
168 |
169 | /* CODE
170 | =============================================================================*/
171 |
172 | pre, code, tt {
173 | font-size: 12px;
174 | font-family: Consolas, "Liberation Mono", Courier, monospace;
175 | }
176 |
177 | code, tt {
178 | margin: 0 0px;
179 | padding: 0px 0px;
180 | white-space: nowrap;
181 | border: 1px solid #eaeaea;
182 | background-color: #f8f8f8;
183 | border-radius: 3px;
184 | }
185 |
186 | pre>code {
187 | margin: 0;
188 | padding: 0;
189 | white-space: pre;
190 | border: none;
191 | background: transparent;
192 | }
193 |
194 | pre {
195 | background-color: #f8f8f8;
196 | border: 1px solid #ccc;
197 | font-size: 13px;
198 | line-height: 19px;
199 | overflow: auto;
200 | padding: 6px 10px;
201 | border-radius: 3px;
202 | }
203 |
204 | pre code, pre tt {
205 | background-color: transparent;
206 | border: none;
207 | }
208 |
209 | kbd {
210 | -moz-border-bottom-colors: none;
211 | -moz-border-left-colors: none;
212 | -moz-border-right-colors: none;
213 | -moz-border-top-colors: none;
214 | background-color: #DDDDDD;
215 | background-image: linear-gradient(#F1F1F1, #DDDDDD);
216 | background-repeat: repeat-x;
217 | border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
218 | border-image: none;
219 | border-radius: 2px 2px 2px 2px;
220 | border-style: solid;
221 | border-width: 1px;
222 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
223 | line-height: 10px;
224 | padding: 1px 4px;
225 | }
226 |
227 | /* QUOTES
228 | =============================================================================*/
229 |
230 | blockquote {
231 | border-left: 4px solid #DDD;
232 | padding: 0 15px;
233 | color: #777;
234 | }
235 |
236 | blockquote>:first-child {
237 | margin-top: 0px;
238 | }
239 |
240 | blockquote>:last-child {
241 | margin-bottom: 0px;
242 | }
243 |
244 | /* HORIZONTAL RULES
245 | =============================================================================*/
246 |
247 | hr {
248 | clear: both;
249 | margin: 15px 0;
250 | height: 0px;
251 | overflow: hidden;
252 | border: none;
253 | background: transparent;
254 | border-bottom: 4px solid #ddd;
255 | padding: 0;
256 | }
257 |
258 | /* TABLES
259 | =============================================================================*/
260 |
261 | table th {
262 | font-weight: bold;
263 | }
264 |
265 | table th, table td {
266 | border: 1px solid #ccc;
267 | padding: 6px 13px;
268 | }
269 |
270 | table tr {
271 | border-top: 1px solid #ccc;
272 | background-color: #fff;
273 | }
274 |
275 | table tr:nth-child(2n) {
276 | background-color: #f8f8f8;
277 | }
278 |
279 | /* IMAGES
280 | =============================================================================*/
281 |
282 | img {
283 | max-width: 100%
284 | }
285 |
286 | /* FOR JIANSHU
287 | =============================================================================*/
288 |
289 | .image-package {
290 | text-align: center
291 | }
--------------------------------------------------------------------------------
/jianhelper.js:
--------------------------------------------------------------------------------
1 | var cheerio = require('cheerio');
2 | var request = require('sync-request');
3 | var fs = require('fs');
4 | var process = require('process');
5 | var ejs = require('ejs');
6 | var jszip = require('jszip');
7 |
8 | var types = {
9 | unknown: 0,
10 | user: 1,
11 | notebook: 2,
12 | collection: 3
13 | }
14 |
15 | var selectors = {
16 | article: '.title a',
17 | title: 'h1.title',
18 | author: 'a.author-name span',
19 | content: '.show-content'
20 | };
21 |
22 | var url = process.argv[2];
23 | if(!url)
24 | {
25 | showUsage();
26 | process.exit(0);
27 | }
28 |
29 | var startPage = process.argv[3];
30 | startPage = startPage? Number.parseInt(startPage): 1;
31 |
32 | var endPage = process.argv[4];
33 | endPage = endPage? Number.parseInt(endPage): Number.POSITIVE_INFINITY;
34 |
35 |
36 | var urlResult = checkUrl(url);
37 | if(urlResult.type == types.unknown)
38 | {
39 | showUsage();
40 | process.exit(0);
41 | }
42 |
43 | var url = getRealUrl(urlResult.type, urlResult.id, url);
44 | var toc = [];
45 |
46 | console.log('Init path...');
47 | initPath();
48 |
49 | for(var i = startPage; i <= endPage; i++)
50 | {
51 | console.log('page: ' + i.toString())
52 | var pageUrl = url.replace(/\{page\}/, i.toString());
53 | var html;
54 | try {
55 | html = request('GET', pageUrl).getBody().toString();
56 | } catch(ex) { break; }
57 | var li = getList(html);
58 | if(li.length == 0)
59 | break;
60 | for(var j in li)
61 | {
62 | try {
63 | var artUrl = li[j];
64 | var fname = /\/p\/(\w{12})/.exec(artUrl)[1] + '.html';
65 | var html = request('GET', artUrl).getBody().toString();
66 | var co = getContent(html);
67 | fs.writeFileSync('./out/OEBPS/Text/' + fname, co, {encoding: 'utf-8'});
68 | var title = /
(.+?)<\/h1>/.exec(co)[1];
69 | toc.push({file: fname, title: title});
70 | console.log('article: ' + fname + ', title: ' + title);
71 | } catch(ex) { console.log(ex.toString()); }
72 | }
73 | }
74 |
75 | var uuidGenerator = require('./uuid.js');
76 | var uuid = uuidGenerator.uuid();
77 |
78 | console.log('Generate content.opf...')
79 | var contentOpf = getContentOpf(toc, uuid);
80 | fs.writeFileSync('./out/OEBPS/content.opf', contentOpf, {encoding: 'utf-8'})
81 |
82 | console.log('Generate toc.ncx...')
83 | var tocNcx = getTocNcx(toc, uuid);
84 | fs.writeFileSync('./out/OEBPS/toc.ncx', tocNcx, {encoding: 'utf-8'})
85 |
86 | console.log('Gnerate epub...');
87 | generate();
88 |
89 | console.log('Done..');
90 |
91 | function showUsage() {
92 | var usage = "用法:node jianhelper url [start [end]]\n\n" +
93 | " url:支持三种类型\n\n" +
94 | " http://www.jianshu.com/users/{id} 用户\n" +
95 | " http://www.jianshu.com/notebooks/{id} 文集\n" +
96 | " http://www.jianshu.com/collection/{id} 专题\n\n" +
97 | " start:起始页,默认为第一页\n\n" +
98 | " end:终止页,默认为最后一页";
99 | console.log(usage);
100 | }
101 |
102 | function checkUrl(url)
103 | {
104 | var regexes = {
105 | user: /^https?:\/\/www\.jianshu\.com\/users\/(\w{6,12})\/?$/,
106 | notebook: /^https?:\/\/www\.jianshu\.com\/notebooks\/(\d+)\/?$/,
107 | collection: /^https?:\/\/www\.jianshu\.com\/collection\/(\w{6,12})\/?$/
108 | };
109 |
110 | var type = types.unknown;
111 | var id;
112 |
113 | for(var k in regexes)
114 | {
115 | var rms;
116 | if(rms = regexes[k].exec(url))
117 | {
118 | type = types[k];
119 | id = rms[1];
120 | break;
121 | }
122 | }
123 |
124 | return {type: type, id: id};
125 | }
126 |
127 | function getRealUrl(type, id, url)
128 | {
129 | if(type == types.user)
130 | {
131 | return 'http://www.jianshu.com/users/' + id +
132 | '/latest_articles?page={page}';
133 | }
134 | else if(type == types.notebook)
135 | {
136 | return 'http://www.jianshu.com/notebooks/' + id +
137 | '/latest?page={page}';
138 | }
139 | else if(type == types.collection)
140 | {
141 | var content = request('GET', url).getBody().toString();;
142 | var realId = /href="\/collections\/(\d+)\//.exec(content)[1];
143 | return 'http://www.jianshu.com/collections/' + realId +
144 | '/notes?order_by=added_at&page={page}';
145 | }
146 | }
147 |
148 | function getList(html) {
149 |
150 | var $ = cheerio.load(html);
151 |
152 | var $list = $(selectors.article);
153 | var res = [];
154 | for(var i = 0; i < $list.length; i++)
155 | {
156 | var url = $list.eq(i).attr('href');
157 | if(!url.startsWith('http'))
158 | url = 'http://www.jianshu.com' + url;
159 | res.push(url);
160 | }
161 | return res;
162 | }
163 |
164 |
165 | function getContent(html) {
166 | var $ = cheerio.load(html);
167 | dealWithImg($);
168 |
169 | var header = '\r\n\r\n\r\n' +
170 | '' +
171 | '\r\n\r\n';
172 |
173 | var title = '' + $(selectors.title).text() + '
';
174 | var author = '
作者:' + $(selectors.author).text() + '
';
175 | var content = $(selectors.content).html();
176 |
177 | var footer = '\r\n\r\n';
178 |
179 | return header + title + '\n' + author + '\n' + content + footer;
180 | }
181 |
182 | function initPath()
183 | {
184 | if(fs.existsSync('./out') &&
185 | fs.statSync('./out').isDirectory())
186 | rRmDir('./out');
187 | fs.mkdirSync('./out');
188 | fs.mkdirSync('./out/OEBPS');
189 | fs.mkdirSync('./out/OEBPS/Text');
190 | fs.mkdirSync('./out/OEBPS/Images');
191 | //try {fs.mkdirSync('./out/OEBPS/Styles');} catch(ex) {}
192 | //try {fs.mkdirSync('./out/META-INF');} catch(ex) {}
193 | //fs.writeFileSync('./out/META-INF/container.xml', fs.readFileSync('./assets/container.xml'));
194 | //fs.writeFileSync('./out/mimetype', fs.readFileSync('./assets/mimetype'));
195 | //fs.writeFileSync('./out/OEBPS/Styles/Style.css', fs.readFileSync('./assets/Style.css'));
196 | }
197 |
198 | function dealWithImg($)
199 | {
200 | var imgs = $(selectors.content + ' img');
201 | for(var i = 0; i < imgs.length; i++)
202 | {
203 | try {
204 | var img = imgs.eq(i);
205 | var url = img.attr('src');
206 | var co = request('GET', url).getBody();
207 | var fname = /[\w\-]+\.(?:jpg|png|gif)/.exec(url)[0];
208 | console.log('img: ' + fname);
209 | fs.writeFileSync('./out/OEBPS/Images/' + fname, co);
210 | img.attr('src', '../Images/' + fname);
211 | } catch(ex) { console.log(ex.toString()); }
212 | }
213 | }
214 |
215 | function getContentOpf(toc, uuid)
216 | {
217 | var date = new Date();
218 | var dateStr
219 | = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
220 |
221 | return ejs.render(fs.readFileSync('assets/content.ejs', 'utf-8'), {
222 | date: dateStr,
223 | toc: toc,
224 | uuid: uuid
225 | });
226 | }
227 |
228 | function getTocNcx(toc, uuid)
229 | {
230 | return ejs.render(fs.readFileSync('assets/toc.ejs', 'utf-8'), {
231 | toc: toc,
232 | uuid: uuid
233 | });
234 | }
235 |
236 | function generate()
237 | {
238 | var zip = new jszip();
239 | zip.file('mimetype', fs.readFileSync('./assets/mimetype'));
240 | zip.file('META-INF/container.xml', fs.readFileSync('./assets/container.xml'));
241 | zip.file('OEBPS/Styles/Style.css', fs.readFileSync('./assets/Style.css'));
242 | zip.file('OEBPS/content.opf', fs.readFileSync('./out/OEBPS/content.opf'));
243 | zip.file('OEBPS/toc.ncx', fs.readFileSync('./out/OEBPS/toc.ncx'));
244 |
245 | var articles = fs.readdirSync('./out/OEBPS/Text');
246 | for(var i = 0; i < articles.length; i++)
247 | {
248 | var fname = articles[i];
249 | zip.file('OEBPS/Text/' + fname, fs.readFileSync('./out/OEBPS/Text/' + fname));
250 | }
251 |
252 | var images = fs.readdirSync('./out/OEBPS/Images');
253 | for(var i = 0; i < images.length; i++)
254 | {
255 | var fname = images[i];
256 | zip.file('OEBPS/Images/' + fname, fs.readFileSync('./out/OEBPS/Images/' + fname));
257 | }
258 |
259 | fs.writeFileSync('out.epub', zip.generate({type: 'nodebuffer', 'compression':'DEFLATE'}));
260 | }
261 |
262 | function rRmDir(dir)
263 | {
264 | var flist = fs.readdirSync(dir);
265 | for(var i = 0; i < flist.length; i++)
266 | {
267 | var item = dir + '/' + flist[i];
268 | if(fs.statSync(item).isDirectory())
269 | rRmDir(item);
270 | else
271 | fs.unlinkSync(item);
272 | }
273 | fs.rmdirSync(dir);
274 | }
--------------------------------------------------------------------------------