changeset 231:69f4768a820c

chore: merge divergent branches
author Paper <paper@paper.us.eu.org>
date Sat, 13 Jan 2024 09:43:41 -0500
parents 2f5a9247e501 (diff) d030b30526d5 (current diff)
children ff0061e75f0f
files src/core/strings.cc src/track/media.cc
diffstat 13 files changed, 193 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/dep/animia/src/fd/xnu.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/dep/animia/src/fd/xnu.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -17,12 +17,12 @@
 namespace animia::internal::xnu {
 
 bool EnumerateOpenProcesses(process_proc_t process_proc) {
-	size_t pids_size = 512;
+	size_t pids_size = 256;
 	std::unique_ptr<pid_t[]> pids;
 
 	int returned_size = 0;
 	do {
-		pids.reset(new pid_t[pids_size]);
+		pids.reset(new pid_t[pids_size *= 2]);
 		returned_size = proc_listpids(PROC_ALL_PIDS, 0, pids.get(), pids_size * sizeof(pid_t));
 		if (returned_size == -1)
 			return false;
--- a/include/core/filesystem.h	Tue Jan 09 08:05:36 2024 -0500
+++ b/include/core/filesystem.h	Sat Jan 13 09:43:41 2024 -0500
@@ -6,11 +6,10 @@
 namespace Filesystem {
 
 void CreateDirectories(const std::filesystem::path& path);
-std::filesystem::path GetDotPath();        // %APPDATA%/minori, ~/Library/Application Support/minori, ~/.config/minori...
+std::filesystem::path GetDotPath();        // %APPDATA%/minori/, ~/Library/Application Support/minori/, ~/.config/minori/...
 std::filesystem::path GetConfigPath();     // (dotpath)/config.json
 std::filesystem::path GetAnimeDBPath();    // (dotpath)/anime/db.json
-std::filesystem::path GetPlayersPath();    // (dotpath)/player.json
-std::filesystem::path GetExtensionsPath(); // (dotpath)/extensions.json
+std::filesystem::path GetTorrentsPath();   // (dotpath)/torrents/...
 
 } // namespace Filesystem
 
--- a/include/core/http.h	Tue Jan 09 08:05:36 2024 -0500
+++ b/include/core/http.h	Sat Jan 13 09:43:41 2024 -0500
@@ -2,6 +2,7 @@
 #define __core__http_h
 
 #include <QByteArray>
+#include <QThread>
 #include <string>
 #include <vector>
 
@@ -10,6 +11,50 @@
 QByteArray Get(const std::string& url, const std::vector<std::string>& headers = {});
 QByteArray Post(const std::string& url, const std::string& data, const std::vector<std::string>& headers = {});
 
+class GetThread : public QThread {
+	Q_OBJECT
+
+public:
+	GetThread(const std::string& u, const std::vector<std::string>& h = {}) {
+		url = u;
+		headers = h;
+	}
+
+signals:
+	void ReceivedData(const QByteArray& ba);
+
+protected:
+	void run() override {
+		emit ReceivedData(Get(url, headers));
+	}
+
+	std::string url;
+	std::vector<std::string> headers;
+};
+
+class PostThread : public QThread {
+	Q_OBJECT
+
+public:
+	PostThread(const std::string& u, const std::string& d, const std::vector<std::string>& h = {}) {
+		url = u;
+		data = d;
+		headers = h;
+	}
+
+signals:
+	void ReceivedData(const QByteArray& ba);
+
+protected:
+	void run() override {
+		emit ReceivedData(Post(url, data, headers));
+	}
+
+	std::string url;
+	std::string data;
+	std::vector<std::string> headers;
+};
+
 } // namespace HTTP
 
 #endif // __core__http_h
--- a/include/gui/pages/torrents.h	Tue Jan 09 08:05:36 2024 -0500
+++ b/include/gui/pages/torrents.h	Sat Jan 13 09:43:41 2024 -0500
@@ -5,6 +5,9 @@
 #include <QFrame>
 #include <QAbstractListModel>
 #include <QSortFilterProxyModel>
+#include <QItemSelection>
+
+class QTreeView;
 
 class TorrentsPageListSortFilter final : public QSortFilterProxyModel {
 		Q_OBJECT
@@ -46,6 +49,7 @@
 		Qt::ItemFlags flags(const QModelIndex& index) const override;
 
 		QByteArray DownloadTorrentList();
+		void DownloadTorrents(QItemSelection selection);
 		void ParseFeedDescription(const std::string& description, Torrent& torrent);
 		void ParseTorrentList(const QByteArray& ba);
 		void RefreshTorrentList();
@@ -68,11 +72,13 @@
 
 	public:
 		TorrentsPage(QWidget* parent = nullptr);
+		void DownloadSelection();
 		void Refresh();
 
 	private:
 		TorrentsPageListModel* model = nullptr;
 		TorrentsPageListSortFilter* sort_model = nullptr;
+		QTreeView* treeview = nullptr;
 };
 
 #endif // __gui__pages__torrents_h
--- a/src/core/filesystem.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/core/filesystem.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -72,16 +72,12 @@
 	return GetDotPath() / CONFIG_NAME;
 }
 
-std::filesystem::path GetPlayersPath() {
-	return GetDotPath() / "recognition" / "players.json";
-}
-
-std::filesystem::path GetExtensionsPath() {
-	return GetDotPath() / "recognition" / "extensions.json";
-}
-
 std::filesystem::path GetAnimeDBPath() {
 	return GetDotPath() / "anime" / "db.json";
 }
 
+std::filesystem::path GetTorrentsPath() {
+	return GetDotPath() / "torrents";
+}
+
 } // namespace Filesystem
--- a/src/core/http.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/core/http.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -65,3 +65,5 @@
 }
 
 } // namespace HTTP
+
+#include "core/moc_http.cpp"
--- a/src/core/strings.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/core/strings.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -16,6 +16,7 @@
 #include <string>
 #include <vector>
 #include <unordered_map>
+#include <iostream>
 
 namespace Strings {
 
@@ -147,8 +148,15 @@
 }
 
 std::wstring ToWstring(const std::string& string) {
-	static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
-	return converter.from_bytes(string);
+	static std::wstring_convert<std::codecvt_utf8<wchar_t>> converter("", L"");
+
+	std::wstring wstr;
+	try {
+		wstr = converter.from_bytes(string);
+	} catch (std::range_error const& ex) {
+		std::cerr << "Failed to convert UTF-8 to wide string!" << std::endl;
+	}
+	return wstr;
 }
 
 std::wstring ToWstring(const QString& string) {
@@ -158,7 +166,7 @@
 }
 
 std::string ToUtf8String(const std::wstring& wstring) {
-	static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
+	static std::wstring_convert<std::codecvt_utf8<wchar_t>> converter("", L"");
 	return converter.to_bytes(wstring);
 }
 
--- a/src/gui/pages/anime_list.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/gui/pages/anime_list.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -28,7 +28,7 @@
 #include <QTreeView>
 #include <QStylePainter>
 #include <QStyledItemDelegate>
-#include <QThreadPool>
+#include <QThread>
 
 #include <set>
 
@@ -218,10 +218,14 @@
 }
 
 void AnimeListPage::UpdateAnime(int id) {
-	QThreadPool::globalInstance()->start([this, id] {
+	QThread* thread = QThread::create([id] {
 		Services::UpdateAnimeEntry(id);
-		Refresh();
 	});
+
+	connect(thread, &QThread::finished, this, &AnimeListPage::Refresh);
+	connect(thread, &QThread::finished, this, &QThread::deleteLater);
+
+	thread->start();
 }
 
 void AnimeListPage::RemoveAnime(int id) {
--- a/src/gui/pages/torrents.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/gui/pages/torrents.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -2,6 +2,7 @@
 #include "core/strings.h"
 #include "core/http.h"
 #include "core/session.h"
+#include "core/filesystem.h"
 #include "gui/widgets/text.h"
 #include "track/media.h"
 
@@ -11,11 +12,12 @@
 #include <QMainWindow>
 #include <QByteArray>
 #include <QDataStream>
-#include <QThreadPool>
+#include <QThread>
 #include <QDebug>
 
 #include <iostream>
 #include <sstream>
+#include <fstream>
 #include <algorithm>
 
 #include "pugixml.hpp"
@@ -50,6 +52,28 @@
 TorrentsPageListModel::TorrentsPageListModel(QObject* parent) : QAbstractListModel(parent) {
 }
 
+void TorrentsPageListModel::DownloadTorrents(QItemSelection selection) {
+	const auto indexes = selection.indexes();
+
+	for (const auto& index : indexes) {
+		/* a torrent file IS literally text... */
+		const std::string link = list.at(index.row()).GetLink();
+		const std::string filename = list.at(index.row()).GetFilename() + ".torrent";
+
+		const std::filesystem::path torrents_dir = Filesystem::GetTorrentsPath();
+		std::filesystem::create_directories(torrents_dir);
+
+		std::ofstream file(torrents_dir / filename, std::ofstream::out | std::ofstream::trunc);
+		if (!file)
+			return; // wat
+
+		const QByteArray data = HTTP::Get(link);
+		file.write(data.data(), data.size());
+
+		file.close();
+	}
+}
+
 QByteArray TorrentsPageListModel::DownloadTorrentList() {
 	return HTTP::Get(session.config.torrents.feed_link);
 }
@@ -231,14 +255,15 @@
 				case TL_DESCRIPTION: return Strings::ToQString(item.GetDescription());
 				case TL_FILENAME: return Strings::ToQString(item.GetFilename());
 				case TL_RELEASEDATE: return item.GetDate();
-				default: return "";
+				default: return {};
 			}
 			break;
 		case Qt::UserRole:
 			switch (index.column()) {
 				case TL_EPISODE: return Strings::ToInt(item.GetEpisode(), -1);
 				/* We have to use this to work around some stupid
-				   "conversion ambiguous" error on Linux */
+				 * "conversion ambiguous" error on Linux
+				*/
 				case TL_SIZE: return QVariant::fromValue(item.GetSize());
 				default: return data(index, Qt::DisplayRole);
 			}
@@ -300,17 +325,17 @@
 		{
 			/* this needs to be stored somewhere to replicate Taiga's
 			   "timer" feature */
-			toolbar->addAction(QIcon(":/icons/16x16/arrow-circle-315.png"), tr("&Check new torrents"), [this]{
-				QThreadPool::globalInstance()->start([this] {
-					Refresh();
-				});
+			toolbar->addAction(QIcon(":/icons/16x16/arrow-circle-315.png"), tr("&Check new torrents"), [this] {
+				Refresh();
 			});
 		}
 
 		toolbar->addSeparator();
 
 		{
-			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"), [this] {
+				DownloadSelection();
+			});
 		}
 
 		{
@@ -335,7 +360,7 @@
 	}
 
 	{
-		QTreeView* treeview = new QTreeView(this);
+		treeview = new QTreeView(this);
 		treeview->setUniformRowHeights(true);
 		treeview->setAllColumnsShowFocus(false);
 		treeview->setAlternatingRowColors(true);
@@ -359,10 +384,44 @@
 	}
 }
 
+void TorrentsPage::DownloadSelection() {
+	/* we only want one of these at a time, because if we don't
+	 * we have the possibility of going into Multithreading Hell
+	*/
+	static QThread* thread = nullptr;
+
+	if (!model || thread)
+		return;
+
+	const QItemSelection selection = sort_model->mapSelectionToSource(treeview->selectionModel()->selection());
+
+	thread = QThread::create([this, selection] {
+		model->DownloadTorrents(selection);
+	});
+
+	connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+	connect(thread, &QThread::finished, this, [&] { thread = nullptr; });
+
+	thread->start();
+}
+
 void TorrentsPage::Refresh() {
 	if (!model)
 		return;
-	model->RefreshTorrentList();
+
+	HTTP::GetThread* thread = new HTTP::GetThread(session.config.torrents.feed_link);
+
+	connect(thread, &HTTP::GetThread::ReceivedData, this, [&](const QByteArray& ba) {
+		/* This is to make sure we aren't in a different thread
+		 * messing around with GUI stuff
+		*/
+		treeview->setUpdatesEnabled(false);
+		model->ParseTorrentList(ba);
+		treeview->setUpdatesEnabled(true);
+	});
+	connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+
+	thread->start();
 }
 
 #include "gui/pages/moc_torrents.cpp"
--- a/src/gui/theme.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/gui/theme.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -11,15 +11,12 @@
 #	include "sys/win32/dark_theme.h"
 #endif
 
-/* This is, believe it or not, one of the hardest things I've implemented :/
-     1. Dark mode stuff in Qt changes a lot and Qt 5 and Qt 6 are massively different
-     2. Some widgets, i.e. QTabWidget, QTabBar, etc., just completely IGNORE the QPalette setting
-     3. I don't want to use the Fusion style on every single platform
-     4. Windows dark mode support in Qt 6.5 (with Fusion) is completely unavoidable
-        (not a joke btw, it's retarded)
-   These four already make it really difficult, but along with that, I don't even remember if
-   OS X dark mode support even works still; I remember the background of some of the widgets
-   would refuse to update for whatever reason. */
+/* Weird quirks of this implementation:
+ *   1. Dark mode stuff in Qt changes a lot and Qt 5 and Qt 6 are massively different
+ *   2. Some widgets, i.e. QTabWidget, QTabBar, etc., just completely IGNORE the QPalette setting
+ *      on different platforms and the only way to fix it is by using Fusion
+ *   3. Windows dark mode support in Qt 6.5 (with Fusion) is completely unavoidable
+*/
 
 namespace Theme {
 
@@ -88,10 +85,10 @@
 void Theme::SetStyleSheet(Themes theme) {
 	switch (theme) {
 		case Themes::DARK: {
-			QColor darkGray(53, 53, 53);
-			QColor gray(128, 128, 128);
-			QColor black(25, 25, 25);
-			QColor blue(42, 130, 218);
+			const QColor darkGray(53, 53, 53);
+			const QColor gray(128, 128, 128);
+			const QColor black(25, 25, 25);
+			const QColor blue(42, 130, 218);
 
 			QPalette pal(QApplication::style()->standardPalette());
 			pal.setColor(QPalette::Window, darkGray);
@@ -114,15 +111,21 @@
 			pal.setColor(QPalette::Disabled, QPalette::Light, darkGray);
 			qApp->setPalette(pal);
 
-			QFile f(":dark.qss");
-			if (!f.exists())
-				break; // how?
-			f.open(QFile::ReadOnly | QFile::Text);
-			QTextStream ts(&f);
-			qApp->setStyleSheet(ts.readAll());
+#ifdef WIN32
+			qApp->setStyleSheet([]{
+				QFile f(":/dark.qss");
+				if (!f.exists())
+					return QStringLiteral("");
+				f.open(QFile::ReadOnly | QFile::Text);
+				QTextStream ts(&f);
+				return ts.readAll();
+			}());
+#endif
 			break;
 		}
 		default:
+			/* this sucks, it relies on the standard palette which
+			 * may or may not be a dark style itself. */
 			QPalette pal(QApplication::style()->standardPalette());
 #ifdef WIN32 /* fuck you Qt 6 */
 			pal.setColor(QPalette::Window, QColor(0xF0, 0xF0, 0xF0));
--- a/src/gui/widgets/poster.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/gui/widgets/poster.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -12,7 +12,7 @@
 #include <QLabel>
 #include <QMessageBox>
 #include <QPixmap>
-#include <QThreadPool>
+#include <QThread>
 #include <QUrl>
 #include <curl/curl.h>
 
@@ -35,10 +35,19 @@
 }
 
 void Poster::SetAnime(const Anime::Anime& anime) {
-	QThreadPool::globalInstance()->start([this, anime] {
-		QByteArray ba = HTTP::Get(anime.GetPosterUrl(), {});
-		ImageDownloadFinished(ba);
-	});
+	{
+		QByteArray ba;
+
+		QThread* thread = QThread::create([&] {
+			ba = HTTP::Get(anime.GetPosterUrl(), {});
+		});
+
+		connect(thread, &QThread::finished, this, [&] {
+			ImageDownloadFinished(ba);
+		});
+
+		thread->start();
+	}
 
 	label->disconnect();
 	connect(label, &ClickableLabel::clicked, this,
--- a/src/main.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/main.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -10,6 +10,10 @@
 
 int main(int argc, char** argv) {
 	QApplication app(argc, argv);
+#if !(defined(WIN32) || defined(MACOSX))
+	/* force Fusion */
+	app.setStyle("Fusion");
+#endif
 
 	session.config.Load();
 	session.config.locale.RefreshAvailableLocales();
--- a/src/track/media.cc	Tue Jan 09 08:05:36 2024 -0500
+++ b/src/track/media.cc	Sat Jan 13 09:43:41 2024 -0500
@@ -44,9 +44,13 @@
 			for (const auto& info : media.information) {
 				switch (info.type) {
 					case animia::MediaInfoType::File:
-					case animia::MediaInfoType::Title:
 						vec.push_back(std::filesystem::path(info.value).filename().u8string());
 						success |= true;
+						break;
+					case animia::MediaInfoType::Title:
+						vec.push_back(info.value);
+						success |= true;
+						break;
 					default:
 						break;
 				}