Mercurial > minori
changeset 230:2f5a9247e501
torrents: implement download button
erg
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Sat, 13 Jan 2024 09:42:02 -0500 |
parents | adc20fa321c1 |
children | 69f4768a820c |
files | dep/animia/src/fd/xnu.cc include/core/filesystem.h include/core/http.h include/gui/pages/torrents.h src/core/filesystem.cc src/core/http.cc src/core/strings.cc src/gui/pages/anime_list.cc src/gui/pages/torrents.cc src/gui/theme.cc src/gui/widgets/poster.cc src/track/media.cc |
diffstat | 12 files changed, 183 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/dep/animia/src/fd/xnu.cc Wed Jan 10 21:23:57 2024 -0500 +++ b/dep/animia/src/fd/xnu.cc Sat Jan 13 09:42:02 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/include/core/filesystem.h Sat Jan 13 09:42:02 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/include/core/http.h Sat Jan 13 09:42:02 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/include/gui/pages/torrents.h Sat Jan 13 09:42:02 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/src/core/filesystem.cc Sat Jan 13 09:42:02 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/src/core/http.cc Sat Jan 13 09:42:02 2024 -0500 @@ -65,3 +65,5 @@ } } // namespace HTTP + +#include "core/moc_http.cpp"
--- a/src/core/strings.cc Wed Jan 10 21:23:57 2024 -0500 +++ b/src/core/strings.cc Sat Jan 13 09:42:02 2024 -0500 @@ -16,6 +16,7 @@ #include <string> #include <vector> #include <unordered_map> +#include <iostream> namespace Strings { @@ -132,8 +133,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) { @@ -143,7 +151,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 Wed Jan 10 21:23:57 2024 -0500 +++ b/src/gui/pages/anime_list.cc Sat Jan 13 09:42:02 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/src/gui/pages/torrents.cc Sat Jan 13 09:42:02 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/src/gui/theme.cc Sat Jan 13 09:42:02 2024 -0500 @@ -16,9 +16,6 @@ * 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 - * I think what I might end up doing is forcing the Fusion style on any platforms that isn't - * Windows or Mac. I'm not really fond of doing that, but it's the best way to achieve a "good" - * visual style without a substaintial amount of fucking around and subsequent finding out. */ 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); @@ -115,22 +112,20 @@ qApp->setPalette(pal); #ifdef WIN32 - /* This is a dark style sheet that makes things look - * marginally better on Windows. - * - * I'm very close to just giving up and using Fusion - * everywhere. - */ - QFile f(":dark.qss"); - if (!f.exists()) - break; // how? - f.open(QFile::ReadOnly | QFile::Text); - QTextStream ts(&f); - qApp->setStyleSheet(ts.readAll()); + 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 Wed Jan 10 21:23:57 2024 -0500 +++ b/src/gui/widgets/poster.cc Sat Jan 13 09:42:02 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/track/media.cc Wed Jan 10 21:23:57 2024 -0500 +++ b/src/track/media.cc Sat Jan 13 09:42:02 2024 -0500 @@ -11,6 +11,8 @@ #include <vector> #include <filesystem> +#include <iostream> + #include "animia.h" namespace Track { @@ -44,9 +46,13 @@ for (const auto& info : media.information) { switch (info.type) { case animia::MediaInfoType::File: + vec.push_back(std::filesystem::path(info.value).filename().u8string()); + success |= true; + break; case animia::MediaInfoType::Title: - vec.push_back(std::filesystem::path(info.value).filename().string()); + vec.push_back(info.value); success |= true; + break; default: break; }