UNPKG

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