UNPKG

10.9 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.serverOPDS_local_feed = exports.serverOPDS_local_feed_PATH_ = exports.serverOPDS_local_feed_PATH = void 0;
4var crypto = require("crypto");
5var css2json = require("css2json");
6var debug_ = require("debug");
7var DotProp = require("dot-prop");
8var express = require("express");
9var jsonMarkup = require("json-markup");
10var path = require("path");
11var serializable_1 = require("r2-lcp-js/dist/es5/src/serializable");
12var opds2_link_1 = require("r2-opds-js/dist/es5/src/opds/opds2/opds2-link");
13var UrlUtils_1 = require("r2-utils-js/dist/es5/src/_utils/http/UrlUtils");
14var JsonUtils_1 = require("r2-utils-js/dist/es5/src/_utils/JsonUtils");
15var json_schema_validate_1 = require("../utils/json-schema-validate");
16var request_ext_1 = require("./request-ext");
17var server_trailing_slash_redirect_1 = require("./server-trailing-slash-redirect");
18var debug = debug_("r2:streamer#http/server-opds-local-feed");
19exports.serverOPDS_local_feed_PATH = "/opds2";
20exports.serverOPDS_local_feed_PATH_ = "/publications.json";
21function serverOPDS_local_feed(server, topRouter) {
22 var jsonStyle = "\n.json-markup {\n line-height: 17px;\n font-size: 13px;\n font-family: monospace;\n white-space: pre;\n}\n.json-markup-key {\n font-weight: bold;\n}\n.json-markup-bool {\n color: firebrick;\n}\n.json-markup-string {\n color: green;\n}\n.json-markup-null {\n color: gray;\n}\n.json-markup-number {\n color: blue;\n}\n";
23 var routerOPDS_local_feed = express.Router({ strict: false });
24 routerOPDS_local_feed.get(["/", "/" + request_ext_1._show + "/:" + request_ext_1._jsonPath + "?"], function (req, res) {
25 var reqparams = req.params;
26 var isShow = req.url.indexOf("/show") >= 0 || req.query.show;
27 if (!reqparams.jsonPath && req.query.show) {
28 reqparams.jsonPath = req.query.show;
29 }
30 var isCanonical = req.query.canonical &&
31 req.query.canonical === "true";
32 var isSecureHttp = req.secure ||
33 req.protocol === "https" ||
34 req.get("X-Forwarded-Proto") === "https";
35 var rootUrl = (isSecureHttp ? "https://" : "http://")
36 + req.headers.host;
37 var selfURL = rootUrl + exports.serverOPDS_local_feed_PATH + exports.serverOPDS_local_feed_PATH_;
38 var feed = server.publicationsOPDS();
39 if (!feed) {
40 var err = "Publications OPDS2 feed not available yet, try again later.";
41 debug(err);
42 res.status(503).send("<html><body><p>Resource temporarily unavailable</p><p>"
43 + err + "</p></body></html>");
44 return;
45 }
46 if (!feed.findFirstLinkByRel("self")) {
47 feed.Links = [];
48 var selfLink = new opds2_link_1.OPDSLink();
49 selfLink.Href = selfURL;
50 selfLink.TypeLink = "application/opds+json";
51 selfLink.AddRel("self");
52 feed.Links.push(selfLink);
53 }
54 function absoluteURL(href) {
55 return rootUrl + "/pub/" + href;
56 }
57 function absolutizeURLs(jsonObj) {
58 JsonUtils_1.traverseJsonObjects(jsonObj, function (obj) {
59 if (obj.href && typeof obj.href === "string") {
60 if (!UrlUtils_1.isHTTP(obj.href)) {
61 obj.href = absoluteURL(obj.href);
62 }
63 if (isShow &&
64 (obj.type === "application/webpub+json"
65 || obj.type === "application/audiobook+json"
66 || obj.type === "application/divina+json") &&
67 obj.rel === "http://opds-spec.org/acquisition" &&
68 obj.href.endsWith("/manifest.json")) {
69 obj.href += "/show";
70 }
71 }
72 });
73 }
74 if (isShow) {
75 var objToSerialize = null;
76 if (reqparams.jsonPath) {
77 switch (reqparams.jsonPath) {
78 case "all": {
79 objToSerialize = feed;
80 break;
81 }
82 case "metadata": {
83 objToSerialize = feed.Metadata;
84 break;
85 }
86 case "links": {
87 objToSerialize = feed.Links;
88 break;
89 }
90 case "publications": {
91 objToSerialize = feed.Publications;
92 break;
93 }
94 default: {
95 objToSerialize = null;
96 }
97 }
98 }
99 else {
100 objToSerialize = feed;
101 }
102 if (!objToSerialize) {
103 objToSerialize = {};
104 }
105 var jsonObj = serializable_1.TaJsonSerialize(objToSerialize);
106 var validationStr = void 0;
107 var doValidate = !reqparams.jsonPath || reqparams.jsonPath === "all";
108 if (doValidate) {
109 var jsonSchemasRootpath = path.join(process.cwd(), "misc", "json-schema");
110 var jsonSchemasNames = [
111 "opds/feed",
112 "opds/publication",
113 "opds/acquisition-object",
114 "opds/catalog-entry",
115 "opds/feed-metadata",
116 "opds/properties",
117 "webpub-manifest/publication",
118 "webpub-manifest/contributor-object",
119 "webpub-manifest/contributor",
120 "webpub-manifest/link",
121 "webpub-manifest/metadata",
122 "webpub-manifest/subcollection",
123 "webpub-manifest/properties",
124 "webpub-manifest/subject",
125 "webpub-manifest/subject-object",
126 "webpub-manifest/extensions/epub/metadata",
127 "webpub-manifest/extensions/epub/subcollections",
128 "webpub-manifest/extensions/epub/properties",
129 "webpub-manifest/extensions/presentation/metadata",
130 "webpub-manifest/extensions/presentation/properties",
131 "webpub-manifest/language-map",
132 ];
133 var validationErrors = json_schema_validate_1.jsonSchemaValidate(jsonSchemasRootpath, jsonSchemasNames, jsonObj);
134 if (validationErrors) {
135 validationStr = "";
136 for (var _i = 0, validationErrors_1 = validationErrors; _i < validationErrors_1.length; _i++) {
137 var err = validationErrors_1[_i];
138 debug("JSON Schema validation FAIL.");
139 debug(err);
140 var val = DotProp.get(jsonObj, err.jsonPath);
141 var valueStr = (typeof val === "string") ?
142 "" + val :
143 ((val instanceof Array || typeof val === "object") ?
144 "" + JSON.stringify(val) :
145 "");
146 debug(valueStr);
147 var title = "";
148 var pubIndex = "";
149 if (/^publications\.[0-9]+/.test(err.jsonPath)) {
150 var jsonPubTitlePath = err.jsonPath.replace(/^(publications\.[0-9]+).*/, "$1.metadata.title");
151 debug(jsonPubTitlePath);
152 title = DotProp.get(jsonObj, jsonPubTitlePath);
153 debug(title);
154 pubIndex = err.jsonPath.replace(/^publications\.([0-9]+).*/, "$1");
155 debug(pubIndex);
156 }
157 validationStr +=
158 "\n___________INDEX___________ #" + pubIndex + " \"" + title + "\"\n\n" + err.ajvMessage + ": " + valueStr + "\n\n'" + err.ajvDataPath.replace(/^\./, "") + "' (" + err.ajvSchemaPath + ")\n\n";
159 }
160 }
161 }
162 absolutizeURLs(jsonObj);
163 if (jsonObj.publications && jsonObj.publications.length) {
164 var i_1 = 0;
165 jsonObj.publications.forEach(function (pub) {
166 pub.___________INDEX___________ = i_1++;
167 });
168 }
169 var jsonPretty = jsonMarkup(jsonObj, css2json(jsonStyle));
170 res.status(200).send("<html><body>" +
171 "<h1>OPDS2 JSON feed</h1>" +
172 "<hr><p><pre>" + jsonPretty + "</pre></p>" +
173 (doValidate ? (validationStr ? ("<hr><p><pre>" + validationStr + "</pre></p>") : ("<hr><p>JSON SCHEMA OK.</p>")) : "") +
174 "</body></html>");
175 }
176 else {
177 server.setResponseCORS(res);
178 res.set("Content-Type", "application/opds+json; charset=utf-8");
179 var publicationsJsonObj = serializable_1.TaJsonSerialize(feed);
180 absolutizeURLs(publicationsJsonObj);
181 var publicationsJsonStr = isCanonical ?
182 global.JSON.stringify(JsonUtils_1.sortObject(publicationsJsonObj), null, "") :
183 global.JSON.stringify(publicationsJsonObj, null, " ");
184 var checkSum = crypto.createHash("sha256");
185 checkSum.update(publicationsJsonStr);
186 var hash = checkSum.digest("hex");
187 var match = req.header("If-None-Match");
188 if (match === hash) {
189 debug("opds2 publications.json cache");
190 res.status(304);
191 res.end();
192 return;
193 }
194 res.setHeader("ETag", hash);
195 res.status(200).send(publicationsJsonStr);
196 }
197 });
198 var routerOPDS_local_feed_ = express.Router({ strict: false });
199 routerOPDS_local_feed_.use(server_trailing_slash_redirect_1.trailingSlashRedirect);
200 routerOPDS_local_feed_.get("/", function (req, res) {
201 var i = req.originalUrl.indexOf("?");
202 var pathWithoutQuery = req.originalUrl;
203 if (i >= 0) {
204 pathWithoutQuery = pathWithoutQuery.substr(0, i);
205 }
206 var redirect = pathWithoutQuery +
207 exports.serverOPDS_local_feed_PATH_ + "/show";
208 redirect = redirect.replace("//", "/");
209 if (i >= 0) {
210 redirect += req.originalUrl.substr(i);
211 }
212 debug("REDIRECT: " + req.originalUrl + " ==> " + redirect);
213 res.redirect(301, redirect);
214 });
215 routerOPDS_local_feed_.use(exports.serverOPDS_local_feed_PATH_, routerOPDS_local_feed);
216 topRouter.use(exports.serverOPDS_local_feed_PATH, routerOPDS_local_feed_);
217}
218exports.serverOPDS_local_feed = serverOPDS_local_feed;
219//# sourceMappingURL=server-opds-local-feed.js.map
\No newline at end of file