Merge pull request #960 from kiwix/opdsLanguages

OPDS based languages and categories
This commit is contained in:
Kelson 2023-08-02 14:50:41 +02:00 committed by GitHub
commit 7c4cd1d412
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 196 additions and 257 deletions

View File

@ -72,7 +72,6 @@ SOURCES += \
src/fullscreenwindow.cpp \
src/fullscreennotification.cpp \
src/zimview.cpp \
src/static_content.cpp
HEADERS += \
src/contentmanagerdelegate.h \
@ -115,7 +114,6 @@ HEADERS += \
src/fullscreennotification.h \
src/menuproxystyle.h \
src/zimview.h \
src/static_content.h
FORMS += \
src/contentmanagerview.ui \

View File

@ -1,7 +1,6 @@
#include "contentmanager.h"
#include "kiwixapp.h"
#include "static_content.h"
#include <kiwix/manager.h>
#include <kiwix/tools.h>
@ -68,6 +67,10 @@ ContentManager::ContentManager(Library* library, kiwix::Downloader* downloader,
connect(mp_view->getView(), SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onCustomContextMenu(const QPoint &)));
connect(this, &ContentManager::pendingRequest, mp_view, &ContentManagerView::showLoader);
connect(treeView, &QTreeView::doubleClicked, this, &ContentManager::openBookWithIndex);
connect(&m_remoteLibraryManager, &OpdsRequestManager::languagesReceived, this, &ContentManager::updateLanguages);
connect(&m_remoteLibraryManager, &OpdsRequestManager::categoriesReceived, this, &ContentManager::updateCategories);
setCategories();
setLanguages();
}
QList<QMap<QString, QVariant>> ContentManager::getBooksList()
@ -143,6 +146,8 @@ void ContentManager::setLocal(bool local) {
}
m_local = local;
emit(filterParamsChanged());
setCategories();
setLanguages();
}
QStringList ContentManager::getTranslations(const QStringList &keys)
@ -155,6 +160,40 @@ QStringList ContentManager::getTranslations(const QStringList &keys)
return translations;
}
void ContentManager::setCategories()
{
QStringList categories;
if (m_local) {
auto categoryData = mp_library->getKiwixLibrary().getBooksCategories();
categories.push_back("all");
for (auto category : categoryData) {
auto categoryName = QString::fromStdString(category);
categories.push_back(categoryName);
}
m_categories = categories;
emit(categoriesLoaded(m_categories));
return;
}
m_remoteLibraryManager.getCategoriesFromOpds();
}
void ContentManager::setLanguages()
{
LanguageList languages;
if (m_local) {
auto languageData = mp_library->getKiwixLibrary().getBooksLanguages();
for (auto language : languageData) {
auto langCode = QString::fromStdString(language);
auto selfName = QString::fromStdString(kiwix::getLanguageSelfName(language));
languages.push_back({langCode, selfName});
}
m_languages = languages;
emit(languagesLoaded(m_languages));
return;
}
m_remoteLibraryManager.getLanguagesFromOpds();
}
#define ADD_V(KEY, METH) {if(key==KEY) values.insert(key, QString::fromStdString((b->METH())));}
QMap<QString, QVariant> ContentManager::getBookInfos(QString id, const QStringList &keys)
{
@ -544,6 +583,8 @@ void ContentManager::setCurrentLanguage(QString language)
kiwix::converta2toa3(language.toStdString()));
} catch (std::out_of_range&) {}
}
if (m_currentLanguage == language)
return;
m_currentLanguage = language;
emit(currentLangChanged());
emit(filterParamsChanged());
@ -551,6 +592,8 @@ void ContentManager::setCurrentLanguage(QString language)
void ContentManager::setCurrentCategoryFilter(QString category)
{
if (m_categoryFilter == category)
return;
m_categoryFilter = category.toLower();
emit(filterParamsChanged());
}
@ -585,6 +628,29 @@ void ContentManager::updateRemoteLibrary(const QString& content) {
});
}
void ContentManager::updateLanguages(const QString& content) {
auto languages = kiwix::readLanguagesFromFeed(content.toStdString());
LanguageList tempLanguages;
for (auto language : languages) {
auto code = QString::fromStdString(language.first);
auto title = QString::fromStdString(language.second);
tempLanguages.push_back({code, title});
}
m_languages = tempLanguages;
emit(languagesLoaded(m_languages));
}
void ContentManager::updateCategories(const QString& content) {;
auto categories = kiwix::readCategoriesFromFeed(content.toStdString());
QStringList tempCategories;
tempCategories.push_back("all");
for (auto catg : categories) {
tempCategories.push_back(QString::fromStdString(catg));
}
m_categories = tempCategories;
emit(categoriesLoaded(m_categories));
}
void ContentManager::setSearch(const QString &search)
{
m_searchQuery = search;
@ -599,9 +665,9 @@ QStringList ContentManager::getBookIds()
acceptTags.push_back("_category:"+m_categoryFilter.toStdString());
}
if (m_categoryFilter == "other") {
for (auto& category: S_CATEGORIES) {
if (category.first != "other" && category.first != "all") {
rejectTags.push_back("_category:"+category.first.toStdString());
for (auto& category: m_categories) {
if (category != "other" && category != "all") {
rejectTags.push_back("_category:"+category.toStdString());
}
}
}

View File

@ -18,6 +18,7 @@ class ContentManager : public QObject
Q_PROPERTY(QString currentLanguage MEMBER m_currentLanguage WRITE setCurrentLanguage NOTIFY currentLangChanged)
public:
typedef QList<QPair<QString, QString>> LanguageList;
explicit ContentManager(Library* library, kiwix::Downloader *downloader, QObject *parent = nullptr);
virtual ~ContentManager() {}
@ -28,6 +29,8 @@ public:
void setCurrentCategoryFilter(QString category);
void setCurrentContentTypeFilter(QList<ContentTypeFilter*>& contentTypeFilter);
bool isLocal() const { return m_local; }
QStringList getCategories() const { return m_categories; }
LanguageList getLanguages() const { return m_languages; }
private:
Library* mp_library;
@ -42,12 +45,16 @@ private:
QList<ContentTypeFilter*> m_contentTypeFilters;
kiwix::supportedListSortBy m_sortBy = kiwix::UNSORTED;
bool m_sortOrderAsc = true;
LanguageList m_languages;
QStringList m_categories;
QStringList getBookIds();
void eraseBookFilesFromComputer(const QString dirPath, const QString filename);
QList<QMap<QString, QVariant>> getBooksList();
ContentManagerModel *managerModel;
QMutex remoteLibraryLocker;
void setCategories();
void setLanguages();
signals:
void filterParamsChanged();
@ -57,6 +64,8 @@ signals:
void downloadsChanged();
void currentLangChanged();
void pendingRequest(const bool);
void categoriesLoaded(QStringList);
void languagesLoaded(LanguageList);
public slots:
QStringList getTranslations(const QStringList &keys);
@ -70,6 +79,8 @@ public slots:
void setSortBy(const QString& sortBy, const bool sortOrderAsc);
void eraseBook(const QString& id);
void updateRemoteLibrary(const QString& content);
void updateLanguages(const QString& content);
void updateCategories(const QString& content);
void pauseBook(const QString& id);
void resumeBook(const QString& id);
void cancelBook(const QString& id);

View File

@ -3,9 +3,9 @@
#include "kiwixapp.h"
#include <QLocale>
#include <QDebug>
#include "klistwidgetitem.h"
#include "static_content.h"
ContentManagerSide::ContentManagerSide(QWidget *parent) :
QWidget(parent),
@ -91,39 +91,10 @@ ContentManagerSide::ContentManagerSide(QWidget *parent) :
});
}
for(auto lang: S_LANGUAGES)
{
auto currentLang = QLocale().language();
auto locale = QLocale(lang);
if (locale.language() != lang) {
// Qt may not find the locale for the lang :/
// In this case, Qt return the current locale
// So we must be sure that the locale found correspond to the lang we want to add,
// else we may add several time the current language.
continue;
}
auto item = new KListWidgetItem(QLocale::languageToString(locale.language()));
item->setData(Qt::UserRole, lang);
mp_languageSelector->addItem(item);
if (lang == currentLang) {
item->setSelected(true);
}
}
mp_languageSelector->sortItems();
auto item = new KListWidgetItem("All");
item->setData(Qt::UserRole, QLocale::AnyLanguage);
mp_languageSelector->insertItem(0, item);
for (auto category: S_CATEGORIES)
{
auto item = new KListWidgetItem(category.second);
item->setData(Qt::UserRole, category.first);
mp_categorySelector->addItem(item);
if (category.first == "all")
{
item->setSelected(true);
}
}
setCategories(KiwixApp::instance()->getContentManager()->getCategories());
setLanguages(KiwixApp::instance()->getContentManager()->getLanguages());
connect(KiwixApp::instance()->getContentManager(), &ContentManager::categoriesLoaded, this, &ContentManagerSide::setCategories);
connect(KiwixApp::instance()->getContentManager(), &ContentManager::languagesLoaded, this, &ContentManagerSide::setLanguages);
}
ContentManagerSide::~ContentManagerSide()
@ -138,14 +109,12 @@ void ContentManagerSide::setContentManager(ContentManager *contentManager)
this, [=]() {
auto item = mp_languageSelector->selectedItems().at(0);
if (!item) return;
auto langId = item->data(Qt::UserRole).toInt();
auto lang = QLocale::Language(langId);
if (lang == QLocale::AnyLanguage) {
auto lang = item->data(Qt::UserRole).toString();
if (lang == "all") {
mp_contentManager->setCurrentLanguage("*");
return;
}
auto locale = QLocale(lang);
mp_contentManager->setCurrentLanguage(locale.name().split("_").at(0));
mp_contentManager->setCurrentLanguage(lang);
});
connect(mp_categorySelector, &QListWidget::itemSelectionChanged,
this, [=]() {
@ -155,3 +124,50 @@ void ContentManagerSide::setContentManager(ContentManager *contentManager)
mp_contentManager->setCurrentCategoryFilter(category);
});
}
QString beautify(QString word)
{
word = word.replace("_", " ");
word[0] = word[0].toUpper();
return word;
}
void ContentManagerSide::setCategories(QStringList categories)
{
mp_categorySelector->blockSignals(true);
mp_categorySelector->setHidden(true);
mp_categorySelector->clear();
mp_categorySelector->blockSignals(false);
for (auto category: categories)
{
auto item = new KListWidgetItem(beautify(category));
item->setData(Qt::UserRole, category);
mp_categorySelector->addItem(item);
if (category == "all")
{
item->setSelected(true);
}
}
}
void ContentManagerSide::setLanguages(ContentManager::LanguageList langList)
{
mp_languageSelector->blockSignals(true);
mp_languageSelector->setHidden(true);
mp_languageSelector->clear();
mp_languageSelector->blockSignals(false);
for(auto lang: langList)
{
auto currentLang = QLocale().language();
auto item = new KListWidgetItem(lang.second);
item->setData(Qt::UserRole, lang.first);
mp_languageSelector->addItem(item);
if (lang.second == QLocale::languageToString(currentLang)) {
item->setSelected(true);
}
}
mp_languageSelector->sortItems();
auto item = new KListWidgetItem("All");
item->setData(Qt::UserRole, "all");
mp_languageSelector->insertItem(0, item);
}

View File

@ -30,6 +30,10 @@ private:
QListWidget* mp_categorySelector;
QCheckBox* mp_contentTypeButton;
QList<ContentTypeFilter*> m_contentTypeFilters;
public slots:
void setCategories(QStringList);
void setLanguages(ContentManager::LanguageList);
};
#endif // CONTENTMANAGERSIDE_H

View File

@ -1,5 +1,4 @@
#include "kiwixapp.h"
#include "static_content.h"
#include "zim/error.h"
#include "zim/version.h"
#include "kiwix/tools.h"
@ -66,8 +65,6 @@ void KiwixApp::init()
}
mp_manager = new ContentManager(&m_library, mp_downloader);
initStaticContent();
auto icon = QIcon();
icon.addFile(":/icons/kiwix-app-icons-square.svg");
setWindowIcon(icon);

View File

@ -1,9 +1,7 @@
#include "opdsrequestmanager.h"
#include "static_content.h"
#include "kiwixapp.h"
OpdsRequestManager::OpdsRequestManager()
: mp_reply(nullptr)
{
}
@ -31,37 +29,71 @@ void OpdsRequestManager::doUpdate(const QString& currentLanguage, const QString&
// Add "special negative" filter for "other" category (if necessary)
if (categoryFilter == "other") {
for (auto& category: S_CATEGORIES) {
if (category.first != "other" && category.first != "all") {
excludeTags += "_category:"+category.first;
for (auto& category: KiwixApp::instance()->getContentManager()->getCategories()) {
if (category != "other" && category != "all") {
excludeTags += "_category:"+category;
}
}
}
query.addQueryItem("notag", excludeTags.join(";"));
auto mp_reply = opdsResponseFromPath("/catalog/search", query);
connect(mp_reply, &QNetworkReply::finished, this, [=]() {
receiveContent(mp_reply);
});
}
QNetworkReply* OpdsRequestManager::opdsResponseFromPath(const QString &path, const QUrlQuery &query)
{
QUrl url;
url.setScheme("https");
url.setHost(CATALOG_HOST);
url.setPort(CATALOG_PORT);
url.setPath("/catalog/search");
url.setPath(path);
url.setQuery(query);
qInfo() << "Downloading" << url.toString(QUrl::FullyEncoded);
QNetworkRequest request(url);
if (mp_reply) {
mp_reply->abort();
}
mp_reply = m_networkManager.get(request);
connect(mp_reply, &QNetworkReply::finished, this, &OpdsRequestManager::receiveContent);
return m_networkManager.get(request);
}
void OpdsRequestManager::receiveContent()
void OpdsRequestManager::getLanguagesFromOpds()
{
auto mp_reply = opdsResponseFromPath("/catalog/v2/languages");
connect(mp_reply, &QNetworkReply::finished, this, [=]() {
receiveLanguages(mp_reply);
});
}
void OpdsRequestManager::getCategoriesFromOpds()
{
auto mp_reply = opdsResponseFromPath("/catalog/v2/categories");
connect(mp_reply, &QNetworkReply::finished, this, [=]() {
receiveCategories(mp_reply);
});
}
QString replyContent(QNetworkReply *mp_reply)
{
QString content;
if (mp_reply->error() != QNetworkReply::OperationCanceledError) {
QString content = mp_reply->readAll().data();
emit(requestReceived(content));
content = mp_reply->readAll().data();
}
mp_reply->deleteLater();
mp_reply = nullptr;
return content;
}
void OpdsRequestManager::receiveLanguages(QNetworkReply *mp_reply)
{
emit(languagesReceived(replyContent(mp_reply)));
}
void OpdsRequestManager::receiveCategories(QNetworkReply *mp_reply)
{
emit(categoriesReceived(replyContent(mp_reply)));
}
void OpdsRequestManager::receiveContent(QNetworkReply *mp_reply)
{
emit(requestReceived(replyContent(mp_reply)));
}

View File

@ -16,16 +16,22 @@ public:
public:
void doUpdate(const QString& currentLanguage, const QString& categoryFilter);
void getLanguagesFromOpds();
void getCategoriesFromOpds();
private:
QNetworkAccessManager m_networkManager;
QNetworkReply *mp_reply;
QNetworkReply* opdsResponseFromPath(const QString &path, const QUrlQuery &query = QUrlQuery());
signals:
void requestReceived(const QString&);
void languagesReceived(const QString&);
void categoriesReceived(const QString&);
public slots:
void receiveContent();
void receiveContent(QNetworkReply*);
void receiveLanguages(QNetworkReply*);
void receiveCategories(QNetworkReply*);
};
#endif // OPDSREQUESTMANAGER_H

View File

@ -1,176 +0,0 @@
#include "static_content.h"
#include "kiwixapp.h"
std::vector<QLocale::Language> S_LANGUAGES;
std::vector<std::pair<QString, QString>> S_CATEGORIES;
void initStaticContent() {
#define PUSH(key) S_CATEGORIES.push_back(std::make_pair(QString::fromStdString(key), gt(key)))
PUSH("all");
PUSH("other");
PUSH("gutenberg");
PUSH("mooc");
PUSH("phet");
PUSH("psiram");
PUSH("stack_exchange");
PUSH("ted");
PUSH("vikidia");
PUSH("wikibooks");
PUSH("wikihow");
PUSH("wikinews");
PUSH("wikipedia");
PUSH("wikiquote");
PUSH("wikisource");
PUSH("wikiversity");
PUSH("wikivoyage");
PUSH("wiktionary");
#undef PUSH
#define PUSH(value) S_LANGUAGES.push_back(value)
PUSH(QLocale::Afar);
PUSH(QLocale::Afrikaans);
PUSH(QLocale::Akan);
PUSH(QLocale::Amharic);
PUSH(QLocale::Arabic);
PUSH(QLocale::Assamese);
PUSH(QLocale::Azerbaijani);
PUSH(QLocale::Bashkir);
PUSH(QLocale::Belarusian);
PUSH(QLocale::Bulgarian);
PUSH(QLocale::Bambara);
PUSH(QLocale::Bengali);
PUSH(QLocale::Tibetan);
PUSH(QLocale::Breton);
PUSH(QLocale::Bosnian);
PUSH(QLocale::Catalan);
PUSH(QLocale::Chechen);
PUSH(QLocale::Corsican);
PUSH(QLocale::Czech);
PUSH(QLocale::Church);
PUSH(QLocale::Chuvash);
PUSH(QLocale::Welsh);
PUSH(QLocale::Danish);
PUSH(QLocale::German);
PUSH(QLocale::Divehi);
PUSH(QLocale::Dzongkha);
PUSH(QLocale::Ewe);
PUSH(QLocale::Greek);
PUSH(QLocale::English);
PUSH(QLocale::Spanish);
PUSH(QLocale::Estonian);
PUSH(QLocale::Basque);
PUSH(QLocale::Persian);
PUSH(QLocale::Fulah);
PUSH(QLocale::Finnish);
PUSH(QLocale::Faroese);
PUSH(QLocale::French);
PUSH(QLocale::WesternFrisian);
PUSH(QLocale::Irish);
PUSH(QLocale::Gaelic);
PUSH(QLocale::Galician);
PUSH(QLocale::Guarani);
PUSH(QLocale::Gujarati);
PUSH(QLocale::Manx);
PUSH(QLocale::Hausa);
PUSH(QLocale::Hebrew);
PUSH(QLocale::Hindi);
PUSH(QLocale::Croatian);
PUSH(QLocale::Hungarian);
PUSH(QLocale::Armenian);
PUSH(QLocale::Interlingua);
PUSH(QLocale::Indonesian);
PUSH(QLocale::Igbo);
PUSH(QLocale::Icelandic);
PUSH(QLocale::Italian);
PUSH(QLocale::Inuktitut);
PUSH(QLocale::Japanese);
PUSH(QLocale::Javanese);
PUSH(QLocale::Georgian);
PUSH(QLocale::Kikuyu);
PUSH(QLocale::Kazakh);
PUSH(QLocale::Greenlandic);
PUSH(QLocale::Khmer);
PUSH(QLocale::Kannada);
PUSH(QLocale::Korean);
PUSH(QLocale::Kashmiri);
PUSH(QLocale::Kurdish);
PUSH(QLocale::Cornish);
PUSH(QLocale::Kirghiz);
PUSH(QLocale::Luxembourgish);
PUSH(QLocale::Ganda);
PUSH(QLocale::Lingala);
PUSH(QLocale::Lao);
PUSH(QLocale::Lithuanian);
PUSH(QLocale::Latvian);
PUSH(QLocale::Malagasy);
PUSH(QLocale::Maori);
PUSH(QLocale::Maori);
PUSH(QLocale::Macedonian);
PUSH(QLocale::Malayalam);
PUSH(QLocale::Mongolian);
PUSH(QLocale::Marathi);
PUSH(QLocale::Malay);
PUSH(QLocale::Maltese);
PUSH(QLocale::Burmese);
PUSH(QLocale::Nepali);
PUSH(QLocale::Dutch);
PUSH(QLocale::NorwegianNynorsk);
PUSH(QLocale::NorwegianBokmal);
PUSH(QLocale::Nyanja);
PUSH(QLocale::Occitan);
PUSH(QLocale::Oromo);
PUSH(QLocale::Oriya);
PUSH(QLocale::Ossetic);
PUSH(QLocale::Punjabi);
PUSH(QLocale::Polish);
PUSH(QLocale::Pashto);
PUSH(QLocale::Portuguese);
PUSH(QLocale::Quechua);
PUSH(QLocale::Romansh);
PUSH(QLocale::Rundi);
PUSH(QLocale::Romanian);
PUSH(QLocale::Russian);
PUSH(QLocale::Kinyarwanda);
PUSH(QLocale::Sanskrit);
PUSH(QLocale::Sindhi);
PUSH(QLocale::NorthernSami);
PUSH(QLocale::Sango);
PUSH(QLocale::Sinhala);
PUSH(QLocale::Slovak);
PUSH(QLocale::Slovenian);
PUSH(QLocale::Shona);
PUSH(QLocale::Somali);
PUSH(QLocale::Albanian);
PUSH(QLocale::Serbian);
PUSH(QLocale::Swati);
PUSH(QLocale::SouthernSotho);
PUSH(QLocale::Swedish);
PUSH(QLocale::Swahili);
PUSH(QLocale::Tamil);
PUSH(QLocale::Telugu);
PUSH(QLocale::Tajik);
PUSH(QLocale::Thai);
PUSH(QLocale::Tigrinya);
PUSH(QLocale::Turkmen);
PUSH(QLocale::Filipino);
PUSH(QLocale::Tswana);
PUSH(QLocale::Tongan);
PUSH(QLocale::Turkish);
PUSH(QLocale::Tsonga);
PUSH(QLocale::Tatar);
PUSH(QLocale::Uighur);
PUSH(QLocale::Ukrainian);
PUSH(QLocale::Urdu);
PUSH(QLocale::Uzbek);
PUSH(QLocale::Venda);
PUSH(QLocale::Vietnamese);
PUSH(QLocale::Walloon);
PUSH(QLocale::Wolof);
PUSH(QLocale::Xhosa);
PUSH(QLocale::Yoruba);
PUSH(QLocale::Chinese);
PUSH(QLocale::Zulu);
#undef PUSH
}

View File

@ -1,15 +0,0 @@
#ifndef STATICCONTENT_H
#define STATICCONTENT_H
#include <QLocale>
#include <QString>
#include <utility>
#include <vector>
extern std::vector<QLocale::Language> S_LANGUAGES;
extern std::vector<std::pair<QString, QString>> S_CATEGORIES;
void initStaticContent();
#endif //STATICCONTENT_H