opds-web-client
Version:
334 lines (333 loc) • 11.5 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.feedToCollection = exports.entryToBook = exports.adapter = void 0;
var opds_feed_parser_1 = require("opds-feed-parser");
var sanitizeHtml;
var createDOMPurify = require("dompurify");
if (typeof window === "undefined") {
// sanitization needs to work server-side,
// so we use jsdom to build it a window object
var JSDOM = require("jsdom").JSDOM;
var jsdom = new JSDOM("<!doctype html><html><body></body></html>", {
url: "http://localhost",
FetchExternalResources: false,
ProcessExternalResources: false
});
var window_1 = jsdom.window;
var defaultView = window_1.defaultView;
sanitizeHtml = createDOMPurify(defaultView).sanitize;
}
else {
sanitizeHtml = createDOMPurify(window).sanitize;
}
/** Converts OPDS data into the internal representation used by components. */
function adapter(data, url) {
if (data instanceof opds_feed_parser_1.OPDSFeed) {
var collectionData = feedToCollection(data, url);
return collectionData;
}
else if (data instanceof opds_feed_parser_1.OPDSEntry) {
var bookData = entryToBook(data, url);
return bookData;
}
else {
throw "parsed data must be OPDSFeed or OPDSEntry";
}
}
exports.adapter = adapter;
function entryToBook(entry, feedUrl) {
var authors = entry.authors.map(function (author) {
return author.name;
});
var contributors = entry.contributors.map(function (contributor) {
return contributor.name;
});
var imageUrl, imageThumbLink;
var artworkLinks = entry.links.filter(function (link) {
return link instanceof opds_feed_parser_1.OPDSArtworkLink;
});
if (artworkLinks.length > 0) {
imageThumbLink = artworkLinks.find(function (link) { return link.rel === "http://opds-spec.org/image/thumbnail"; });
if (imageThumbLink) {
imageUrl = imageThumbLink.href;
}
else {
console.log("WARNING: using possibly large image for " + entry.title);
imageUrl = artworkLinks[0].href;
}
}
var detailUrl;
var detailLink = entry.links.find(function (link) { return link instanceof opds_feed_parser_1.CompleteEntryLink; });
if (detailLink) {
detailUrl = detailLink.href;
}
var categories = entry.categories
.filter(function (category) { return !!category.label; })
.map(function (category) { return category.label; });
var openAccessLinks = entry.links
.filter(function (link) {
return (link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
link.rel === opds_feed_parser_1.OPDSAcquisitionLink.OPEN_ACCESS_REL);
})
.map(function (link) {
return {
url: link.href,
type: link.type
};
});
var borrowUrl;
var borrowLink = entry.links.find(function (link) {
return (link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
link.rel === opds_feed_parser_1.OPDSAcquisitionLink.BORROW_REL);
});
if (borrowLink) {
borrowUrl = borrowLink.href;
}
var allBorrowLinks = entry.links
.filter(function (link) {
return (link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
link.rel === opds_feed_parser_1.OPDSAcquisitionLink.BORROW_REL);
})
.map(function (link) {
var indirectType;
var indirects = link.indirectAcquisitions;
if (indirects && indirects.length > 0) {
indirectType = indirects[0].type;
}
return {
url: link.href,
type: link.type,
indirectType: indirectType
};
});
var fulfillmentType;
var fulfillmentLinks = entry.links
.filter(function (link) {
return (link instanceof opds_feed_parser_1.OPDSAcquisitionLink &&
link.rel === opds_feed_parser_1.OPDSAcquisitionLink.GENERIC_REL);
})
.map(function (link) {
var indirectType;
var indirects = link.indirectAcquisitions;
if (indirects && indirects.length > 0) {
indirectType = indirects[0].type;
}
return {
url: link.href,
type: link.type,
indirectType: indirectType
};
});
var availability;
var holds;
var copies;
var linkWithAvailability = entry.links.find(function (link) {
return link instanceof opds_feed_parser_1.OPDSAcquisitionLink && !!link.availability;
});
if (linkWithAvailability) {
(availability = linkWithAvailability.availability, holds = linkWithAvailability.holds, copies = linkWithAvailability.copies);
}
return {
id: entry.id,
title: entry.title,
series: entry.series,
authors: authors,
contributors: contributors,
subtitle: entry.subtitle,
summary: entry.summary.content && sanitizeHtml(entry.summary.content),
imageUrl: imageUrl,
openAccessLinks: openAccessLinks,
borrowUrl: borrowUrl,
allBorrowLinks: allBorrowLinks,
fulfillmentLinks: fulfillmentLinks,
availability: availability,
holds: holds,
copies: copies,
publisher: entry.publisher,
published: entry.issued && formatDate(entry.issued),
categories: categories,
language: entry.language,
url: detailUrl,
raw: entry.unparsed
};
}
exports.entryToBook = entryToBook;
function entryToLink(entry, feedUrl) {
var links = entry.links;
if (links.length > 0) {
var href = links[0].href;
return {
id: entry.id,
text: entry.title,
url: href
};
}
console.error("Attempting to create Link with undefined url. entry is: ", entry);
return null;
}
function dedupeBooks(books) {
// using Map because it preserves key order
var bookIndex = books.reduce(function (index, book) {
index.set(book.id, book);
return index;
}, new Map());
return Array.from(bookIndex.values());
}
function formatDate(inputDate) {
var monthNames = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
var date = new Date(inputDate);
var day = date.getUTCDate();
var monthIndex = date.getUTCMonth();
var month = monthNames[monthIndex];
var year = date.getUTCFullYear();
return "".concat(month, " ").concat(day, ", ").concat(year);
}
function OPDSLinkToLinkData(feedUrl, link) {
if (link === void 0) { link = {}; }
if (!link || !link.href) {
return null;
}
return {
url: link.href,
text: link.title,
type: link.rel
};
}
function feedToCollection(feed, feedUrl) {
var collection = {
id: feed.id,
title: feed.title,
url: feedUrl
};
var books = [];
var navigationLinks = [];
var lanes = [];
var laneTitles = [];
var laneIndex = [];
var facetGroups = [];
var search = undefined;
var nextPageUrl = undefined;
var catalogRootLink = undefined;
var parentLink = undefined;
var shelfUrl = undefined;
var links = [];
feed.entries.forEach(function (entry) {
if (feed instanceof opds_feed_parser_1.AcquisitionFeed) {
var book = entryToBook(entry, feedUrl);
var collectionLink = entry.links.find(function (link) { return link instanceof opds_feed_parser_1.OPDSCollectionLink; });
if (collectionLink) {
var title = collectionLink.title, href = collectionLink.href;
if (laneIndex[title]) {
laneIndex[title].books.push(book);
}
else {
laneIndex[title] = {
title: title,
url: href,
books: [book]
};
// use array of titles to preserve lane order
laneTitles.push(title);
}
}
else {
books.push(book);
}
}
else {
var link = entryToLink(entry, feedUrl);
if (link)
navigationLinks.push(link);
}
});
lanes = laneTitles.reduce(function (result, title) {
var lane = laneIndex[title];
lane.books = dedupeBooks(lane.books);
result.push(lane);
return result;
}, lanes);
var facetLinks = [];
if (feed.links) {
facetLinks = feed.links.filter(function (link) {
return link instanceof opds_feed_parser_1.OPDSFacetLink;
});
var searchLink = feed.links.find(function (link) {
return link instanceof opds_feed_parser_1.SearchLink;
});
if (searchLink) {
search = { url: searchLink.href };
}
var nextPageLink = feed.links.find(function (link) {
return link.rel === "next";
});
if (nextPageLink) {
nextPageUrl = nextPageLink.href;
}
catalogRootLink = feed.links.find(function (link) {
return link instanceof opds_feed_parser_1.OPDSCatalogRootLink;
});
parentLink = feed.links.find(function (link) { return link.rel === "up"; });
var shelfLink = feed.links.find(function (link) { return link instanceof opds_feed_parser_1.OPDSShelfLink; });
if (shelfLink) {
shelfUrl = shelfLink.href;
}
links = feed.links;
}
facetGroups = facetLinks.reduce(function (result, link) {
var groupLabel = link.facetGroup;
var label = link.title;
var href = link.href;
var active = link.activeFacet;
var facet = { label: label, href: href, active: active };
var newResult = [];
var foundGroup = false;
result.forEach(function (group) {
if (group.label === groupLabel) {
var facets = group.facets.concat(facet);
newResult.push({ label: groupLabel, facets: facets });
foundGroup = true;
}
else {
newResult.push(group);
}
});
if (!foundGroup) {
var facets = [facet];
newResult.push({ label: groupLabel, facets: facets });
}
return newResult;
}, []);
collection.lanes = lanes;
collection.navigationLinks = navigationLinks;
collection.books = dedupeBooks(books);
collection.facetGroups = facetGroups;
collection.search = search;
collection.nextPageUrl = nextPageUrl;
collection.catalogRootLink = OPDSLinkToLinkData(feedUrl, catalogRootLink);
collection.parentLink = OPDSLinkToLinkData(feedUrl, parentLink);
collection.shelfUrl = shelfUrl;
function notNull(value) {
return value !== null && value !== undefined;
}
collection.links = links
.map(function (link) { return OPDSLinkToLinkData(feedUrl, link); })
// we have to filter out the null values in order for typescript to accept this
.filter(notNull);
collection.raw = feed.unparsed;
Object.freeze(collection);
return collection;
}
exports.feedToCollection = feedToCollection;
;