diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h new file mode 100644 index 000000000..e60fa8e0a --- /dev/null +++ b/launcher/modplatform/ModAPI.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +class ModAPI { + public: + virtual ~ModAPI() = default; + + inline virtual QString getModSearchURL(int, QString, QString, bool, QString) const { return ""; }; + inline virtual QString getVersionsURL(const QString& addonId) const { return ""; }; + inline virtual QString getAuthorURL(const QString& name) const { return ""; }; +}; diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h new file mode 100644 index 000000000..6e2b9e253 --- /dev/null +++ b/launcher/modplatform/flame/FlameAPI.h @@ -0,0 +1,27 @@ +#pragma once + +#include "modplatform/ModAPI.h" + +class FlameAPI : public ModAPI { + public: + inline QString getModSearchURL(int index, QString searchFilter, QString sort, bool fabricCompatible, QString version) const override + { + return QString("https://addons-ecs.forgesvc.net/api/v2/addon/search?" + "gameId=432&" "categoryId=0&" "sectionId=6&" + + "index=%1&" "pageSize=25&" "searchFilter=%2&" + "sort=%3&" "modLoaderType=%4&" "gameVersion=%5") + .arg(index) + .arg(searchFilter) + .arg(sort) + .arg(fabricCompatible ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType + .arg(version); + }; + + inline QString getVersionsURL(const QString& addonId) const override + { + return QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId); + }; + + inline QString getAuthorURL(const QString& name) const override { return ""; }; +}; diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h new file mode 100644 index 000000000..4ae8b8f9d --- /dev/null +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -0,0 +1,25 @@ +#pragma once + +#include "modplatform/ModAPI.h" + +class ModrinthAPI : public ModAPI { + public: + inline QString getModSearchURL(int offset, QString query, QString sort, bool fabricCompatible, QString version) const override + { + return QString("https://api.modrinth.com/v2/search?" + "offset=%1&" "limit=25&" "query=%2&" "index=%3&" + "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") + .arg(offset) + .arg(query) + .arg(sort) + .arg(fabricCompatible ? "fabric" : "forge") + .arg(version); + }; + + inline QString getVersionsURL(const QString& addonId) const override + { + return QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId); + }; + + inline QString getAuthorURL(const QString& name) const override { return "https://modrinth.com/user/" + name; }; +}; diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index a59186f76..02aac34d5 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -1,10 +1,13 @@ #include "ModrinthPackIndex.h" +#include "ModrinthAPI.h" #include "Json.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "net/NetJob.h" +static ModrinthAPI api; + void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj) { pack.addonId = Json::requireString(obj, "project_id"); @@ -17,7 +20,7 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj) ModPlatform::ModpackAuthor modAuthor; modAuthor.name = Json::requireString(obj, "author"); - modAuthor.url = "https://modrinth.com/user/" + modAuthor.name; + modAuthor.url = api.getAuthorURL(modAuthor.name); pack.authors.append(modAuthor); } diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 5bd7e33e1..481f1c560 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -1,6 +1,8 @@ #include "ModModel.h" #include "ModPage.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" #include @@ -95,6 +97,24 @@ void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallbac } } +void ListModel::performPaginatedSearch() +{ + QString mcVersion = ((MinecraftInstance*)((ModPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); + bool hasFabric = !((MinecraftInstance*)((ModPage*)parent())->m_instance) + ->getPackProfile() + ->getComponentVersion("net.fabricmc.fabric-loader") + .isEmpty(); + auto netJob = new NetJob(QString("%1::Search").arg(m_parent->debugName()), APPLICATION->network()); + auto searchUrl = m_parent->apiProvider()->getModSearchURL(nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric, mcVersion); + + netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); + jobPtr = netJob; + jobPtr->start(); + + QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); + QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); +} + void ListModel::searchWithTerm(const QString& term, const int sort) { if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { return; } diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index ae8ceb7c3..23e544f1f 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -3,6 +3,7 @@ #include #include "modplatform/ModIndex.h" +#include "modplatform/ModAPI.h" #include "net/NetJob.h" class ModPage; @@ -30,15 +31,18 @@ class ListModel : public QAbstractListModel { void searchWithTerm(const QString& term, const int sort); protected slots: - virtual void performPaginatedSearch() = 0; virtual void searchRequestFinished() = 0; + void performPaginatedSearch(); + void logoFailed(QString logo); void logoLoaded(QString logo, QIcon out); void searchRequestFailed(QString reason); protected: + virtual const char** getSorts() const = 0; + void requestLogo(QString file, QString url); protected: @@ -56,5 +60,6 @@ class ListModel : public QAbstractListModel { enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; NetJob::Ptr jobPtr; QByteArray response; + }; } // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 8af534a6f..2d47e31c2 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -101,13 +101,8 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName()).arg(current.name), APPLICATION->network()); auto response = new QByteArray(); QString addonId = current.addonId.toString(); - //FIXME - if(debugName() == "Modrinth") - netJob->addNetAction( - Net::Download::makeByteArray(QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId), response)); - else - netJob->addNetAction( - Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response)); + + netJob->addNetAction(Net::Download::makeByteArray(apiProvider()->getVersionsURL(addonId), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]{ onModVersionSucceed(this, response, addonId); diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index c0102549d..4657bc5e6 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -3,6 +3,7 @@ #include #include +#include "modplatform/ModAPI.h" #include "modplatform/ModIndex.h" #include "tasks/Task.h" #include "ui/pages/BasePage.h" @@ -30,6 +31,7 @@ class ModPage : public QWidget, public BasePage { inline virtual QString metaEntryBase() const = 0; virtual bool shouldDisplay() const override = 0; + virtual const ModAPI* apiProvider() const = 0; void openedImpl() override; bool eventFilter(QObject* watched, QEvent* event) override; diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index 5ab6672fa..283f9ce75 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -1,6 +1,5 @@ #include "FlameModModel.h" #include "FlameModPage.h" -#include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include @@ -11,41 +10,6 @@ ListModel::ListModel(FlameModPage* parent) : ModPlatform::ListModel(parent) {} ListModel::~ListModel() {} -const char* sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; - -void ListModel::performPaginatedSearch() -{ - QString mcVersion = ((MinecraftInstance*)((FlameModPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); - bool hasFabric = !((MinecraftInstance*)((FlameModPage*)parent())->m_instance) - ->getPackProfile() - ->getComponentVersion("net.fabricmc.fabric-loader") - .isEmpty(); - auto netJob = new NetJob("Flame::Search", APPLICATION->network()); - auto searchUrl = QString( - "https://addons-ecs.forgesvc.net/api/v2/addon/search?" - "gameId=432&" - "categoryId=0&" - "sectionId=6&" - - "index=%1&" - "pageSize=25&" - "searchFilter=%2&" - "sort=%3&" - "modLoaderType=%4&" - "gameVersion=%5") - .arg(nextSearchOffset) - .arg(currentSearchTerm) - .arg(sorts[currentSort]) - .arg(hasFabric ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType - .arg(mcVersion); - - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - - QObject::connect(netJob, &NetJob::succeeded, this, &FlameMod::ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} void FlameMod::ListModel::searchRequestFinished() { @@ -87,4 +51,11 @@ void FlameMod::ListModel::searchRequestFinished() endInsertRows(); } +const char* sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; + +const char** FlameMod::ListModel::getSorts() const +{ + return sorts; +} + } // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index a585331d8..ae919e639 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -30,8 +30,10 @@ class ListModel : public ModPlatform::ListModel { virtual ~ListModel(); private slots: - void performPaginatedSearch() override; void searchRequestFinished() override; + + private: + const char** getSorts() const override; }; } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index 2daa155f2..e7d98cb08 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -2,6 +2,8 @@ #include "ui/pages/modplatform/ModPage.h" +#include "modplatform/flame/FlameAPI.h" + class FlameModPage : public ModPage { Q_OBJECT @@ -18,7 +20,11 @@ class FlameModPage : public ModPage { inline QString metaEntryBase() const override { return "FlameMods"; }; bool shouldDisplay() const override; + const ModAPI* apiProvider() const override { return &api; }; private: void onModVersionSucceed(ModPage*, QByteArray*, QString) override; + + private: + FlameAPI api; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index d2e86ef80..dc3d14697 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -1,7 +1,6 @@ #include "ModrinthModel.h" #include "ModrinthPage.h" #include "minecraft/MinecraftInstance.h" -#include "minecraft/PackProfile.h" #include @@ -11,37 +10,6 @@ ListModel::ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent) {} ListModel::~ListModel() {} -const char* sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; - -void ListModel::performPaginatedSearch() -{ - QString mcVersion = ((MinecraftInstance*)((ModrinthPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); - bool hasFabric = !((MinecraftInstance*)((ModrinthPage*)parent())->m_instance) - ->getPackProfile() - ->getComponentVersion("net.fabricmc.fabric-loader") - .isEmpty(); - auto netJob = new NetJob("Modrinth::Search", APPLICATION->network()); - auto searchUrl = QString( - "https://api.modrinth.com/v2/search?" - "offset=%1&" - "limit=25&" - "query=%2&" - "index=%3&" - "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") - .arg(nextSearchOffset) - .arg(currentSearchTerm) - .arg(sorts[currentSort]) - .arg(hasFabric ? "fabric" : "forge") - .arg(mcVersion); - - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - - QObject::connect(netJob, &NetJob::succeeded, this, &Modrinth::ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} - void Modrinth::ListModel::searchRequestFinished() { jobPtr.reset(); @@ -80,4 +48,11 @@ void Modrinth::ListModel::searchRequestFinished() endInsertRows(); } +const char* sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; + +const char** Modrinth::ListModel::getSorts() const +{ + return sorts; +} + } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 734923564..b8937b506 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -30,8 +30,10 @@ class ListModel : public ModPlatform::ListModel { virtual ~ListModel(); private slots: - void performPaginatedSearch() override; void searchRequestFinished() override; + + private: + const char** getSorts() const override; }; } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 41c6c31d1..504f42ada 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -2,6 +2,8 @@ #include "ui/pages/modplatform/ModPage.h" +#include "modplatform/modrinth/ModrinthAPI.h" + class ModrinthPage : public ModPage { Q_OBJECT @@ -18,7 +20,11 @@ class ModrinthPage : public ModPage { inline QString metaEntryBase() const override { return "ModrinthPacks"; }; bool shouldDisplay() const override; + const ModAPI* apiProvider() const override { return &api; }; private: void onModVersionSucceed(ModPage*, QByteArray*, QString) override; + + private: + ModrinthAPI api; };