changeset 120:275da698697d

config: template-ify INI now it's... slightly less ugly :')
author Paper <mrpapersonic@gmail.com>
date Wed, 08 Nov 2023 18:13:37 -0500
parents 4eae379cb1ff
children a66c47c1ba3c
files CMakeLists.txt include/core/config.h include/core/ini.h src/core/config.cc src/core/strings.cc src/gui/dialog/settings/recognition.cc src/gui/dialog/settings/services.cc src/services/anilist.cc
diffstat 8 files changed, 123 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Nov 08 13:50:00 2023 -0500
+++ b/CMakeLists.txt	Wed Nov 08 18:13:37 2023 -0500
@@ -57,7 +57,6 @@
 	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
--- a/include/core/config.h	Wed Nov 08 13:50:00 2023 -0500
+++ b/include/core/config.h	Wed Nov 08 18:13:37 2023 -0500
@@ -29,10 +29,19 @@
 		   "auth" struct... */
 		struct {
 			public:
-				std::string auth_token;
-				std::string username;
-				int user_id;
-		} anilist;
+				struct {
+					public:
+						std::string auth_token;
+						std::string username;
+						int user_id;
+				} anilist;
+		} auth;
+
+		struct {
+			public:
+				bool detect_media_players;
+				//bool detect_streaming_media;
+		} recognition;
 
 		struct {
 			public:
--- a/include/core/ini.h	Wed Nov 08 13:50:00 2023 -0500
+++ b/include/core/ini.h	Wed Nov 08 18:13:37 2023 -0500
@@ -3,12 +3,75 @@
 
 #define MINI_CASE_SENSITIVE
 #include "mini/ini.h"
+#include "core/strings.h"
+#include "gui/translate/anime.h"
+#include "gui/translate/config.h"
+#include <type_traits>
+#include <string>
 
 namespace INI {
 
-std::string GetIniString(const mINI::INIStructure& ini, const std::string& section,
-	                     const std::string& value, const std::string& def = "");
+/* very simple tutorial on how to give anyone who reads
+   your code an aneurysm */
+template< class... >  
+using void_t = void;
+
+template <typename T, typename = void>
+struct is_toutf8string_available : std::false_type {};
+
+template<typename T>
+struct is_toutf8string_available<T,
+		void_t<decltype(Strings::ToUtf8String(std::declval<T>()))>> : std::true_type {};
+
+template <typename T, typename = void>
+struct is_translation_available : std::false_type {};
+
+template<typename T>
+struct is_translation_available<T,
+		void_t<decltype(Translate::ToString(std::declval<T>()))>> : std::true_type {};
+
+template<typename T>
+T GetIniValue(const mINI::INIStructure& ini, const std::string& section,
+	          const std::string& value, const T& def) {
+	if (!ini.has(section) || !ini.get(section).has(value))
+		return def;
+
+	const std::string val = ini.get(section).get(value);
+
+	if constexpr (std::is_arithmetic<T>::value) {
+		/* Integer? */
+		if constexpr (std::is_same<T, bool>::value) {
+			/* Boolean? */
+			return Strings::ToBool(val);
+		} else if constexpr (std::is_unsigned<T>::value) {
+			/* Unsigned? */
+			return Strings::ToUnsignedInt(val);
+		} else {
+			/* Always fall back to long long */
+			return Strings::ToInt(val);
+		}
+	} else {
+		return val;
+	}
+}
+
+/* this should be able to handle most of our custom types */
+template<typename T>
+void SetIniValue(mINI::INIStructure& ini, const std::string& section,
+	             const std::string& key, const T& value) {
+	auto& ini_key = ini[section][key];
+
+	if constexpr (is_translation_available<T>::value) {
+		ini_key = Translate::ToString(value);
+	} else if constexpr (std::is_same<T, std::string>::value) {
+		ini_key = value;
+	} else if constexpr (std::is_arithmetic<T>::value && !std::is_same<T, bool>::value) {
+		ini_key = std::to_string(value);
+	} else if constexpr (is_toutf8string_available<T>::value) {
+		ini_key = Strings::ToUtf8String(value);
+	}
+}
 
 }
 
-#endif
\ No newline at end of file
+#endif
--- a/src/core/config.cc	Wed Nov 08 13:50:00 2023 -0500
+++ b/src/core/config.cc	Wed Nov 08 18:13:37 2023 -0500
@@ -17,6 +17,9 @@
 #include <fstream>
 #include <limits.h>
 
+/* I'll use an INI-based config file instead of using an
+   XML file like Taiga. */
+
 int Config::Load() {
 	Filesystem::Path cfg_path = Filesystem::GetConfigPath();
 
@@ -24,22 +27,23 @@
 	mINI::INIStructure ini;
 	file.read(ini);
 
-	service = Translate::ToService(INI::GetIniString(ini, "General", "Service", "None"));
-	/* ew */
-	locale.SetActiveLocale(QLocale(Strings::ToQString(INI::GetIniString(ini, "General", "Locale", "en_US"))));
+	service = Translate::ToService(INI::GetIniValue<std::string>(ini, "General", "Service", "None"));
+
+	anime_list.language = Translate::ToLanguage(INI::GetIniValue<std::string>(ini, "Anime List", "Title language", "Romaji"));
+	anime_list.display_aired_episodes = INI::GetIniValue<bool>(ini, "Anime List", "Display only aired episodes", true);
+	anime_list.display_available_episodes = INI::GetIniValue<bool>(ini, "Anime List", "Display only available episodes in library", true);
+	anime_list.highlight_anime_if_available = INI::GetIniValue<bool>(ini, "Anime List", "Highlight anime if available", true);
+	anime_list.highlighted_anime_above_others = INI::GetIniValue<bool>(ini, "Anime List", "Display highlighted anime above others", false);
 
-	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);
+	auth.anilist.auth_token = INI::GetIniValue<std::string>(ini, "Authentication/AniList", "Auth Token", "");
+	auth.anilist.user_id = INI::GetIniValue<int>(ini, "Authentication/AniList", "User ID", 0);
+
+	torrents.feed_link = INI::GetIniValue<std::string>(ini, "Torrents", "RSS feed", "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
 
-	anilist.auth_token = INI::GetIniString(ini, "AniList", "Auth Token", "");
-	anilist.user_id = Strings::ToInt(INI::GetIniString(ini, "AniList", "User ID", ""), 0);
+	/* ew */
+	locale.SetActiveLocale(QLocale(Strings::ToQString(INI::GetIniValue<std::string>(ini, "General", "Locale", "en_US"))));
 
-	torrents.feed_link = INI::GetIniString(ini, "Torrents", "RSS feed", "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
-
-	theme.SetTheme(Translate::ToTheme(INI::GetIniString(ini, "Appearance", "Theme", "Default")));
+	theme.SetTheme(Translate::ToTheme(INI::GetIniValue<std::string>(ini, "Appearance", "Theme", "Default")));
 
 	return 0;
 }
@@ -52,17 +56,24 @@
 	mINI::INIFile file(cfg_path.GetPath());
 	mINI::INIStructure ini;
 
-	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"] = 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"] = torrents.feed_link;
+	INI::SetIniValue(ini, "General", "Service", service);
+	INI::SetIniValue(ini, "General", "Locale", locale.GetLocale().name());
+
+	INI::SetIniValue(ini, "Anime List", "Title language", anime_list.language);
+	INI::SetIniValue(ini, "Anime List", "Display only aired episodes", anime_list.display_aired_episodes);
+	INI::SetIniValue(ini, "Anime List", "Display only available episodes in library", anime_list.display_available_episodes);
+	INI::SetIniValue(ini, "Anime List", "Highlight anime if available", anime_list.highlight_anime_if_available);
+	INI::SetIniValue(ini, "Anime List", "Display highlighted anime above others", anime_list.highlighted_anime_above_others);
+
+	INI::SetIniValue(ini, "Authentication/AniList", "Auth Token", auth.anilist.auth_token);
+	INI::SetIniValue(ini, "Authentication/AniList", "User ID", auth.anilist.user_id);
+
+	INI::SetIniValue(ini, "Appearance", "Theme", theme.GetTheme());
+
+	INI::SetIniValue(ini, "Torrents", "RSS feed", torrents.feed_link);
+
+	INI::SetIniValue(ini, "Recognition", "Detect media players", recognition.detect_media_players);
+	//ini["Recognition"]["Detect streaming media"] = Strings::ToUtf8String(recognition.detect_streaming_media);
 
 	file.write(ini);
 
--- a/src/core/strings.cc	Wed Nov 08 13:50:00 2023 -0500
+++ b/src/core/strings.cc	Wed Nov 08 18:13:37 2023 -0500
@@ -158,6 +158,7 @@
 	return QString::fromWCharArray(wstring.c_str(), wstring.length());
 }
 
+/* not really an "int"... but who cares? */
 int ToInt(const std::string& str, int def) {
 	int tmp = 0;
 	try {
--- a/src/gui/dialog/settings/recognition.cc	Wed Nov 08 13:50:00 2023 -0500
+++ b/src/gui/dialog/settings/recognition.cc	Wed Nov 08 18:13:37 2023 -0500
@@ -66,5 +66,5 @@
 }
 
 SettingsPageRecognition::SettingsPageRecognition(QWidget* parent) : SettingsPage(parent, tr("Recognition")) {
-	AddTab(CreatePlayersWidget(), tr("Players"));
+	AddTab(CreatePlayersWidget(), tr("Media players"));
 }
--- a/src/gui/dialog/settings/services.cc	Wed Nov 08 13:50:00 2023 -0500
+++ b/src/gui/dialog/settings/services.cc	Wed Nov 08 18:13:37 2023 -0500
@@ -87,7 +87,7 @@
 				/* The actual auth button */
 				QPushButton* auth_button = new QPushButton(auth_widget);
 				connect(auth_button, &QPushButton::clicked, this, [] { Services::AniList::AuthorizeUser(); });
-				auth_button->setText(session.config.anilist.auth_token.empty() ? tr("Authorize...") : tr("Re-authorize..."));
+				auth_button->setText(session.config.auth.anilist.auth_token.empty() ? tr("Authorize...") : tr("Re-authorize..."));
 				auth_layout->addWidget(auth_button);
 			}
 
--- a/src/services/anilist.cc	Wed Nov 08 13:50:00 2023 -0500
+++ b/src/services/anilist.cc	Wed Nov 08 18:13:37 2023 -0500
@@ -24,14 +24,14 @@
 
 class Account {
 	public:
-		std::string Username() const { return session.config.anilist.username; }
-		void SetUsername(std::string const& username) { session.config.anilist.username = username; }
+		std::string Username() const { return session.config.auth.anilist.username; }
+		void SetUsername(std::string const& username) { session.config.auth.anilist.username = username; }
 
-		int UserId() const { return session.config.anilist.user_id; }
-		void SetUserId(const int id) { session.config.anilist.user_id = id; }
+		int UserId() const { return session.config.auth.anilist.user_id; }
+		void SetUserId(const int id) { session.config.auth.anilist.user_id = id; }
 
-		std::string AuthToken() const { return session.config.anilist.auth_token; }
-		void SetAuthToken(std::string const& auth_token) { session.config.anilist.auth_token = auth_token; }
+		std::string AuthToken() const { return session.config.auth.anilist.auth_token; }
+		void SetAuthToken(std::string const& auth_token) { session.config.auth.anilist.auth_token = auth_token; }
 
 		bool Authenticated() const { return !AuthToken().empty(); }
 };