From b2027b397c34d27f318a53661fce094f0b795ab4 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 10 Jun 2021 11:56:51 +0400 Subject: [PATCH 1/9] List of languages entry in /catalog/v2/root.xml Added a new entry in /catalog/v2/root.xml that points to a not-yet-existing list of languages navigation feed. --- src/server/internalServer_catalog_v2.cpp | 3 ++- static/templates/catalog_v2_root.xml | 9 +++++++++ test/server.cpp | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/server/internalServer_catalog_v2.cpp b/src/server/internalServer_catalog_v2.cpp index d4fc9fbef..879d059c2 100644 --- a/src/server/internalServer_catalog_v2.cpp +++ b/src/server/internalServer_catalog_v2.cpp @@ -74,7 +74,8 @@ std::unique_ptr InternalServer::handle_catalog_v2_root(const RequestCo {"endpoint_root", m_root + "/catalog/v2"}, {"feed_id", gen_uuid(m_library_id)}, {"all_entries_feed_id", gen_uuid(m_library_id + "/entries")}, - {"category_list_feed_id", gen_uuid(m_library_id + "/categories")} + {"category_list_feed_id", gen_uuid(m_library_id + "/categories")}, + {"language_list_feed_id", gen_uuid(m_library_id + "/languages")} }, "application/atom+xml;profile=opds-catalog;kind=navigation" ); diff --git a/static/templates/catalog_v2_root.xml b/static/templates/catalog_v2_root.xml index 44db61c13..9aec1cbad 100644 --- a/static/templates/catalog_v2_root.xml +++ b/static/templates/catalog_v2_root.xml @@ -32,4 +32,13 @@ {{category_list_feed_id}} List of all categories in this catalog. + + List of languages + + {{date}} + {{language_list_feed_id}} + List of all languages in this catalog. + diff --git a/test/server.cpp b/test/server.cpp index 749474bbe..6db353234 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -942,6 +942,15 @@ TEST_F(LibraryServerTest, catalog_v2_root) 12345678-90ab-cdef-1234-567890abcdef List of all categories in this catalog. + + List of languages + + YYYY-MM-DDThh:mm:ssZ + 12345678-90ab-cdef-1234-567890abcdef + List of all languages in this catalog. + )"; EXPECT_EQ(maskVariableOPDSFeedData(r->body), expected_output); From 18871b4b15139c26f97a7aa0b0d07b76ec95bf5c Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 10 Jun 2021 12:27:51 +0400 Subject: [PATCH 2/9] Helper function Library::getBookPropValueSet() Introduced a helper function `Library::getBookPropValueSet()` and deduplicated Library::getBooks{Languages,Creators,Publishers}() methods. --- include/library.h | 4 ++++ src/library.cpp | 56 ++++++++++++----------------------------------- test/library.cpp | 22 ++++++++++++++++--- 3 files changed, 37 insertions(+), 45 deletions(-) diff --git a/include/library.h b/include/library.h index c5e026e2f..f1ba7849c 100644 --- a/include/library.h +++ b/include/library.h @@ -341,7 +341,11 @@ class Library friend class OPDSDumper; friend class libXMLDumper; +private: // types + typedef const std::string& (Book::*BookStrPropMemFn)() const; + private: // functions + std::vector getBookPropValueSet(BookStrPropMemFn p) const; BookIdCollection filterViaBookDB(const Filter& filter) const; void updateBookDB(const Book& book); }; diff --git a/src/library.cpp b/src/library.cpp index 3a0f0cd53..6633dce5f 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -208,23 +208,23 @@ bool Library::writeBookmarksToFile(const std::string& path) const return writeTextFile(path, dumper.dumpLibXMLBookmark()); } -std::vector Library::getBooksLanguages() const +std::vector Library::getBookPropValueSet(BookStrPropMemFn p) const { - std::vector booksLanguages; - std::map booksLanguagesMap; + std::set propValues; - for (auto& pair: m_books) { - auto& book = pair.second; - auto& language = book.getLanguage(); - if (booksLanguagesMap.find(language) == booksLanguagesMap.end()) { - if (book.getOrigId().empty()) { - booksLanguagesMap[language] = true; - booksLanguages.push_back(language); - } + for (const auto& pair: m_books) { + const auto& book = pair.second; + if (book.getOrigId().empty()) { + propValues.insert((book.*p)()); } } - return booksLanguages; + return std::vector(propValues.begin(), propValues.end()); +} + +std::vector Library::getBooksLanguages() const +{ + return getBookPropValueSet(&Book::getLanguage); } std::vector Library::getBooksCategories() const @@ -244,40 +244,12 @@ std::vector Library::getBooksCategories() const std::vector Library::getBooksCreators() const { - std::vector booksCreators; - std::map booksCreatorsMap; - - for (auto& pair: m_books) { - auto& book = pair.second; - auto& creator = book.getCreator(); - if (booksCreatorsMap.find(creator) == booksCreatorsMap.end()) { - if (book.getOrigId().empty()) { - booksCreatorsMap[creator] = true; - booksCreators.push_back(creator); - } - } - } - - return booksCreators; + return getBookPropValueSet(&Book::getCreator); } std::vector Library::getBooksPublishers() const { - std::vector booksPublishers; - std::map booksPublishersMap; - - for (auto& pair:m_books) { - auto& book = pair.second; - auto& publisher = book.getPublisher(); - if (booksPublishersMap.find(publisher) == booksPublishersMap.end()) { - if (book.getOrigId().empty()) { - booksPublishersMap[publisher] = true; - booksPublishers.push_back(publisher); - } - } - } - - return booksPublishers; + return getBookPropValueSet(&Book::getPublisher); } const std::vector Library::getBookmarks(bool onlyValidBookmarks) const diff --git a/test/library.cpp b/test/library.cpp index 543f01594..77780ba7b 100644 --- a/test/library.cpp +++ b/test/library.cpp @@ -275,9 +275,25 @@ TEST_F(LibraryTest, getBookMarksTest) TEST_F(LibraryTest, sanityCheck) { EXPECT_EQ(lib.getBookCount(true, true), 12U); - EXPECT_EQ(lib.getBooksLanguages().size(), 3U); - EXPECT_EQ(lib.getBooksCreators().size(), 9U); - EXPECT_EQ(lib.getBooksPublishers().size(), 3U); + EXPECT_EQ(lib.getBooksLanguages(), + std::vector({"deu", "eng", "fra"}) + ); + EXPECT_EQ(lib.getBooksCreators(), std::vector({ + "Islam Stack Exchange", + "Movies & TV Stack Exchange", + "Mythology & Folklore Stack Exchange", + "TED", + "Tania Louis", + "Wiki", + "Wikibooks", + "Wikipedia", + "Wikiquote" + })); + EXPECT_EQ(lib.getBooksPublishers(), std::vector({ + "", + "Kiwix", + "Kiwix & Some Enthusiasts" + })); } TEST_F(LibraryTest, categoryHandling) From 64b55dbdc797c91525698d2705c0de480b45bd4c Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Fri, 11 Jun 2021 12:53:30 +0400 Subject: [PATCH 3/9] Made test library.xml a multi-language library --- test/data/library.xml | 8 ++++---- test/server.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/data/library.xml b/test/data/library.xml index aa9502382..52cd9799b 100644 --- a/test/data/library.xml +++ b/test/data/library.xml @@ -21,11 +21,11 @@ url="https://github.com/kiwix/libkiwix/raw/master/test/data/zimfile.zim" title="Ray (uncategorized) Charles" description="No category is assigned to this library entry." - language="eng" + language="rus" creator="Wikipedia" publisher="Kiwix" date="2020-03-31" - name="wikipedia_en_ray_charles" + name="wikipedia_ru_ray_charles" tags="unittest;wikipedia;_pictures:no;_videos:no;_details:no" articleCount="284" mediaCount="2" @@ -37,11 +37,11 @@ url="https://github.com/kiwix/libkiwix/raw/master/test/data/zimfile.zim" title="Charles, Ray" description="Wikipedia articles about Ray Charles" - language="eng" + language="fra" creator="Wikipedia" publisher="Kiwix" date="2020-03-31" - name="wikipedia_en_ray_charles" + name="wikipedia_fr_ray_charles" tags="unittest;wikipedia;_category:jazz;_pictures:no;_videos:no;_details:no;_ftindex:yes" articleCount="284" mediaCount="2" diff --git a/test/server.cpp b/test/server.cpp index 6db353234..e256f5bb2 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -617,10 +617,10 @@ std::string maskVariableOPDSFeedData(std::string s) " \n" \ " urn:uuid:charlesray\n" \ " Charles, Ray\n" \ - " Wikipedia articles about Ray Charles\n" \ - " eng\n" \ + " Wikipedia articles about Ray Charles\n" \ + " fra\n" \ " YYYY-MM-DDThh:mm:ssZ\n" \ - " wikipedia_en_ray_charles\n" \ + " wikipedia_fr_ray_charles\n" \ " \n" \ " jazz\n" \ " unittest;wikipedia;_category:jazz;_pictures:no;_videos:no;_details:no;_ftindex:yes\n" \ @@ -666,9 +666,9 @@ std::string maskVariableOPDSFeedData(std::string s) " urn:uuid:raycharles_uncategorized\n" \ " Ray (uncategorized) Charles\n" \ " No category is assigned to this library entry.\n" \ - " eng\n" \ + " rus\n" \ " YYYY-MM-DDThh:mm:ssZ\n" \ - " wikipedia_en_ray_charles\n" \ + " wikipedia_ru_ray_charles\n" \ " \n" \ " \n" \ " unittest;wikipedia;_pictures:no;_videos:no;_details:no\n" \ From 5f90f5ee2a746b65d1ca329e3c0e6c17541abe12 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Fri, 11 Jun 2021 12:55:04 +0400 Subject: [PATCH 4/9] Preliminary version of /catalog/v2/languages --- include/opds_dumper.h | 7 ++++ src/opds_dumper.cpp | 46 +++++++++++++++++++++ src/server/internalServer.h | 1 + src/server/internalServer_catalog_v2.cpp | 14 +++++++ static/resources_list.txt | 1 + static/templates/catalog_v2_languages.xml | 25 ++++++++++++ test/server.cpp | 49 +++++++++++++++++++++++ 7 files changed, 143 insertions(+) create mode 100644 static/templates/catalog_v2_languages.xml diff --git a/include/opds_dumper.h b/include/opds_dumper.h index db6026ef8..0a70b65d5 100644 --- a/include/opds_dumper.h +++ b/include/opds_dumper.h @@ -71,6 +71,13 @@ class OPDSDumper */ std::string categoriesOPDSFeed(const std::vector& categories) const; + /** + * Dump the languages OPDS feed. + * + * @return The OPDS feed. + */ + std::string languagesOPDSFeed() const; + /** * Set the id of the library. * diff --git a/src/opds_dumper.cpp b/src/opds_dumper.cpp index 8426a34d1..65ea3c526 100644 --- a/src/opds_dumper.cpp +++ b/src/opds_dumper.cpp @@ -22,6 +22,7 @@ #include "kiwixlib-resources.h" #include +#include #include "tools/stringTools.h" #include "tools/otherTools.h" @@ -83,6 +84,24 @@ BookData getBookData(const Library* library, const std::vector& boo return bookData; } +struct LangInfo { + std::string selfName, englishName; +}; + +std::map langMap = { + {"eng", { "English", "English"} }, + {"fra", { "Français", "French"} }, + {"rus", { "Русский", "Russian"} }, +}; + +std::string getLanguageSelfName(const std::string& lang) { + return langMap.at(lang).selfName; +}; + +std::string getLanguageEnglishName(const std::string& lang) { + return langMap.at(lang).englishName; +}; + } // unnamed namespace string OPDSDumper::dumpOPDSFeed(const std::vector& bookIds, const std::string& query) const @@ -146,4 +165,31 @@ std::string OPDSDumper::categoriesOPDSFeed(const std::vector& categ ); } +std::string OPDSDumper::languagesOPDSFeed() const +{ + const auto now = gen_date_str(); + kainjow::mustache::list languageData; + for ( const auto& languageCode : library->getBooksLanguages() ) { + const auto languageSelfName = getLanguageSelfName(languageCode); + const auto languageEnglishName = getLanguageEnglishName(languageCode); + languageData.push_back(kainjow::mustache::object{ + {"lang_code", languageCode}, + {"lang_self_name", languageSelfName}, + {"lang_english_name", languageEnglishName}, + {"updated", now}, + {"id", gen_uuid(libraryId + "/languages/" + languageCode)} + }); + } + + return render_template( + RESOURCE::templates::catalog_v2_languages_xml, + kainjow::mustache::object{ + {"date", now}, + {"endpoint_root", rootLocation + "/catalog/v2"}, + {"feed_id", gen_uuid(libraryId + "/languages")}, + {"languages", languageData } + } + ); +} + } diff --git a/src/server/internalServer.h b/src/server/internalServer.h index ed40fea9c..f1c813a81 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -77,6 +77,7 @@ class InternalServer { std::unique_ptr handle_catalog_v2_root(const RequestContext& request); std::unique_ptr handle_catalog_v2_entries(const RequestContext& request); std::unique_ptr handle_catalog_v2_categories(const RequestContext& request); + std::unique_ptr handle_catalog_v2_languages(const RequestContext& request); std::unique_ptr handle_meta(const RequestContext& request); std::unique_ptr handle_search(const RequestContext& request); std::unique_ptr handle_suggest(const RequestContext& request); diff --git a/src/server/internalServer_catalog_v2.cpp b/src/server/internalServer_catalog_v2.cpp index 879d059c2..3d79111a3 100644 --- a/src/server/internalServer_catalog_v2.cpp +++ b/src/server/internalServer_catalog_v2.cpp @@ -59,6 +59,8 @@ std::unique_ptr InternalServer::handle_catalog_v2(const RequestContext return handle_catalog_v2_entries(request); } else if (url == "categories") { return handle_catalog_v2_categories(request); + } else if (url == "languages") { + return handle_catalog_v2_languages(request); } else { return Response::build_404(*this, request, "", ""); } @@ -107,4 +109,16 @@ std::unique_ptr InternalServer::handle_catalog_v2_categories(const Req ); } +std::unique_ptr InternalServer::handle_catalog_v2_languages(const RequestContext& request) +{ + OPDSDumper opdsDumper(mp_library); + opdsDumper.setRootLocation(m_root); + opdsDumper.setLibraryId(m_library_id); + return ContentResponse::build( + *this, + opdsDumper.languagesOPDSFeed(), + "application/atom+xml;profile=opds-catalog;kind=navigation" + ); +} + } // namespace kiwix diff --git a/static/resources_list.txt b/static/resources_list.txt index 41552195d..a440e1841 100644 --- a/static/resources_list.txt +++ b/static/resources_list.txt @@ -48,5 +48,6 @@ templates/catalog_entries.xml templates/catalog_v2_root.xml templates/catalog_v2_entries.xml templates/catalog_v2_categories.xml +templates/catalog_v2_languages.xml opensearchdescription.xml catalog_v2_searchdescription.xml diff --git a/static/templates/catalog_v2_languages.xml b/static/templates/catalog_v2_languages.xml new file mode 100644 index 000000000..845d3279e --- /dev/null +++ b/static/templates/catalog_v2_languages.xml @@ -0,0 +1,25 @@ + + + {{feed_id}} + + + List of languages + {{date}} + + {{#languages}} + + {{lang_self_name}} + + {{updated}} + {{id}} + All entries in {{lang_english_name}}. + + {{/languages}} + diff --git a/test/server.cpp b/test/server.cpp index e256f5bb2..7c534b5fa 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -1014,6 +1014,55 @@ TEST_F(LibraryServerTest, catalog_v2_categories) EXPECT_EQ(maskVariableOPDSFeedData(r->body), expected_output); } +TEST_F(LibraryServerTest, catalog_v2_languages) +{ + const auto r = zfs1_->GET("/catalog/v2/languages"); + EXPECT_EQ(r->status, 200); + const char expected_output[] = R"( + + 12345678-90ab-cdef-1234-567890abcdef + + + List of languages + YYYY-MM-DDThh:mm:ssZ + + + English + + YYYY-MM-DDThh:mm:ssZ + 12345678-90ab-cdef-1234-567890abcdef + All entries in English. + + + Français + + YYYY-MM-DDThh:mm:ssZ + 12345678-90ab-cdef-1234-567890abcdef + All entries in French. + + + Русский + + YYYY-MM-DDThh:mm:ssZ + 12345678-90ab-cdef-1234-567890abcdef + All entries in Russian. + + +)"; + EXPECT_EQ(maskVariableOPDSFeedData(r->body), expected_output); +} + #define CATALOG_V2_ENTRIES_PREAMBLE(q) \ "\n" \ " Date: Sun, 13 Jun 2021 23:34:03 +0400 Subject: [PATCH 5/9] Language code in /catalog/v2/languages entries --- static/templates/catalog_v2_languages.xml | 2 ++ test/server.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/static/templates/catalog_v2_languages.xml b/static/templates/catalog_v2_languages.xml index 845d3279e..8fe30bac7 100644 --- a/static/templates/catalog_v2_languages.xml +++ b/static/templates/catalog_v2_languages.xml @@ -1,5 +1,6 @@ {{feed_id}} {{lang_self_name}} + {{{lang_code}}} diff --git a/test/server.cpp b/test/server.cpp index 7c534b5fa..110486198 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -1020,6 +1020,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) EXPECT_EQ(r->status, 200); const char expected_output[] = R"( 12345678-90ab-cdef-1234-567890abcdef English + eng @@ -1042,6 +1044,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) Français + fra @@ -1051,6 +1054,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) Русский + rus From dd118df612dee0603d19fabcf655c8363097caa6 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Sun, 4 Jul 2021 15:28:27 +0400 Subject: [PATCH 6/9] Got rid of langMap in opds_dumper.cpp Language code to human friendly name translation is now done with the help of the ICU library. It works if the line ``` -include $(LANGSRCDIR)/resfiles.mk ``` in the file `source/data/Makefile.in` of the icu4c dependency is not commented out. Currently, the said line is commented out (along with some other include's) by the `icu4c_custom_data.patch` patch of the `kiwix-build` tool. --- src/opds_dumper.cpp | 24 ++++++++++++------------ test/server.cpp | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/opds_dumper.cpp b/src/opds_dumper.cpp index 65ea3c526..68bffbe13 100644 --- a/src/opds_dumper.cpp +++ b/src/opds_dumper.cpp @@ -84,22 +84,22 @@ BookData getBookData(const Library* library, const std::vector& boo return bookData; } -struct LangInfo { - std::string selfName, englishName; -}; - -std::map langMap = { - {"eng", { "English", "English"} }, - {"fra", { "Français", "French"} }, - {"rus", { "Русский", "Russian"} }, -}; - std::string getLanguageSelfName(const std::string& lang) { - return langMap.at(lang).selfName; + const icu::Locale locale(lang.c_str()); + icu::UnicodeString ustring; + locale.getDisplayLanguage(locale, ustring); + std::string result; + ustring.toUTF8String(result); + return result; }; std::string getLanguageEnglishName(const std::string& lang) { - return langMap.at(lang).englishName; + const icu::Locale locale(lang.c_str()); + icu::UnicodeString ustring; + locale.getDisplayLanguage(icu::Locale("en"), ustring); + std::string result; + ustring.toUTF8String(result); + return result; }; } // unnamed namespace diff --git a/test/server.cpp b/test/server.cpp index 110486198..77dd92a6c 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -1043,7 +1043,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) All entries in English. - Français + français fra All entries in French. - Русский + русский rus Date: Thu, 8 Jul 2021 16:14:34 +0400 Subject: [PATCH 7/9] OPDSDumper::categoriesOPDSFeed() with no args --- include/opds_dumper.h | 3 +-- src/opds_dumper.cpp | 4 ++-- src/server/internalServer_catalog_v2.cpp | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/opds_dumper.h b/include/opds_dumper.h index 0a70b65d5..69c74e753 100644 --- a/include/opds_dumper.h +++ b/include/opds_dumper.h @@ -66,10 +66,9 @@ class OPDSDumper /** * Dump the categories OPDS feed. * - * @param categories list of category names * @return The OPDS feed. */ - std::string categoriesOPDSFeed(const std::vector& categories) const; + std::string categoriesOPDSFeed() const; /** * Dump the languages OPDS feed. diff --git a/src/opds_dumper.cpp b/src/opds_dumper.cpp index 68bffbe13..373921686 100644 --- a/src/opds_dumper.cpp +++ b/src/opds_dumper.cpp @@ -140,11 +140,11 @@ string OPDSDumper::dumpOPDSFeedV2(const std::vector& bookIds, const return render_template(RESOURCE::templates::catalog_v2_entries_xml, template_data); } -std::string OPDSDumper::categoriesOPDSFeed(const std::vector& categories) const +std::string OPDSDumper::categoriesOPDSFeed() const { const auto now = gen_date_str(); kainjow::mustache::list categoryData; - for ( const auto& category : categories ) { + for ( const auto& category : library->getBooksCategories() ) { const auto urlencodedCategoryName = urlEncode(category); categoryData.push_back(kainjow::mustache::object{ {"name", category}, diff --git a/src/server/internalServer_catalog_v2.cpp b/src/server/internalServer_catalog_v2.cpp index 3d79111a3..9dc88b49c 100644 --- a/src/server/internalServer_catalog_v2.cpp +++ b/src/server/internalServer_catalog_v2.cpp @@ -104,7 +104,7 @@ std::unique_ptr InternalServer::handle_catalog_v2_categories(const Req opdsDumper.setLibraryId(m_library_id); return ContentResponse::build( *this, - opdsDumper.categoriesOPDSFeed(mp_library->getBooksCategories()), + opdsDumper.categoriesOPDSFeed(), "application/atom+xml;profile=opds-catalog;kind=navigation" ); } From 45adda44b3909a4ac427e7c1fed006a2fbcc1072 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 8 Jul 2021 16:34:02 +0400 Subject: [PATCH 8/9] Got rid of node in languages OPDS entry --- src/opds_dumper.cpp | 11 ----------- static/templates/catalog_v2_languages.xml | 1 - test/server.cpp | 3 --- 3 files changed, 15 deletions(-) diff --git a/src/opds_dumper.cpp b/src/opds_dumper.cpp index 373921686..824033c49 100644 --- a/src/opds_dumper.cpp +++ b/src/opds_dumper.cpp @@ -93,15 +93,6 @@ std::string getLanguageSelfName(const std::string& lang) { return result; }; -std::string getLanguageEnglishName(const std::string& lang) { - const icu::Locale locale(lang.c_str()); - icu::UnicodeString ustring; - locale.getDisplayLanguage(icu::Locale("en"), ustring); - std::string result; - ustring.toUTF8String(result); - return result; -}; - } // unnamed namespace string OPDSDumper::dumpOPDSFeed(const std::vector& bookIds, const std::string& query) const @@ -171,11 +162,9 @@ std::string OPDSDumper::languagesOPDSFeed() const kainjow::mustache::list languageData; for ( const auto& languageCode : library->getBooksLanguages() ) { const auto languageSelfName = getLanguageSelfName(languageCode); - const auto languageEnglishName = getLanguageEnglishName(languageCode); languageData.push_back(kainjow::mustache::object{ {"lang_code", languageCode}, {"lang_self_name", languageSelfName}, - {"lang_english_name", languageEnglishName}, {"updated", now}, {"id", gen_uuid(libraryId + "/languages/" + languageCode)} }); diff --git a/static/templates/catalog_v2_languages.xml b/static/templates/catalog_v2_languages.xml index 8fe30bac7..64e24ac68 100644 --- a/static/templates/catalog_v2_languages.xml +++ b/static/templates/catalog_v2_languages.xml @@ -21,7 +21,6 @@ type="application/atom+xml;profile=opds-catalog;kind=acquisition"/> {{updated}} {{id}} - All entries in {{lang_english_name}}. {{/languages}} diff --git a/test/server.cpp b/test/server.cpp index 77dd92a6c..b2695ab41 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -1040,7 +1040,6 @@ TEST_F(LibraryServerTest, catalog_v2_languages) type="application/atom+xml;profile=opds-catalog;kind=acquisition"/> YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef - All entries in English. français @@ -1050,7 +1049,6 @@ TEST_F(LibraryServerTest, catalog_v2_languages) type="application/atom+xml;profile=opds-catalog;kind=acquisition"/> YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef - All entries in French. русский @@ -1060,7 +1058,6 @@ TEST_F(LibraryServerTest, catalog_v2_languages) type="application/atom+xml;profile=opds-catalog;kind=acquisition"/> YYYY-MM-DDThh:mm:ssZ 12345678-90ab-cdef-1234-567890abcdef - All entries in Russian. )"; From ab3095745e7f6a16ca9ebda5e1c36e2bbc015b0e Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 8 Jul 2021 17:00:54 +0400 Subject: [PATCH 9/9] Languages OPDS feed includes book counts --- include/library.h | 9 +++++++++ src/library.cpp | 21 +++++++++++++++++---- src/opds_dumper.cpp | 5 ++++- static/templates/catalog_v2_languages.xml | 1 + test/server.cpp | 3 +++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/library.h b/include/library.h index f1ba7849c..5c44cd8a2 100644 --- a/include/library.h +++ b/include/library.h @@ -154,6 +154,7 @@ class Library public: typedef std::vector BookIdCollection; + typedef std::map AttributeCounts; public: Library(); @@ -242,6 +243,13 @@ class Library */ std::vector getBooksLanguages() const; + /** + * Get all languagues of the books in the library with counts. + * + * @return A list of languages with the count of books in each language. + */ + AttributeCounts getBooksLanguagesWithCounts() const; + /** * Get all categories of the books in the library. * @@ -345,6 +353,7 @@ class Library typedef const std::string& (Book::*BookStrPropMemFn)() const; private: // functions + AttributeCounts getBookAttributeCounts(BookStrPropMemFn p) const; std::vector getBookPropValueSet(BookStrPropMemFn p) const; BookIdCollection filterViaBookDB(const Filter& filter) const; void updateBookDB(const Book& book); diff --git a/src/library.cpp b/src/library.cpp index 6633dce5f..1882574d6 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -208,18 +208,26 @@ bool Library::writeBookmarksToFile(const std::string& path) const return writeTextFile(path, dumper.dumpLibXMLBookmark()); } -std::vector Library::getBookPropValueSet(BookStrPropMemFn p) const +Library::AttributeCounts Library::getBookAttributeCounts(BookStrPropMemFn p) const { - std::set propValues; + AttributeCounts propValueCounts; for (const auto& pair: m_books) { const auto& book = pair.second; if (book.getOrigId().empty()) { - propValues.insert((book.*p)()); + propValueCounts[(book.*p)()] += 1; } } + return propValueCounts; +} - return std::vector(propValues.begin(), propValues.end()); +std::vector Library::getBookPropValueSet(BookStrPropMemFn p) const +{ + std::vector result; + for ( const auto& kv : getBookAttributeCounts(p) ) { + result.push_back(kv.first); + } + return result; } std::vector Library::getBooksLanguages() const @@ -227,6 +235,11 @@ std::vector Library::getBooksLanguages() const return getBookPropValueSet(&Book::getLanguage); } +Library::AttributeCounts Library::getBooksLanguagesWithCounts() const +{ + return getBookAttributeCounts(&Book::getLanguage); +} + std::vector Library::getBooksCategories() const { std::set categories; diff --git a/src/opds_dumper.cpp b/src/opds_dumper.cpp index 824033c49..440272c30 100644 --- a/src/opds_dumper.cpp +++ b/src/opds_dumper.cpp @@ -160,11 +160,14 @@ std::string OPDSDumper::languagesOPDSFeed() const { const auto now = gen_date_str(); kainjow::mustache::list languageData; - for ( const auto& languageCode : library->getBooksLanguages() ) { + for ( const auto& langAndBookCount : library->getBooksLanguagesWithCounts() ) { + const std::string languageCode = langAndBookCount.first; + const int bookCount = langAndBookCount.second; const auto languageSelfName = getLanguageSelfName(languageCode); languageData.push_back(kainjow::mustache::object{ {"lang_code", languageCode}, {"lang_self_name", languageSelfName}, + {"book_count", to_string(bookCount)}, {"updated", now}, {"id", gen_uuid(libraryId + "/languages/" + languageCode)} }); diff --git a/static/templates/catalog_v2_languages.xml b/static/templates/catalog_v2_languages.xml index 64e24ac68..8a5b74cce 100644 --- a/static/templates/catalog_v2_languages.xml +++ b/static/templates/catalog_v2_languages.xml @@ -16,6 +16,7 @@ {{lang_self_name}} {{{lang_code}}} + {{book_count}} diff --git a/test/server.cpp b/test/server.cpp index b2695ab41..f900cd938 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -1035,6 +1035,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) English eng + 1 @@ -1044,6 +1045,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) français fra + 1 @@ -1053,6 +1055,7 @@ TEST_F(LibraryServerTest, catalog_v2_languages) русский rus + 1