/* * Copyright 2011 Emmanuel Engelhart * * 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 "library.h" #include "book.h" #include "libxml_dumper.h" #include "tools/base64.h" #include "tools/regexTools.h" #include "tools/pathTools.h" #include #include #include namespace kiwix { /* Constructor */ Library::Library() { } /* Destructor */ Library::~Library() { } bool Library::addBook(const Book& book) { /* Try to find it */ try { auto& oldbook = m_books.at(book.getId()); oldbook.update(book); return false; } catch (std::out_of_range&) { m_books[book.getId()] = book; return true; } } void Library::addBookmark(const Bookmark& bookmark) { m_bookmarks.push_back(bookmark); } bool Library::removeBookmark(const std::string& zimId, const std::string& url) { for(auto it=m_bookmarks.begin(); it!=m_bookmarks.end(); it++) { if (it->getBookId() == zimId && it->getUrl() == url) { m_bookmarks.erase(it); return true; } } return false; } bool Library::removeBookById(const std::string& id) { return m_books.erase(id) == 1; } Book& Library::getBookById(const std::string& id) { return m_books.at(id); } unsigned int Library::getBookCount(const bool localBooks, const bool remoteBooks) { unsigned int result = 0; for (auto& pair: m_books) { auto& book = pair.second; if ((!book.getPath().empty() && localBooks) || (book.getPath().empty() && remoteBooks)) { result++; } } return result; } bool Library::writeToFile(const std::string& path) { auto baseDir = removeLastPathElement(path, true, false); LibXMLDumper dumper(this); dumper.setBaseDir(baseDir); return writeTextFile(path, dumper.dumpLibXMLContent(getBooksIds())); } bool Library::writeBookmarksToFile(const std::string& path) { LibXMLDumper dumper(this); return writeTextFile(path, dumper.dumpLibXMLBookmark()); } std::vector Library::getBooksLanguages() { std::vector booksLanguages; std::map booksLanguagesMap; 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); } } } return booksLanguages; } std::vector Library::getBooksCreators() { 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; } std::vector Library::getBooksPublishers() { 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; } std::vector Library::getBooksIds() { std::vector bookIds; for (auto& pair: m_books) { bookIds.push_back(pair.first); } return bookIds; } std::vector Library::filter(const std::string& search) { if (search.empty()) { return getBooksIds(); } std::vector bookIds; for(auto& pair:m_books) { auto& book = pair.second; if (matchRegex(book.getTitle(), "\\Q" + search + "\\E") || matchRegex(book.getDescription(), "\\Q" + search + "\\E")) { bookIds.push_back(pair.first); } } return bookIds; } template struct Comparator { Library* lib; Comparator(Library* lib) : lib(lib) {} bool operator() (const std::string& id1, const std::string& id2) { return get_keys(id1) < get_keys(id2); } std::string get_keys(const std::string& id); unsigned int get_keyi(const std::string& id); }; template<> std::string Comparator::get_keys(const std::string& id) { return lib->getBookById(id).getTitle(); } template<> unsigned int Comparator<SIZE>::get_keyi(const std::string& id) { return lib->getBookById(id).getSize(); } template<> bool Comparator<SIZE>::operator() (const std::string& id1, const std::string& id2) { return get_keyi(id1) < get_keyi(id2); } template<> std::string Comparator<DATE>::get_keys(const std::string& id) { return lib->getBookById(id).getDate(); } template<> std::string Comparator<CREATOR>::get_keys(const std::string& id) { return lib->getBookById(id).getCreator(); } template<> std::string Comparator<PUBLISHER>::get_keys(const std::string& id) { return lib->getBookById(id).getPublisher(); } std::vector<std::string> Library::listBooksIds( int mode, supportedListSortBy sortBy, const std::string& search, const std::string& language, const std::string& creator, const std::string& publisher, const std::vector<std::string>& tags, size_t maxSize) { std::vector<std::string> bookIds; for(auto& pair:m_books) { auto& book = pair.second; auto local = !book.getPath().empty(); if (mode & LOCAL && !local) continue; if (mode & NOLOCAL && local) continue; auto valid = book.isPathValid(); if (mode & VALID && !valid) continue; if (mode & NOVALID && valid) continue; auto remote = !book.getUrl().empty(); if (mode & REMOTE && !remote) continue; if (mode & NOREMOTE && remote) continue; if (!tags.empty()) { auto vBookTags = split(book.getTags(), ";"); std::set<std::string> sBookTags(vBookTags.begin(), vBookTags.end()); bool ok = true; for (auto& t: tags) { if (sBookTags.find(t) == sBookTags.end()) { // A "filter" tag is not in the book tag. // No need to loop for all "filter" tags. ok = false; break; } } if (! ok ) { // Skip the book continue; } } if (maxSize != 0 && book.getSize() > maxSize) continue; if (!language.empty() && book.getLanguage() != language) continue; if (!publisher.empty() && book.getPublisher() != publisher) continue; if (!creator.empty() && book.getCreator() != creator) continue; if (!search.empty() && !(matchRegex(book.getTitle(), "\\Q" + search + "\\E") || matchRegex(book.getDescription(), "\\Q" + search + "\\E"))) continue; bookIds.push_back(pair.first); } switch(sortBy) { case TITLE: std::sort(bookIds.begin(), bookIds.end(), Comparator<TITLE>(this)); break; case SIZE: std::sort(bookIds.begin(), bookIds.end(), Comparator<SIZE>(this)); break; case DATE: std::sort(bookIds.begin(), bookIds.end(), Comparator<DATE>(this)); break; case CREATOR: std::sort(bookIds.begin(), bookIds.end(), Comparator<CREATOR>(this)); break; case PUBLISHER: std::sort(bookIds.begin(), bookIds.end(), Comparator<PUBLISHER>(this)); break; default: break; } return bookIds; } }