1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.serverOPDS_browse_v1 = exports.serverOPDS_browse_v1_PATH = void 0;
|
4 | var tslib_1 = require("tslib");
|
5 | var debug_ = require("debug");
|
6 | var express = require("express");
|
7 | var morgan = require("morgan");
|
8 | var request = require("request");
|
9 | var requestPromise = require("request-promise-native");
|
10 | var xmldom = require("xmldom");
|
11 | var opds_1 = require("r2-opds-js/dist/es5/src/opds/opds1/opds");
|
12 | var opds_entry_1 = require("r2-opds-js/dist/es5/src/opds/opds1/opds-entry");
|
13 | var UrlUtils_1 = require("r2-utils-js/dist/es5/src/_utils/http/UrlUtils");
|
14 | var BufferUtils_1 = require("r2-utils-js/dist/es5/src/_utils/stream/BufferUtils");
|
15 | var xml_js_mapper_1 = require("r2-utils-js/dist/es5/src/_utils/xml-js-mapper");
|
16 | var request_ext_1 = require("./request-ext");
|
17 | var server_lcp_lsd_show_1 = require("./server-lcp-lsd-show");
|
18 | var server_trailing_slash_redirect_1 = require("./server-trailing-slash-redirect");
|
19 | var server_url_1 = require("./server-url");
|
20 | var debug = debug_("r2:streamer#http/server-opds-browse-v1");
|
21 | exports.serverOPDS_browse_v1_PATH = "/opds-v1-browse";
|
22 | function serverOPDS_browse_v1(_server, topRouter) {
|
23 | var _this = this;
|
24 | var routerOPDS_browse_v1 = express.Router({ strict: false });
|
25 | routerOPDS_browse_v1.use(morgan("combined", { stream: { write: function (msg) { return debug(msg); } } }));
|
26 | routerOPDS_browse_v1.use(server_trailing_slash_redirect_1.trailingSlashRedirect);
|
27 | routerOPDS_browse_v1.get("/", function (_req, res) {
|
28 | var html = "<html><head>";
|
29 | html += "<script type=\"text/javascript\">function encodeURIComponent_RFC3986(str) { " +
|
30 | "return encodeURIComponent(str).replace(/[!'()*]/g, (c) => { " +
|
31 | "return \"%\" + c.charCodeAt(0).toString(16); }); }" +
|
32 | "function go(evt) {" +
|
33 | "if (evt) { evt.preventDefault(); } var url = " +
|
34 | "location.origin +" +
|
35 | (" '" + exports.serverOPDS_browse_v1_PATH + "/' +") +
|
36 | " encodeURIComponent_RFC3986(document.getElementById(\"url\").value);" +
|
37 | "location.href = url;}</script>";
|
38 | html += "</head>";
|
39 | html += "<body><h1>OPDS feed browser</h1>";
|
40 | html += "<form onsubmit=\"go();return false;\">" +
|
41 | "<input type=\"text\" name=\"url\" id=\"url\" size=\"80\">" +
|
42 | "<input type=\"submit\" value=\"Go!\"></form>";
|
43 | html += "</body></html>";
|
44 | res.status(200).send(html);
|
45 | });
|
46 | routerOPDS_browse_v1.param("urlEncoded", function (req, _res, next, value, _name) {
|
47 | req.urlEncoded = value;
|
48 | next();
|
49 | });
|
50 | routerOPDS_browse_v1.get("/:" + request_ext_1._urlEncoded + "(*)", function (req, res) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
51 | var reqparams, urlDecoded, failure, success, headers, needsStreamingResponse, response, err_1;
|
52 | var _this = this;
|
53 | return tslib_1.__generator(this, function (_a) {
|
54 | switch (_a.label) {
|
55 | case 0:
|
56 | reqparams = req.params;
|
57 | if (!reqparams.urlEncoded) {
|
58 | reqparams.urlEncoded = req.urlEncoded;
|
59 | }
|
60 | urlDecoded = reqparams.urlEncoded;
|
61 | debug(urlDecoded);
|
62 | failure = function (err) {
|
63 | debug(err);
|
64 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
65 | + err + "</p></body></html>");
|
66 | };
|
67 | success = function (response) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
68 | function processEntry(entry) {
|
69 | html += "<hr/>";
|
70 | html += "<div>";
|
71 | if (opds) {
|
72 | html += "<h3>" + entry.Title + "</h3>";
|
73 | }
|
74 | if (entry.Summary) {
|
75 | if (!entry.SummaryType || entry.SummaryType === "text") {
|
76 | html += "<strong>" + entry.Summary + "</strong>";
|
77 | }
|
78 | else if (entry.SummaryType === "html") {
|
79 | html += "<div>" + entry.Summary + "</div>";
|
80 | }
|
81 | html += "<br/>";
|
82 | }
|
83 | if (entry.Content) {
|
84 | if (!entry.ContentType || entry.ContentType === "text") {
|
85 | html += "<strong>" + entry.Content + "</strong>";
|
86 | }
|
87 | else if (entry.ContentType === "html") {
|
88 | html += "<div>" + entry.Content + "</div>";
|
89 | }
|
90 | html += "<br/>";
|
91 | }
|
92 | if (entry.Links && entry.Links.length) {
|
93 | var image_1;
|
94 | var imageThumbnail_1;
|
95 | var epub_1;
|
96 | entry.Links.forEach(function (link) {
|
97 | if (link.Type === "application/epub+zip") {
|
98 | epub_1 = link.Href;
|
99 | }
|
100 | if (link.HasRel("http://opds-spec.org/image")
|
101 | || link.HasRel("x-stanza-cover-image")) {
|
102 | image_1 = link.Href;
|
103 | }
|
104 | if (link.HasRel("http://opds-spec.org/image/thumbnail")
|
105 | || link.HasRel("http://opds-spec.org/thumbnail")
|
106 | || link.HasRel("x-stanza-cover-image-thumbnail")) {
|
107 | imageThumbnail_1 = link.Href;
|
108 | }
|
109 | if (opds && link.Type &&
|
110 | (link.Type.indexOf("opds-catalog") >= 0 || link.Type === "application/atom+xml")) {
|
111 | var linkUrl = UrlUtils_1.ensureAbsolute(urlDecoded, link.Href);
|
112 | var opdsUrl = req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v1_PATH + "/"))
|
113 | + exports.serverOPDS_browse_v1_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(linkUrl);
|
114 | html += "<a href='" + opdsUrl
|
115 | + "'>" + link.Href + "</a> (TITLE: " + link.Title
|
116 | + ") [REL: " + link.Rel + "]<br/>";
|
117 | }
|
118 | else if (opds && link.Type &&
|
119 | (link.Type === "application/vnd.readium.lcp.license.v1.0+json")) {
|
120 | var linkUrl = UrlUtils_1.ensureAbsolute(urlDecoded, link.Href);
|
121 | var opdsUrl = req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v1_PATH + "/"))
|
122 | + server_lcp_lsd_show_1.serverLCPLSD_show_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(linkUrl);
|
123 | html += "<a href='" + opdsUrl
|
124 | + "'>" + link.Href + "</a> (TITLE: " + link.Title
|
125 | + ") [REL: " + link.Rel + "]<br/>";
|
126 | }
|
127 | });
|
128 | if (imageThumbnail_1) {
|
129 | var imageThumbnailUrl = UrlUtils_1.ensureAbsolute(urlDecoded, imageThumbnail_1);
|
130 | if (image_1) {
|
131 | var imageUrl = UrlUtils_1.ensureAbsolute(urlDecoded, image_1);
|
132 | html += "<a href='" + imageUrl + "'><img src='"
|
133 | + imageThumbnailUrl + "' alt='' /></a><br/>";
|
134 | }
|
135 | else {
|
136 | html += "<img src='" + imageThumbnailUrl + "' alt='' /><br/>";
|
137 | }
|
138 | }
|
139 | else if (image_1) {
|
140 | var imageUrl = UrlUtils_1.ensureAbsolute(urlDecoded, image_1);
|
141 | html += "<img src='" + imageUrl + "' alt='' /><br/>";
|
142 | }
|
143 | if (epub_1) {
|
144 | var epub_ = UrlUtils_1.ensureAbsolute(urlDecoded, epub_1);
|
145 | var epubUrl = req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v1_PATH + "/"))
|
146 | + server_url_1.serverRemotePub_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(epub_);
|
147 | html += "<strong><a href='" + epubUrl + "'>" + epub_1 + "</a></strong>";
|
148 | }
|
149 | }
|
150 | html += "</div>";
|
151 | }
|
152 | var responseData, err_2, responseStr, responseXml, isEntry, opds, opdsEntry, html, iconUrl, links;
|
153 | return tslib_1.__generator(this, function (_a) {
|
154 | switch (_a.label) {
|
155 | case 0:
|
156 | if (response.statusCode && (response.statusCode < 200 || response.statusCode >= 300)) {
|
157 | failure("HTTP CODE " + response.statusCode);
|
158 | return [2];
|
159 | }
|
160 | _a.label = 1;
|
161 | case 1:
|
162 | _a.trys.push([1, 3, , 4]);
|
163 | return [4, BufferUtils_1.streamToBufferPromise(response)];
|
164 | case 2:
|
165 | responseData = _a.sent();
|
166 | return [3, 4];
|
167 | case 3:
|
168 | err_2 = _a.sent();
|
169 | debug(err_2);
|
170 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
171 | + err_2 + "</p></body></html>");
|
172 | return [2];
|
173 | case 4:
|
174 | responseStr = responseData.toString("utf8");
|
175 | responseXml = new xmldom.DOMParser().parseFromString(responseStr);
|
176 | if (!responseXml || !responseXml.documentElement) {
|
177 | res.status(500).send("<html><body><p>Internal Server Error</p><p>"
|
178 | + "XML parse fail" + "</p></body></html>");
|
179 | return [2];
|
180 | }
|
181 | isEntry = responseXml.documentElement.localName === "entry";
|
182 | if (isEntry) {
|
183 | opdsEntry = xml_js_mapper_1.XML.deserialize(responseXml, opds_entry_1.Entry);
|
184 | }
|
185 | else {
|
186 | opds = xml_js_mapper_1.XML.deserialize(responseXml, opds_1.OPDS);
|
187 | }
|
188 | html = "<html><head>";
|
189 | html += "</head>";
|
190 | html += "<body><h1>" + urlDecoded + "</h1>";
|
191 | if (opds && opds.Title) {
|
192 | html += "<h2>" + opds.Title + "</h2>";
|
193 | }
|
194 | if (opdsEntry && opdsEntry.Title) {
|
195 | html += "<h2>" + opdsEntry.Title + "</h2>";
|
196 | }
|
197 | if (opds && opds.Icon) {
|
198 | iconUrl = UrlUtils_1.ensureAbsolute(urlDecoded, opds.Icon);
|
199 | html += "<img src='" + iconUrl + "' alt='' />";
|
200 | }
|
201 | links = opds ? opds.Links : (opdsEntry ? opdsEntry.Links : undefined);
|
202 | if (links && links.length) {
|
203 | html += "<p>";
|
204 | links.forEach(function (link) {
|
205 | if (link.Type &&
|
206 | (link.Type.indexOf("opds-catalog") >= 0 || link.Type === "application/atom+xml")) {
|
207 | var linkUrl = UrlUtils_1.ensureAbsolute(urlDecoded, link.Href);
|
208 | var opdsUrl = req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v1_PATH + "/"))
|
209 | + exports.serverOPDS_browse_v1_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(linkUrl);
|
210 | html += "<a href='" + opdsUrl
|
211 | + "'>" + link.Href + "</a> (TITLE: " + link.Title
|
212 | + ") [REL: " + link.Rel + "]<br/>";
|
213 | }
|
214 | });
|
215 | html += "</p>";
|
216 | }
|
217 | if (opds && opds.Entries && opds.Entries.length) {
|
218 | opds.Entries.forEach(function (entry) {
|
219 | processEntry(entry);
|
220 | });
|
221 | }
|
222 | if (opdsEntry) {
|
223 | processEntry(opdsEntry);
|
224 | }
|
225 | html += "</body></html>";
|
226 | res.status(200).send(html);
|
227 | return [2];
|
228 | }
|
229 | });
|
230 | }); };
|
231 | headers = {
|
232 | "Accept": "application/json,application/xml",
|
233 | "Accept-Language": "en-UK,en-US;q=0.7,en;q=0.5",
|
234 | "User-Agent": "READIUM2",
|
235 | };
|
236 | needsStreamingResponse = true;
|
237 | if (!needsStreamingResponse) return [3, 1];
|
238 | request.get({
|
239 | headers: headers,
|
240 | method: "GET",
|
241 | uri: urlDecoded,
|
242 | })
|
243 | .on("response", success)
|
244 | .on("error", failure);
|
245 | return [3, 7];
|
246 | case 1:
|
247 | response = void 0;
|
248 | _a.label = 2;
|
249 | case 2:
|
250 | _a.trys.push([2, 4, , 5]);
|
251 | return [4, requestPromise({
|
252 | headers: headers,
|
253 | method: "GET",
|
254 | resolveWithFullResponse: true,
|
255 | uri: urlDecoded,
|
256 | })];
|
257 | case 3:
|
258 | response = _a.sent();
|
259 | return [3, 5];
|
260 | case 4:
|
261 | err_1 = _a.sent();
|
262 | failure(err_1);
|
263 | return [2];
|
264 | case 5: return [4, success(response)];
|
265 | case 6:
|
266 | _a.sent();
|
267 | _a.label = 7;
|
268 | case 7: return [2];
|
269 | }
|
270 | });
|
271 | }); });
|
272 | topRouter.use(exports.serverOPDS_browse_v1_PATH, routerOPDS_browse_v1);
|
273 | }
|
274 | exports.serverOPDS_browse_v1 = serverOPDS_browse_v1;
|
275 |
|
\ | No newline at end of file |