dongnelibrary 0.2.8 → 0.2.10
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/package.json +7 -5
- package/src/cli.js +103 -133
- package/src/dongnelibrary.js +67 -109
- package/src/http.js +109 -0
- package/src/library/gg.js +60 -60
- package/src/library/gunpo.js +29 -37
- package/src/library/hscity.js +47 -48
- package/src/library/osan.js +90 -82
- package/src/library/snlib.js +64 -57
- package/src/library/suwon.js +69 -99
- package/src/library/yongin.js +182 -0
- package/test/helpers/libraryTestSuite.js +19 -6
- package/test/yongin.spec.js +4 -0
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dongnelibrary",
|
|
3
3
|
"engines": {
|
|
4
|
-
"node": ">=
|
|
4
|
+
"node": ">=18.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.10",
|
|
7
7
|
"description": "책을 빌릴 수 있는지 확인한다.",
|
|
8
8
|
"main": "src/dongnelibrary.js",
|
|
9
9
|
"bin": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"hscity": "mocha test/hscity.spec.js",
|
|
18
18
|
"osan": "mocha test/osan.spec.js",
|
|
19
19
|
"snlib": "mocha test/snlib.spec.js",
|
|
20
|
-
"suwon": "mocha test/suwon.spec.js"
|
|
20
|
+
"suwon": "mocha test/suwon.spec.js",
|
|
21
|
+
"yongin": "mocha test/yongin.spec.js"
|
|
21
22
|
},
|
|
22
23
|
"repository": {
|
|
23
24
|
"type": "git",
|
|
@@ -32,7 +33,8 @@
|
|
|
32
33
|
"성남시도서관",
|
|
33
34
|
"오산시도서관",
|
|
34
35
|
"화성시립도서관",
|
|
35
|
-
"수원시도서관"
|
|
36
|
+
"수원시도서관",
|
|
37
|
+
"용인시도서관"
|
|
36
38
|
],
|
|
37
39
|
"author": "<autoscripts@gmail.com>",
|
|
38
40
|
"license": "MIT",
|
|
@@ -56,6 +58,6 @@
|
|
|
56
58
|
"jquery": "^3.7.1",
|
|
57
59
|
"jsdom": "^21.1.1",
|
|
58
60
|
"lodash": "^4.17.20",
|
|
59
|
-
"
|
|
61
|
+
"undici": "^6.23.0"
|
|
60
62
|
}
|
|
61
63
|
}
|
package/src/cli.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const Configstore = require("configstore");
|
|
3
|
-
const _ = require("lodash");
|
|
4
3
|
const colors = require("colors");
|
|
5
4
|
const figlet = require("figlet");
|
|
6
|
-
const fp = require("lodash/fp");
|
|
7
5
|
const inquirer = require("inquirer");
|
|
8
6
|
const program = require("commander");
|
|
9
7
|
const dl = require("./dongnelibrary");
|
|
@@ -11,11 +9,13 @@ const util = require("./util");
|
|
|
11
9
|
const pkg = require("../package.json");
|
|
12
10
|
|
|
13
11
|
const conf = new Configstore(pkg.name, {});
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
|
|
13
|
+
const config = {
|
|
14
|
+
getLibrary: () => conf.get("library"),
|
|
15
|
+
setLibrary: (name) => conf.set("library", name),
|
|
16
|
+
getTitle: () => conf.get("title") ?? "javascript",
|
|
17
|
+
setTitle: (title) => conf.set("title", title),
|
|
18
|
+
};
|
|
19
19
|
|
|
20
20
|
const introMessage = (msg) => {
|
|
21
21
|
console.log(
|
|
@@ -35,151 +35,121 @@ program
|
|
|
35
35
|
.option("-t, --title [title]", "a part of book title")
|
|
36
36
|
.parse(process.argv);
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
let result = "";
|
|
38
|
+
const cutTail = (str, tail) => {
|
|
40
39
|
const index = str.indexOf(tail);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
return index === -1 ? str : str.substring(0, index);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const MARKS = {
|
|
44
|
+
ok: "✓ ",
|
|
45
|
+
notOk: "✖ ",
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const printBooks = ({ booklist }) => {
|
|
49
|
+
for (const { libraryName, exist, title, bookUrl } of booklist) {
|
|
50
|
+
const mark = exist ? ` ${MARKS.ok} ` : ` ${colors.red(MARKS.notOk)} `;
|
|
51
|
+
console.log(`${cutTail(libraryName, "도서관")}${mark}${title}`);
|
|
52
|
+
if (bookUrl) {
|
|
53
|
+
console.log(` → ${colors.cyan(bookUrl)}`);
|
|
54
|
+
}
|
|
45
55
|
}
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const okMark = "✓ ";
|
|
50
|
-
const notokMark = "✖ ";
|
|
51
|
-
|
|
52
|
-
function printBooks(book) {
|
|
53
|
-
_.each(book.booklist, (book) => {
|
|
54
|
-
console.log(
|
|
55
|
-
cutTail(book.libraryName, "도서관") +
|
|
56
|
-
(book.exist ? " " + okMark + " " : " " + colors.red(notokMark) + " ") +
|
|
57
|
-
book.title +
|
|
58
|
-
" ",
|
|
59
|
-
);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
56
|
+
};
|
|
62
57
|
|
|
63
|
-
|
|
58
|
+
const printAllLibraryNames = () => {
|
|
64
59
|
const libs = dl.getLibraryNames();
|
|
65
|
-
libs.forEach((name) =>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const msg = `모두 ${libs.length} 개의 도서관`;
|
|
69
|
-
console.log(colors.green(msg));
|
|
70
|
-
}
|
|
60
|
+
libs.forEach((name) => console.log(name));
|
|
61
|
+
console.log(colors.green(`모두 ${libs.length} 개의 도서관`));
|
|
62
|
+
};
|
|
71
63
|
|
|
72
64
|
const getFullLibraryName = (str) =>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
function search(option, bookCallback, allBookCallback) {
|
|
76
|
-
dl.search(
|
|
77
|
-
{
|
|
78
|
-
title: option.title,
|
|
79
|
-
libraryName: getLibraries(option.libraryName),
|
|
80
|
-
},
|
|
81
|
-
(err, book) => {
|
|
82
|
-
if (err) {
|
|
83
|
-
err.msg = err.msg || "Unknown Error";
|
|
84
|
-
if (bookCallback) {
|
|
85
|
-
bookCallback(err);
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
if (bookCallback) {
|
|
89
|
-
bookCallback(null, book);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
(err, books) => {
|
|
94
|
-
if (err) {
|
|
95
|
-
err.msg = err.msg || "Unknown Error";
|
|
96
|
-
if (allBookCallback) {
|
|
97
|
-
allBookCallback(err);
|
|
98
|
-
}
|
|
99
|
-
} else {
|
|
100
|
-
if (allBookCallback) {
|
|
101
|
-
allBookCallback(null, books);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
);
|
|
106
|
-
}
|
|
65
|
+
dl.getLibraryNames().find((name) => name.includes(str));
|
|
107
66
|
|
|
108
67
|
const getBookCount = (results) =>
|
|
109
|
-
|
|
110
|
-
results,
|
|
111
|
-
(memo, book) =>
|
|
112
|
-
memo +
|
|
113
|
-
(book && book.booklist && book.booklist.length
|
|
114
|
-
? book.booklist.length
|
|
115
|
-
: 0),
|
|
116
|
-
0,
|
|
117
|
-
);
|
|
68
|
+
results.reduce((sum, book) => sum + (book?.booklist?.length ?? 0), 0);
|
|
118
69
|
|
|
119
|
-
const getLibraryFullNameList =
|
|
120
|
-
util
|
|
121
|
-
|
|
122
|
-
|
|
70
|
+
const getLibraryFullNameList = (libraryName) =>
|
|
71
|
+
util
|
|
72
|
+
.getArrayFromCommaSeparatedString(libraryName)
|
|
73
|
+
.filter((name) => getFullLibraryName(name));
|
|
123
74
|
|
|
124
75
|
const getLibraries = (libraryName) =>
|
|
125
76
|
libraryName ? getLibraryFullNameList(libraryName) : dl.getLibraryNames();
|
|
126
77
|
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
78
|
+
const searchLibraries = ({ title, libraryName }) =>
|
|
79
|
+
new Promise((resolve) => {
|
|
80
|
+
const results = [];
|
|
81
|
+
dl.search(
|
|
82
|
+
{ title, libraryName: getLibraries(libraryName) },
|
|
83
|
+
(err, book) => {
|
|
84
|
+
if (err) {
|
|
85
|
+
console.log(err.msg ?? "Unknown Error");
|
|
86
|
+
} else {
|
|
87
|
+
printBooks(book);
|
|
88
|
+
results.push(book);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
(err, allBooks) => {
|
|
92
|
+
if (err) {
|
|
93
|
+
console.log("Error, Can't access detail information");
|
|
94
|
+
resolve([]);
|
|
95
|
+
} else {
|
|
96
|
+
resolve(allBooks);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const printSearchSummary = (results) => {
|
|
103
|
+
const bookCount = getBookCount(results);
|
|
104
|
+
console.log(
|
|
105
|
+
colors.green(`${results.length} 개의 도서관에서 ${bookCount} 권 검색됨`),
|
|
106
|
+
);
|
|
133
107
|
};
|
|
134
108
|
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
),
|
|
143
|
-
|
|
144
|
-
|
|
109
|
+
const promptForSearchOptions = async () => {
|
|
110
|
+
introMessage("Dongne Library");
|
|
111
|
+
const { library, title } = await inquirer.prompt([
|
|
112
|
+
{
|
|
113
|
+
type: "list",
|
|
114
|
+
name: "library",
|
|
115
|
+
message: "도서관 이름은?",
|
|
116
|
+
choices: dl.getLibraryNames(),
|
|
117
|
+
default: config.getLibrary(),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: "input",
|
|
121
|
+
name: "title",
|
|
122
|
+
message: "책 이름은?",
|
|
123
|
+
default: config.getTitle(),
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
config.setLibrary(library);
|
|
128
|
+
config.setTitle(title);
|
|
129
|
+
|
|
130
|
+
return { libraryName: library, title };
|
|
145
131
|
};
|
|
146
132
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
133
|
+
const activate = async () => {
|
|
134
|
+
const { libraryList, interactive, libraryName, title } = program;
|
|
135
|
+
|
|
136
|
+
if (libraryList) {
|
|
137
|
+
printAllLibraryNames();
|
|
150
138
|
return;
|
|
151
139
|
}
|
|
152
140
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
choices: dl.getLibraryNames(),
|
|
162
|
-
default: getDefaultLibrary(),
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
type: "input",
|
|
166
|
-
name: "title",
|
|
167
|
-
message: "책 이름은?",
|
|
168
|
-
default: getDefaultTitle(),
|
|
169
|
-
},
|
|
170
|
-
])
|
|
171
|
-
.then((answers) => {
|
|
172
|
-
option.libraryName = answers["library"];
|
|
173
|
-
option.title = answers["title"];
|
|
174
|
-
setDefaultLibrary(option.libraryName);
|
|
175
|
-
setDefaultTitle(option.title);
|
|
176
|
-
if (option.libraryName && option.title) {
|
|
177
|
-
search(option, processOneLibrary, processLibraries);
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
} else if (option.libraryName && option.title) {
|
|
181
|
-
search(option, processOneLibrary, processLibraries);
|
|
141
|
+
let searchOptions;
|
|
142
|
+
|
|
143
|
+
if (interactive) {
|
|
144
|
+
searchOptions = await promptForSearchOptions();
|
|
145
|
+
} else if (libraryName && title) {
|
|
146
|
+
searchOptions = { libraryName, title };
|
|
147
|
+
} else {
|
|
148
|
+
return;
|
|
182
149
|
}
|
|
183
|
-
}
|
|
184
150
|
|
|
185
|
-
|
|
151
|
+
const results = await searchLibraries(searchOptions);
|
|
152
|
+
printSearchSummary(results);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
activate();
|
package/src/dongnelibrary.js
CHANGED
|
@@ -1,139 +1,97 @@
|
|
|
1
|
-
const _ = require("lodash");
|
|
2
|
-
const fp = require("lodash/fp");
|
|
3
1
|
const gg = require("./library/gg");
|
|
4
2
|
const gunpo = require("./library/gunpo");
|
|
5
3
|
const hscity = require("./library/hscity");
|
|
6
4
|
const osan = require("./library/osan");
|
|
7
5
|
const snlib = require("./library/snlib");
|
|
8
6
|
const suwon = require("./library/suwon");
|
|
9
|
-
const
|
|
7
|
+
const yongin = require("./library/yongin");
|
|
10
8
|
const util = require("./util.js");
|
|
11
9
|
|
|
12
|
-
const
|
|
10
|
+
const LIBRARY_MODULES = [gg, gunpo, hscity, osan, snlib, suwon, yongin];
|
|
11
|
+
|
|
12
|
+
const libraryList = LIBRARY_MODULES.flatMap((module) =>
|
|
13
|
+
module.getLibraryNames().map((name) => ({
|
|
14
|
+
name,
|
|
15
|
+
search: module.search,
|
|
16
|
+
})),
|
|
17
|
+
);
|
|
13
18
|
|
|
14
19
|
const getLibraryNames = () => util.getLibraryNames(libraryList);
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
const UNKNOWN_LIBRARY = {
|
|
22
|
+
name: "Unknown",
|
|
23
|
+
search: (opt, getBook) => getBook?.({ msg: "Unknown library name" }),
|
|
24
|
+
};
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
libraryList.push({
|
|
22
|
-
name,
|
|
23
|
-
search: library.search,
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
}
|
|
26
|
+
const getLibraryFunction = (libraryName) =>
|
|
27
|
+
libraryList.find((lib) => lib.name === libraryName) ?? UNKNOWN_LIBRARY;
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
return found
|
|
32
|
-
? found
|
|
33
|
-
: {
|
|
34
|
-
search: (opt, getBook) => {
|
|
35
|
-
if (getBook) {
|
|
36
|
-
getBook({ msg: "Unknown library name" });
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
name: "Unknown",
|
|
40
|
-
};
|
|
41
|
-
};
|
|
29
|
+
const completeLibraryName = (str) =>
|
|
30
|
+
getLibraryNames().find((name) => name.includes(str)) ?? "";
|
|
42
31
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return found ? found : "";
|
|
46
|
-
}
|
|
32
|
+
const isValidLibraryName = (libraryName) =>
|
|
33
|
+
libraryList.some((lib) => lib.name === libraryName);
|
|
47
34
|
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
return
|
|
51
|
-
|
|
35
|
+
const getLibArray = (libraryName) => {
|
|
36
|
+
const names = Array.isArray(libraryName) ? libraryName : [libraryName];
|
|
37
|
+
return names
|
|
38
|
+
.map((name) => completeLibraryName(name))
|
|
39
|
+
.filter((fullName) => isValidLibraryName(fullName))
|
|
40
|
+
.map((fullName) => getLibraryFunction(fullName));
|
|
41
|
+
};
|
|
52
42
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return isValidLibraryName(fullName) ? getLibraryFunction(fullName) : null;
|
|
58
|
-
}),
|
|
59
|
-
_.compact,
|
|
60
|
-
])(Array.isArray(libraryName) ? libraryName : [libraryName]);
|
|
61
|
-
}
|
|
43
|
+
const getSortedBooks = (books) =>
|
|
44
|
+
books
|
|
45
|
+
.map(({ libraryName, title, exist, bookUrl }) => ({ libraryName, title, exist, bookUrl }))
|
|
46
|
+
.sort((a, b) => (a.exist === b.exist ? 0 : a.exist ? -1 : 1));
|
|
62
47
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
libraryName:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
48
|
+
const searchLibrary = (lib, title) =>
|
|
49
|
+
new Promise((resolve) => {
|
|
50
|
+
lib.search({ title, libraryName: lib.name }, (err, data) => {
|
|
51
|
+
if (err) {
|
|
52
|
+
resolve({ error: err });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!data?.booklist) {
|
|
56
|
+
resolve({ error: { msg: "invalid Data response" } });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
resolve({
|
|
60
|
+
result: {
|
|
61
|
+
title,
|
|
62
|
+
libraryName: lib.name,
|
|
63
|
+
totalBookCount: data.totalBookCount,
|
|
64
|
+
startPage: data.startPage,
|
|
65
|
+
booklist: getSortedBooks(data.booklist),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
const search = (opt, getBook, getAllBooks) => {
|
|
73
72
|
if (!opt || (!getBook && !getAllBooks)) {
|
|
74
73
|
console.log("invalid search options");
|
|
75
74
|
return;
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
const title = opt
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
_.each(getLibArray(opt.libraryName), (lib) => {
|
|
82
|
-
tasks.push((callback) => {
|
|
83
|
-
lib.search(
|
|
84
|
-
{
|
|
85
|
-
title: title,
|
|
86
|
-
libraryName: lib.name,
|
|
87
|
-
},
|
|
88
|
-
(err, data) => {
|
|
89
|
-
if (err) {
|
|
90
|
-
if (getBook) {
|
|
91
|
-
getBook(err);
|
|
92
|
-
}
|
|
93
|
-
callback(err);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (!data || !data.booklist) {
|
|
97
|
-
if (getBook) {
|
|
98
|
-
getBook({ msg: "invalid Data response" });
|
|
99
|
-
}
|
|
100
|
-
callback({ msg: "invalid Data response" });
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const bookObj = {
|
|
105
|
-
title: title,
|
|
106
|
-
libraryName: lib.name,
|
|
107
|
-
totalBookCount: data.totalBookCount,
|
|
108
|
-
startPage: data.startPage,
|
|
109
|
-
booklist: getSortedBooks(data.booklist),
|
|
110
|
-
};
|
|
77
|
+
const { title, libraryName } = opt;
|
|
78
|
+
const libraries = getLibArray(libraryName);
|
|
111
79
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
);
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
async.parallel(tasks, (err, results) => {
|
|
122
|
-
if (getAllBooks) {
|
|
123
|
-
if (err) {
|
|
124
|
-
getAllBooks(err);
|
|
125
|
-
} else {
|
|
126
|
-
getAllBooks(null, results);
|
|
127
|
-
}
|
|
80
|
+
const promises = libraries.map(async (lib) => {
|
|
81
|
+
const { error, result } = await searchLibrary(lib, title);
|
|
82
|
+
if (error) {
|
|
83
|
+
getBook?.(error);
|
|
84
|
+
return null;
|
|
128
85
|
}
|
|
86
|
+
getBook?.(null, result);
|
|
87
|
+
return result;
|
|
129
88
|
});
|
|
130
|
-
}
|
|
131
89
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
90
|
+
Promise.all(promises).then((results) => {
|
|
91
|
+
const validResults = results.filter(Boolean);
|
|
92
|
+
getAllBooks?.(null, validResults);
|
|
93
|
+
});
|
|
94
|
+
};
|
|
137
95
|
|
|
138
96
|
module.exports = {
|
|
139
97
|
search,
|
package/src/http.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const { request } = require("undici");
|
|
2
|
+
|
|
3
|
+
const DEFAULT_TIMEOUT = 20000;
|
|
4
|
+
const DEFAULT_USER_AGENT =
|
|
5
|
+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
6
|
+
|
|
7
|
+
async function get(url, options = {}) {
|
|
8
|
+
const { qs, headers = {}, timeout = DEFAULT_TIMEOUT } = options;
|
|
9
|
+
|
|
10
|
+
let fullUrl = url;
|
|
11
|
+
if (qs && Object.keys(qs).length > 0) {
|
|
12
|
+
const params = new URLSearchParams();
|
|
13
|
+
for (const [key, value] of Object.entries(qs)) {
|
|
14
|
+
params.append(key, String(value));
|
|
15
|
+
}
|
|
16
|
+
fullUrl = `${url}?${params}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const res = await request(fullUrl, {
|
|
20
|
+
method: "GET",
|
|
21
|
+
headersTimeout: timeout,
|
|
22
|
+
bodyTimeout: timeout,
|
|
23
|
+
headers: { "User-Agent": DEFAULT_USER_AGENT, ...headers },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return { statusCode: res.statusCode, body: await res.body.text() };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function post(url, options = {}) {
|
|
30
|
+
const { form, headers = {}, timeout = DEFAULT_TIMEOUT } = options;
|
|
31
|
+
|
|
32
|
+
const formData = new URLSearchParams();
|
|
33
|
+
if (form) {
|
|
34
|
+
for (const [key, value] of Object.entries(form)) {
|
|
35
|
+
formData.append(key, String(value));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const res = await request(url, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headersTimeout: timeout,
|
|
42
|
+
bodyTimeout: timeout,
|
|
43
|
+
headers: {
|
|
44
|
+
"User-Agent": DEFAULT_USER_AGENT,
|
|
45
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
46
|
+
...headers,
|
|
47
|
+
},
|
|
48
|
+
body: formData.toString(),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return { statusCode: res.statusCode, body: await res.body.text() };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createSession() {
|
|
55
|
+
let cookies = [];
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
async get(url, options = {}) {
|
|
59
|
+
const { headers = {}, timeout = DEFAULT_TIMEOUT } = options;
|
|
60
|
+
|
|
61
|
+
const res = await request(url, {
|
|
62
|
+
method: "GET",
|
|
63
|
+
headersTimeout: timeout,
|
|
64
|
+
bodyTimeout: timeout,
|
|
65
|
+
headers: {
|
|
66
|
+
"User-Agent": DEFAULT_USER_AGENT,
|
|
67
|
+
Cookie: cookies.join("; "),
|
|
68
|
+
...headers,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const setCookie = res.headers["set-cookie"];
|
|
73
|
+
if (setCookie) {
|
|
74
|
+
const newCookies = Array.isArray(setCookie) ? setCookie : [setCookie];
|
|
75
|
+
cookies = [...cookies, ...newCookies.map((c) => c.split(";")[0])];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { statusCode: res.statusCode, body: await res.body.text() };
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async post(url, options = {}) {
|
|
82
|
+
const { form, headers = {}, timeout = DEFAULT_TIMEOUT } = options;
|
|
83
|
+
|
|
84
|
+
const formData = new URLSearchParams();
|
|
85
|
+
if (form) {
|
|
86
|
+
for (const [key, value] of Object.entries(form)) {
|
|
87
|
+
formData.append(key, String(value));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const res = await request(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headersTimeout: timeout,
|
|
94
|
+
bodyTimeout: timeout,
|
|
95
|
+
headers: {
|
|
96
|
+
"User-Agent": DEFAULT_USER_AGENT,
|
|
97
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
98
|
+
Cookie: cookies.join("; "),
|
|
99
|
+
...headers,
|
|
100
|
+
},
|
|
101
|
+
body: formData.toString(),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return { statusCode: res.statusCode, body: await res.body.text() };
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = { get, post, createSession };
|