# HG changeset patch # User Paper # Date 1699383133 18000 # Node ID 254b1d2b7096f11f5551703c31d9af3c6f57f467 # Parent c72b907b9bef474ed7ef0462493ea00793030ebf settings: add torrents page, make rss feed configurable diff -r c72b907b9bef -r 254b1d2b7096 CMakeLists.txt --- a/CMakeLists.txt Tue Nov 07 12:04:51 2023 -0500 +++ b/CMakeLists.txt Tue Nov 07 13:52:13 2023 -0500 @@ -57,6 +57,7 @@ src/core/config.cc src/core/date.cc src/core/filesystem.cc + src/core/ini.cc src/core/http.cc src/core/json.cc src/core/strings.cc @@ -90,6 +91,7 @@ src/gui/dialog/settings.cc src/gui/dialog/settings/application.cc src/gui/dialog/settings/services.cc + src/gui/dialog/settings/torrents.cc # Translate src/gui/translate/anime.cc diff -r c72b907b9bef -r 254b1d2b7096 include/core/config.h --- a/include/core/config.h Tue Nov 07 12:04:51 2023 -0500 +++ b/include/core/config.h Tue Nov 07 13:52:13 2023 -0500 @@ -23,17 +23,28 @@ bool highlighted_anime_above_others; } anime_list; + /* these should preferably be in an + "auth" struct... */ struct { public: std::string auth_token; std::string username; int user_id; } anilist; + + struct { + public: + std::string feed_link; + } torrents; }; #define WIDEIFY_EX(x) L##x #define WIDEIFY(x) WIDEIFY_EX(x) +/* only on these platforms keep this uppercase. + this will not remove compatibility with older + versions, since these platforms are case insensitive + (on macOS, only by default) */ #if (defined(WIN32) || defined(MACOSX)) #define CONFIG_DIR "Minori" #else diff -r c72b907b9bef -r 254b1d2b7096 include/core/ini.h --- a/include/core/ini.h Tue Nov 07 12:04:51 2023 -0500 +++ b/include/core/ini.h Tue Nov 07 13:52:13 2023 -0500 @@ -4,4 +4,11 @@ #define MINI_CASE_SENSITIVE #include "mini/ini.h" +namespace INI { + +std::string GetIniString(const mINI::INIStructure& ini, const std::string& section, + const std::string& value, const std::string& def = ""); + +} + #endif \ No newline at end of file diff -r c72b907b9bef -r 254b1d2b7096 include/core/strings.h --- a/include/core/strings.h Tue Nov 07 12:04:51 2023 -0500 +++ b/include/core/strings.h Tue Nov 07 13:52:13 2023 -0500 @@ -7,6 +7,7 @@ #include class QString; +class QByteArray; namespace Strings { @@ -32,12 +33,16 @@ std::wstring ToWstring(const QString& string); std::string ToUtf8String(const std::wstring& wstring); std::string ToUtf8String(const QString& string); +std::string ToUtf8String(const QByteArray& ba); QString ToQString(const std::string& string); QString ToQString(const std::wstring& wstring); /* arithmetic :) */ int ToInt(const std::string& str, int def = 0); +bool ToBool(const std::string& s, const bool def = false); +std::string ToUtf8String(const bool b); + uint64_t HumanReadableSizeToBytes(const std::string& str); std::string RemoveLeadingChars(std::string s, const char c); diff -r c72b907b9bef -r 254b1d2b7096 include/gui/dialog/settings.h --- a/include/gui/dialog/settings.h Tue Nov 07 12:04:51 2023 -0500 +++ b/include/gui/dialog/settings.h Tue Nov 07 13:52:13 2023 -0500 @@ -3,6 +3,7 @@ #include "core/anime.h" #include "core/config.h" +#include "core/session.h" #include #include #include @@ -58,6 +59,18 @@ bool highlighted_anime_above_others; }; +class SettingsPageTorrents final : public SettingsPage { + Q_OBJECT + + public: + SettingsPageTorrents(QWidget* parent = nullptr); + void SaveInfo() override; + + private: + QWidget* CreateGeneralWidget(); + decltype(session.config.torrents.feed_link) feed_link; +}; + class SettingsDialog final : public QDialog { Q_OBJECT diff -r c72b907b9bef -r 254b1d2b7096 rc/locale/en_GB.ts --- a/rc/locale/en_GB.ts Tue Nov 07 12:04:51 2023 -0500 +++ b/rc/locale/en_GB.ts Tue Nov 07 13:52:13 2023 -0500 @@ -565,6 +565,11 @@ Application + + + Torrents + + SettingsPageApplication @@ -739,6 +744,29 @@ + SettingsPageTorrents + + + URLs + + + + + URL of the RSS feed to check: + + + + + Application + + + + + General + + + + StatisticsPage @@ -775,22 +803,22 @@ TorrentsPage - + &Check new torrents - + Download &marked torrents - + &Discard all - + &Settings diff -r c72b907b9bef -r 254b1d2b7096 rc/locale/es.ts --- a/rc/locale/es.ts Tue Nov 07 12:04:51 2023 -0500 +++ b/rc/locale/es.ts Tue Nov 07 13:52:13 2023 -0500 @@ -646,6 +646,11 @@ Application Aplicación + + + Torrents + + SettingsPageApplication @@ -820,6 +825,29 @@ + SettingsPageTorrents + + + URLs + URLs + + + + URL of the RSS feed to check: + URL del feed RSS para comprobar: + + + + Application + Aplicación + + + + General + General + + + StatisticsPage @@ -862,22 +890,22 @@ TorrentsPage - + &Check new torrents &Comprueba nuevos torrentes - + Download &marked torrents Descargar torrents &marcados - + &Discard all &Descartar todo - + &Settings Configuración (&S) diff -r c72b907b9bef -r 254b1d2b7096 src/core/config.cc --- a/src/core/config.cc Tue Nov 07 12:04:51 2023 -0500 +++ b/src/core/config.cc Tue Nov 07 13:52:13 2023 -0500 @@ -17,22 +17,6 @@ #include #include -/* Move these to strings.cc or the translation stuff, please. */ -static bool string_to_bool(const std::string& s, bool def = false) { - if (s.length() < 4) - return def; - std::string l = Strings::ToLower(s); - if (Strings::BeginningMatchesSubstring(l, "true")) - return true; - else if (Strings::BeginningMatchesSubstring(l, "false")) - return false; - return def; -} - -static std::string bool_to_string(bool b) { - return b ? "true" : "false"; -} - int Config::Load() { Filesystem::Path cfg_path = Filesystem::GetConfigPath(); @@ -40,16 +24,22 @@ mINI::INIStructure ini; file.read(ini); - service = Translate::ToService(ini.get("General").get("Service")); - locale.SetActiveLocale(QLocale(Strings::ToQString(ini.get("General").get("Locale")))); - anime_list.language = Translate::ToLanguage(ini.get("Anime List").get("Title language")); - anime_list.display_aired_episodes = string_to_bool(ini.get("Anime List").get("Display only aired episodes"), true); - anime_list.display_available_episodes = string_to_bool(ini.get("Anime List").get("Display only available episodes in library"), true); - anime_list.highlight_anime_if_available = string_to_bool(ini.get("Anime List").get("Highlight anime if available"), true); - anime_list.highlighted_anime_above_others = string_to_bool(ini.get("Anime List").get("Display highlighted anime above others")); - anilist.auth_token = ini.get("AniList").get("Auth Token"); - anilist.user_id = Strings::ToInt(ini.get("AniList").get("User ID")); - theme.SetTheme(Translate::ToTheme(ini.get("Appearance").get("Theme"))); + service = Translate::ToService(INI::GetIniString(ini, "General", "Service", "None")); + /* ew */ + locale.SetActiveLocale(QLocale(Strings::ToQString(INI::GetIniString(ini, "General", "Locale", "en_US")))); + + anime_list.language = Translate::ToLanguage(INI::GetIniString(ini, "Anime List", "Title language", "Romaji")); + anime_list.display_aired_episodes = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Display only aired episodes", ""), true); + anime_list.display_available_episodes = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Display only available episodes in library", ""), true); + anime_list.highlight_anime_if_available = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Highlight anime if available", ""), true); + anime_list.highlighted_anime_above_others = Strings::ToBool(INI::GetIniString(ini, "Anime List", "Display highlighted anime above others", ""), false); + + anilist.auth_token = INI::GetIniString(ini, "AniList", "Auth Token", ""); + anilist.user_id = Strings::ToInt(INI::GetIniString(ini, "AniList", "User ID", ""), 0); + + torrents.feed_link = INI::GetIniString(ini, "Torrents", "RSS Feed Link", "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0"); + + theme.SetTheme(Translate::ToTheme(INI::GetIniString(ini, "Appearance", "Theme", "Default"))); return 0; } @@ -65,13 +55,14 @@ ini["General"]["Service"] = Translate::ToString(service); ini["General"]["Locale"] = Strings::ToUtf8String(locale.GetLocale().name()); ini["Anime List"]["Title language"] = Translate::ToString(anime_list.language); - ini["Anime List"]["Display only aired episodes"] = bool_to_string(anime_list.display_aired_episodes); - ini["Anime List"]["Display only available episodes in library"] = bool_to_string(anime_list.display_available_episodes); - ini["Anime List"]["Highlight anime if available"] = bool_to_string(anime_list.highlight_anime_if_available); - ini["Anime List"]["Display highlighted anime above others"] = bool_to_string(anime_list.highlighted_anime_above_others); + ini["Anime List"]["Display only aired episodes"] = Strings::ToUtf8String(anime_list.display_aired_episodes); + ini["Anime List"]["Display only available episodes in library"] = Strings::ToUtf8String(anime_list.display_available_episodes); + ini["Anime List"]["Highlight anime if available"] = Strings::ToUtf8String(anime_list.highlight_anime_if_available); + ini["Anime List"]["Display highlighted anime above others"] = Strings::ToUtf8String(anime_list.highlighted_anime_above_others); ini["AniList"]["Auth Token"] = anilist.auth_token; ini["AniList"]["User ID"] = std::to_string(anilist.user_id); ini["Appearance"]["Theme"] = Translate::ToString(theme.GetTheme()); + ini["Torrents"]["RSS Feed Link"] = torrents.feed_link; file.write(ini); diff -r c72b907b9bef -r 254b1d2b7096 src/core/ini.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/core/ini.cc Tue Nov 07 13:52:13 2023 -0500 @@ -0,0 +1,13 @@ +#include "core/ini.h" + +namespace INI { + +/* this should be in some ini.cc or whatever */ +std::string GetIniString(const mINI::INIStructure& ini, const std::string& section, + const std::string& value, const std::string& def) { + if (!ini.has(section) || !ini.get(section).has(value)) + return def; + return ini.get(section).get(value); // ack +} + +} \ No newline at end of file diff -r c72b907b9bef -r 254b1d2b7096 src/core/strings.cc --- a/src/core/strings.cc Tue Nov 07 12:04:51 2023 -0500 +++ b/src/core/strings.cc Tue Nov 07 13:52:13 2023 -0500 @@ -156,6 +156,21 @@ return tmp; } +bool ToBool(const std::string& s, const bool def) { + if (s.length() < 4) + return def; + std::string l = Strings::ToLower(s); + if (Strings::BeginningMatchesSubstring(l, "true")) + return true; + else if (Strings::BeginningMatchesSubstring(l, "false")) + return false; + return def; +} + +std::string ToUtf8String(const bool b) { + return b ? "true" : "false"; +} + uint64_t HumanReadableSizeToBytes(const std::string& str) { const std::unordered_map bytes_map = { {"KB", 1 << 10}, diff -r c72b907b9bef -r 254b1d2b7096 src/gui/dialog/settings.cc --- a/src/gui/dialog/settings.cc Tue Nov 07 12:04:51 2023 -0500 +++ b/src/gui/dialog/settings.cc Tue Nov 07 13:52:13 2023 -0500 @@ -91,7 +91,7 @@ sidebar->AddItem(tr("Application"), SideBar::CreateIcon(":/icons/24x24/application-sidebar-list.png")); // sidebar->AddItem(tr("Recognition"), SideBar::CreateIcon(":/icons/24x24/question.png")); // sidebar->AddItem(tr("Sharing"), SideBar::CreateIcon(":/icons/24x24/megaphone.png")); - // sidebar->AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/24x24/feed.png")); + sidebar->AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/24x24/feed.png")); // sidebar->AddItem(tr("Advanced"), SideBar::CreateIcon(":/icons/24x24/gear.png")); sidebar->setIconSize(QSize(24, 24)); @@ -109,6 +109,7 @@ stacked = new QStackedWidget(widget); stacked->addWidget(new SettingsPageServices(stacked)); stacked->addWidget(new SettingsPageApplication(stacked)); + stacked->addWidget(new SettingsPageTorrents(stacked)); stacked->setCurrentIndex(0); connect(sidebar, &QListWidget::currentRowChanged, stacked, &QStackedWidget::setCurrentIndex); diff -r c72b907b9bef -r 254b1d2b7096 src/gui/dialog/settings/torrents.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/dialog/settings/torrents.cc Tue Nov 07 13:52:13 2023 -0500 @@ -0,0 +1,62 @@ +#include "core/session.h" +#include "core/strings.h" +#include "gui/dialog/settings.h" +#include +#include +#include +#include +#include +#include + +QWidget* SettingsPageTorrents::CreateGeneralWidget() { + QWidget* result = new QWidget(this); + result->setAutoFillBackground(true); + result->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + + QVBoxLayout* full_layout = new QVBoxLayout(result); + + { + /* URLs */ + QGroupBox* group = new QGroupBox(tr("URLs"), result); + group->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + + QVBoxLayout* group_layout = new QVBoxLayout(group); + + { + /* Feed link */ + QWidget* widget = new QWidget(group); + QVBoxLayout* widget_layout = new QVBoxLayout(widget); + + { + QLabel* sync_combo_box_label = new QLabel(tr("URL of the RSS feed to check:"), widget); + widget_layout->addWidget(sync_combo_box_label); + } + + { + /* Username: this literally never gets used btw */ + QLineEdit* lineedit = new QLineEdit(Strings::ToQString(feed_link), widget); + connect(lineedit, &QLineEdit::editingFinished, this, + [this, lineedit] { feed_link = Strings::ToUtf8String(lineedit->text()); }); + widget_layout->addWidget(lineedit); + } + + group_layout->addWidget(widget); + } + + full_layout->addWidget(group); + } + + full_layout->setSpacing(10); + full_layout->addStretch(); + + return result; +} + +void SettingsPageTorrents::SaveInfo() { + session.config.torrents.feed_link = feed_link; +} + +SettingsPageTorrents::SettingsPageTorrents(QWidget* parent) : SettingsPage(parent, tr("Application")) { + feed_link = session.config.torrents.feed_link; + AddTab(CreateGeneralWidget(), tr("General")); +} diff -r c72b907b9bef -r 254b1d2b7096 src/gui/pages/torrents.cc --- a/src/gui/pages/torrents.cc Tue Nov 07 12:04:51 2023 -0500 +++ b/src/gui/pages/torrents.cc Tue Nov 07 13:52:13 2023 -0500 @@ -41,7 +41,7 @@ } QByteArray TorrentsPageListModel::DownloadTorrentList() { - return HTTP::Get("https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0"); + return HTTP::Get(session.config.torrents.feed_link); } void TorrentsPageListModel::ParseTorrentList(const QByteArray& ba) { @@ -173,38 +173,42 @@ QVariant TorrentsPageListModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); + + const TorrentModelItem& item = list.at(index.row()); + switch (role) { case Qt::DisplayRole: switch (index.column()) { - case TL_TITLE: return Strings::ToQString(list.at(index.row()).GetTitle()); - case TL_EPISODE: return Strings::ToQString(list.at(index.row()).GetEpisode()); - case TL_GROUP: return Strings::ToQString(list.at(index.row()).GetGroup()); - case TL_SIZE: return session.config.locale.GetLocale().formattedDataSize(list.at(index.row()).GetSize()); - case TL_RESOLUTION: return Strings::ToQString(list.at(index.row()).GetResolution()); - case TL_SEEDERS: return list.at(index.row()).GetSeeders(); - case TL_LEECHERS: return list.at(index.row()).GetLeechers(); - case TL_DOWNLOADERS: return list.at(index.row()).GetDownloaders(); - case TL_DESCRIPTION: return Strings::ToQString(list.at(index.row()).GetDescription()); - case TL_FILENAME: return Strings::ToQString(list.at(index.row()).GetFilename()); - case TL_RELEASEDATE: return list.at(index.row()).GetDate(); + case TL_TITLE: return Strings::ToQString(item.GetTitle()); + case TL_EPISODE: return Strings::ToQString(item.GetEpisode()); + case TL_GROUP: return Strings::ToQString(item.GetGroup()); + case TL_SIZE: return session.config.locale.GetLocale().formattedDataSize(item.GetSize()); + case TL_RESOLUTION: return Strings::ToQString(item.GetResolution()); + case TL_SEEDERS: return item.GetSeeders(); + case TL_LEECHERS: return item.GetLeechers(); + case TL_DOWNLOADERS: return item.GetDownloaders(); + case TL_DESCRIPTION: return Strings::ToQString(item.GetDescription()); + case TL_FILENAME: return Strings::ToQString(item.GetFilename()); + case TL_RELEASEDATE: return item.GetDate(); default: return ""; } break; case Qt::UserRole: switch (index.column()) { - case TL_EPISODE: return Strings::ToInt(list.at(index.row()).GetEpisode(), -1); - case TL_SIZE: return list.at(index.row()).GetSize(); + case TL_EPISODE: return Strings::ToInt(item.GetEpisode(), -1); + case TL_SIZE: return item.GetSize(); default: return data(index, Qt::DisplayRole); } break; case Qt::CheckStateRole: switch (index.column()) { - case 0: return list.at(index.row()).GetChecked() ? Qt::Checked : Qt::Unchecked; + case 0: return item.GetChecked() ? Qt::Checked : Qt::Unchecked; default: return {}; } case Qt::SizeHintRole: { switch (index.column()) { default: { + /* max horizontal size of 100, height size = size of current font */ const QString d = data(index, Qt::DisplayRole).toString(); const QFontMetrics metric = QFontMetrics(QFont()); @@ -263,7 +267,7 @@ { /* this needs to be stored somewhere to replicate Taiga's "timer" feature */ - QAction* action = toolbar->addAction(QIcon(":/icons/16x16/arrow-circle-315.png"), tr("&Check new torrents"), [this]{ + toolbar->addAction(QIcon(":/icons/16x16/arrow-circle-315.png"), tr("&Check new torrents"), [this]{ QThreadPool::globalInstance()->start([this] { Refresh(); }); @@ -273,17 +277,17 @@ toolbar->addSeparator(); { - QAction* action = toolbar->addAction(QIcon(":/icons/16x16/navigation-270-button.png"), tr("Download &marked torrents")); + toolbar->addAction(QIcon(":/icons/16x16/navigation-270-button.png"), tr("Download &marked torrents")); } { - QAction* action = toolbar->addAction(QIcon(":/icons/16x16/cross-button.png"), tr("&Discard all")); + toolbar->addAction(QIcon(":/icons/16x16/cross-button.png"), tr("&Discard all")); } toolbar->addSeparator(); { - QAction* action = toolbar->addAction(QIcon(":/icons/16x16/gear.png"), tr("&Settings")); + toolbar->addAction(QIcon(":/icons/16x16/gear.png"), tr("&Settings")); } layout->addWidget(toolbar);