From ee51c470b44fd8532b247d9bfc6bc803e5922289 Mon Sep 17 00:00:00 2001 From: Matthieu Gautier Date: Mon, 26 Mar 2018 18:24:33 +0200 Subject: [PATCH] Allow the manager to dump the opds feed of the whole library. --- include/manager.h | 4 +- include/meson.build | 1 + include/opds_dumper.h | 91 ++++++++++++++++++++++++++++++ src/manager.cpp | 3 +- src/meson.build | 1 + src/opds_dumper.cpp | 127 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 223 insertions(+), 4 deletions(-) create mode 100644 include/opds_dumper.h create mode 100644 src/opds_dumper.cpp diff --git a/include/manager.h b/include/manager.h index 6fb74d220..a2f4ea1c6 100644 --- a/include/manager.h +++ b/include/manager.h @@ -84,7 +84,7 @@ class Manager * @param libraryPath The library path (used to resolve relative path) * @return True if the content has been properly parsed. */ - bool readXml(const string xml, + bool readXml(const string& xml, const bool readOnly = true, const string libraryPath = ""); @@ -97,8 +97,6 @@ class Manager bool writeFile(const string path); - string write_OPDS_feed(const string& id, const string& title); - /** * Remove a book from the library. * diff --git a/include/meson.build b/include/meson.build index 4746d8373..ac79e21ee 100644 --- a/include/meson.build +++ b/include/meson.build @@ -1,6 +1,7 @@ headers = [ 'library.h', 'manager.h', + 'opds_dumper.h', 'reader.h', 'searcher.h' ] diff --git a/include/opds_dumper.h b/include/opds_dumper.h new file mode 100644 index 000000000..b76f7abdc --- /dev/null +++ b/include/opds_dumper.h @@ -0,0 +1,91 @@ +/* + * Copyright 2017 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef KIWIX_OPDS_DUMPER_H +#define KIWIX_OPDS_DUMPER_H + +#include +#include +#include + +#include + +#include "common/base64.h" +#include "common/pathTools.h" +#include "common/regexTools.h" +#include "library.h" +#include "reader.h" + +using namespace std; + +namespace kiwix +{ + +/** + * A tool to dump a `Library` into a opds stream. + * + */ +class OPDSDumper +{ + public: + OPDSDumper(Library library); + ~OPDSDumper(); + + /** + * Dump the OPDS feed. + * + * @param id The id of the library. + * @return The OPDS feed. + */ + std::string dumpOPDSFeed(); + + /** + * Set the id of the opds stream. + * + * @param id the id to use. + */ + void setId(const std::string& id) { this->id = id;} + + /** + * Set the title oft the opds stream. + * + * @param title the title to use. + */ + void setTitle(const std::string& title) { this->title = title; } + + /** + * Set the root location used when generating url. + * + * @param rootLocation the root location to use. + */ + void setRootLocation(const std::string& rootLocation) { this->rootLocation = rootLocation; } + + protected: + kiwix::Library library; + std::string id; + std::string title; + std::string date; + std::string rootLocation; + + private: + pugi::xml_node handleBook(Book book, pugi::xml_node root_node); +}; +} + +#endif // KIWIX_OPDS_DUMPER_H diff --git a/src/manager.cpp b/src/manager.cpp index b0e307c53..4caa57307 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -88,7 +88,7 @@ bool Manager::parseXmlDom(const pugi::xml_document& doc, return true; } -bool Manager::readXml(const string xml, +bool Manager::readXml(const string& xml, const bool readOnly, const string libraryPath) { @@ -231,6 +231,7 @@ bool Manager::writeFile(const string path) return true; } + bool Manager::setCurrentBookId(const string id) { if (library.current.empty() || library.current.top() != id) { diff --git a/src/meson.build b/src/meson.build index 4a1e0266f..e977f2021 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,7 @@ kiwix_sources = [ 'library.cpp', 'manager.cpp', + 'opds_dumper.cpp', 'reader.cpp', 'searcher.cpp', 'common/base64.cpp', diff --git a/src/opds_dumper.cpp b/src/opds_dumper.cpp new file mode 100644 index 000000000..d5db57ebe --- /dev/null +++ b/src/opds_dumper.cpp @@ -0,0 +1,127 @@ +/* + * Copyright 2017 Matthieu Gautier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "opds_dumper.h" + +namespace kiwix +{ +/* Constructor */ +OPDSDumper::OPDSDumper(Library library) + : library(library) +{ +} +/* Destructor */ +OPDSDumper::~OPDSDumper() +{ +} + +struct xml_string_writer: pugi::xml_writer +{ + std::string result; + + virtual void write(const void* data, size_t size) + { + result.append(static_cast(data), size); + } +}; + +std::string node_to_string(pugi::xml_node node) +{ + xml_string_writer writer; + node.print(writer, " "); + + return writer.result; +} + +std::string gen_date_str() +{ + auto now = time(0); + auto tm = localtime(&now); + + std::stringstream is; + is << std::setw(2) << std::setfill('0') + << 1900+tm->tm_year << "-" + << std::setw(2) << std::setfill('0') << tm->tm_mon << "-" + << std::setw(2) << std::setfill('0') << tm->tm_mday << "T" + << std::setw(2) << std::setfill('0') << tm->tm_hour << ":" + << std::setw(2) << std::setfill('0') << tm->tm_min << ":" + << std::setw(2) << std::setfill('0') << tm->tm_sec << "Z"; + return is.str(); +} + +#define ADD_TEXT_ENTRY(node, child, value) (node).append_child((child)).append_child(pugi::node_pcdata).set_value((value).c_str()) + +pugi::xml_node OPDSDumper::handleBook(Book book, pugi::xml_node root_node) { + auto entry_node = root_node.append_child("entry"); + ADD_TEXT_ENTRY(entry_node, "title", book.title); + ADD_TEXT_ENTRY(entry_node, "id", "urn:uuid:"+book.id); + ADD_TEXT_ENTRY(entry_node, "icon", rootLocation + "/meta?name=favicon&content=" + book.getHumanReadableIdFromPath()); + ADD_TEXT_ENTRY(entry_node, "updated", date); + ADD_TEXT_ENTRY(entry_node, "summary", book.description); + + auto content_node = entry_node.append_child("link"); + content_node.append_attribute("type") = "text/html"; + content_node.append_attribute("href") = (rootLocation + "/" + book.getHumanReadableIdFromPath()).c_str(); + + auto author_node = entry_node.append_child("author"); + ADD_TEXT_ENTRY(author_node, "name", book.creator); + + if (! book.url.empty()) { + auto acquisition_link = entry_node.append_child("link"); + acquisition_link.append_attribute("rel") = "http://opds-spec.org/acquisition/open-access"; + acquisition_link.append_attribute("type") = "application/x-zim"; + acquisition_link.append_attribute("href") = book.url.c_str(); + } + + if (! book.faviconMimeType.empty() ) { + auto image_link = entry_node.append_child("link"); + image_link.append_attribute("rel") = "http://opds-spec.org/image/thumbnail"; + image_link.append_attribute("type") = book.faviconMimeType.c_str(); + image_link.append_attribute("href") = (rootLocation + "/meta?name=favicon&content=" + book.getHumanReadableIdFromPath()).c_str(); + } + return entry_node; +} + +string OPDSDumper::dumpOPDSFeed() +{ + date = gen_date_str(); + pugi::xml_document doc; + + auto root_node = doc.append_child("feed"); + root_node.append_attribute("xmlns") = "http://www.w3.org/2005/Atom"; + root_node.append_attribute("xmlns:opds") = "http://opds-spec.org/2010/catalog"; + + ADD_TEXT_ENTRY(root_node, "id", id); + + ADD_TEXT_ENTRY(root_node, "title", title); + ADD_TEXT_ENTRY(root_node, "updated", date); + + auto self_link_node = root_node.append_child("link"); + self_link_node.append_attribute("rel") = "self"; + self_link_node.append_attribute("href") = ""; + self_link_node.append_attribute("type") = "application/atom+xml"; + + for (auto book: library.books) { + handleBook(book, root_node); + } + + return node_to_string(root_node); +} + +}