fix: ensure Application accepts URLs and local files form cmd args
refactor: Move curseforge:// url scheme detection to Import Page feat: pass along extra CF pack info so pack metadata is established. Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
parent
54fb799d95
commit
a3173b5371
@ -216,11 +216,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
|
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
|
||||||
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
|
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
|
||||||
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
|
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
|
||||||
{{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"},
|
{{"I", "import"}, "Import instance or resource from specified local path or URL", "url"},
|
||||||
{"show", "Opens the window for the specified instance (by instance ID)", "show"}
|
{"show", "Opens the window for the specified instance (by instance ID)", "show"}
|
||||||
});
|
});
|
||||||
// Has to be positional for some OS to handle that properly
|
// Has to be positional for some OS to handle that properly
|
||||||
parser.addPositionalArgument("urls","import the resource at the given url(s) (URL to modpack Zip / local Zip / curseforge:// modpack link)","[urls...]");
|
parser.addPositionalArgument("urls","import the resource at the given url(s) (same as -I / --import)","[urls...]");
|
||||||
|
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
parser.addVersionOption();
|
parser.addVersionOption();
|
||||||
@ -234,13 +234,13 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_instanceIdToShowWindowOf = parser.value("show");
|
m_instanceIdToShowWindowOf = parser.value("show");
|
||||||
|
|
||||||
for (auto zip_path : parser.values("import")){
|
for (auto url : parser.values("import")){
|
||||||
m_zipsToImport.append(QUrl::fromLocalFile(QFileInfo(zip_path).absoluteFilePath()));
|
addImportUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// treat unspecified positional arguments as import urls
|
// treat unspecified positional arguments as import urls
|
||||||
for (auto zip_path : parser.positionalArguments()) {
|
for (auto url : parser.positionalArguments()) {
|
||||||
m_zipsToImport.append(QUrl::fromLocalFile(QFileInfo(zip_path).absoluteFilePath()));
|
addImportUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// error if --launch is missing with --server or --profile
|
// error if --launch is missing with --server or --profile
|
||||||
@ -345,12 +345,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
activate.command = "activate";
|
activate.command = "activate";
|
||||||
m_peerInstance->sendMessage(activate.serialize(), timeout);
|
m_peerInstance->sendMessage(activate.serialize(), timeout);
|
||||||
|
|
||||||
if(!m_zipsToImport.isEmpty())
|
if(!m_urlsToImport.isEmpty())
|
||||||
{
|
{
|
||||||
for (auto zip_url : m_zipsToImport) {
|
for (auto url : m_urlsToImport) {
|
||||||
ApplicationMessage import;
|
ApplicationMessage import;
|
||||||
import.command = "import";
|
import.command = "import";
|
||||||
import.args.insert("path", zip_url.toString());
|
import.args.insert("path", url.toString());
|
||||||
m_peerInstance->sendMessage(import.serialize(), timeout);
|
m_peerInstance->sendMessage(import.serialize(), timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1027,10 +1027,10 @@ void Application::performMainStartupAction()
|
|||||||
showMainWindow(false);
|
showMainWindow(false);
|
||||||
qDebug() << "<> Main window shown.";
|
qDebug() << "<> Main window shown.";
|
||||||
}
|
}
|
||||||
if(!m_zipsToImport.isEmpty())
|
if(!m_urlsToImport.isEmpty())
|
||||||
{
|
{
|
||||||
qDebug() << "<> Importing from zip:" << m_zipsToImport;
|
qDebug() << "<> Importing from url:" << m_urlsToImport;
|
||||||
m_mainWindow->processURLs( m_zipsToImport );
|
m_mainWindow->processURLs( m_urlsToImport );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1083,7 +1083,12 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
qWarning() << "Received" << command << "message without a zip path/URL.";
|
qWarning() << "Received" << command << "message without a zip path/URL.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_mainWindow->processURLs({ QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath()) });
|
auto local_file = QFileInfo(path);
|
||||||
|
if (local_file.exists()) {
|
||||||
|
m_mainWindow->processURLs({ QUrl::fromLocalFile(local_file.absoluteFilePath()) });
|
||||||
|
} else {
|
||||||
|
m_mainWindow->processURLs({ QUrl::fromUserInput(path) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(command == "launch")
|
else if(command == "launch")
|
||||||
{
|
{
|
||||||
@ -1735,3 +1740,14 @@ void Application::triggerUpdateCheck()
|
|||||||
qDebug() << "Updater not available.";
|
qDebug() << "Updater not available.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::addImportUrl(QString const& url)
|
||||||
|
{
|
||||||
|
auto local_file = QFileInfo(url);
|
||||||
|
if (local_file.exists()){
|
||||||
|
m_urlsToImport.append(QUrl::fromLocalFile(local_file.absoluteFilePath()));
|
||||||
|
} else {
|
||||||
|
m_urlsToImport.append(QUrl::fromUserInput(url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -211,6 +211,8 @@ public:
|
|||||||
|
|
||||||
int suitableMaxMem();
|
int suitableMaxMem();
|
||||||
|
|
||||||
|
void addImportUrl(QString const& url);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateAllowedChanged(bool status);
|
void updateAllowedChanged(bool status);
|
||||||
void globalSettingsAboutToOpen();
|
void globalSettingsAboutToOpen();
|
||||||
@ -314,7 +316,7 @@ public:
|
|||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_liveCheck = false;
|
bool m_liveCheck = false;
|
||||||
QList<QUrl> m_zipsToImport;
|
QList<QUrl> m_urlsToImport;
|
||||||
QString m_instanceIdToShowWindowOf;
|
QString m_instanceIdToShowWindowOf;
|
||||||
std::unique_ptr<QFile> logFile;
|
std::unique_ptr<QFile> logFile;
|
||||||
};
|
};
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -89,46 +90,7 @@ void InstanceImportTask::executeTask()
|
|||||||
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
|
||||||
m_downloadRequired = true;
|
m_downloadRequired = true;
|
||||||
|
|
||||||
if (m_sourceUrl.scheme() == "curseforge") {
|
|
||||||
// need to find the download link for the modpack
|
|
||||||
// format of url curseforge://install?addonId=IDHERE&fileId=IDHERE
|
|
||||||
QUrlQuery query(m_sourceUrl);
|
|
||||||
auto addonId = query.allQueryItemValues("addonId")[0];
|
|
||||||
auto fileId = query.allQueryItemValues("fileId")[0];
|
|
||||||
auto array = new QByteArray();
|
|
||||||
auto req = new NetJob("Curseforge Meta", APPLICATION->network());
|
|
||||||
req->addNetAction(
|
|
||||||
Net::Download::makeByteArray(QUrl(QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(addonId, fileId)), array));
|
|
||||||
connect(req, &NetJob::finished, [array, req] {
|
|
||||||
req->deleteLater();
|
|
||||||
delete array;
|
|
||||||
});
|
|
||||||
connect(req, &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
|
||||||
connect(req, &NetJob::succeeded, [array, this] {
|
|
||||||
auto doc = Json::requireDocument(*array);
|
|
||||||
// No way to find out if it's a mod or a modpack before here
|
|
||||||
// And also we need to check if it ends with .zip, instead of any better way
|
|
||||||
auto fileName = Json::ensureString(Json::ensureObject(Json::ensureObject(doc.object()), "data"), "fileName");
|
|
||||||
if (fileName.endsWith(".zip")) {
|
|
||||||
// Have to use ensureString then use QUrl to get proper url encoding
|
|
||||||
m_sourceUrl = QUrl(
|
|
||||||
Json::ensureString(Json::ensureObject(Json::ensureObject(doc.object()), "data"), "downloadUrl", "", "downloadUrl"));
|
|
||||||
if (!m_sourceUrl.isValid()) {
|
|
||||||
emitFailed(tr("The modpack is blocked ! Please download it manually"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
downloadFromUrl();
|
downloadFromUrl();
|
||||||
} else {
|
|
||||||
emitFailed(tr("This url isn't a valid modpack !"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
connect(req, &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
|
||||||
connect(req, &NetJob::stepProgress, this, &InstanceImportTask::propogateStepProgress);
|
|
||||||
connect(req, &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
|
|
||||||
req->start();
|
|
||||||
} else {
|
|
||||||
downloadFromUrl();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,12 +35,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ImportPage.h"
|
#include "ImportPage.h"
|
||||||
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
#include "ui_ImportPage.h"
|
#include "ui_ImportPage.h"
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QValidator>
|
#include <QValidator>
|
||||||
|
|
||||||
#include "ui/dialogs/NewInstanceDialog.h"
|
#include "ui/dialogs/NewInstanceDialog.h"
|
||||||
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
|
||||||
|
#include "Json.h"
|
||||||
|
|
||||||
#include "InstanceImportTask.h"
|
#include "InstanceImportTask.h"
|
||||||
|
|
||||||
@ -123,8 +127,62 @@ void ImportPage::updateState()
|
|||||||
dialog->setSuggestedIcon("default");
|
dialog->setSuggestedIcon("default");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (url.scheme() == "curseforge")
|
||||||
|
{
|
||||||
|
// need to find the download link for the modpack
|
||||||
|
// format of url curseforge://install?addonId=IDHERE&fileId=IDHERE
|
||||||
|
QUrlQuery query(url);
|
||||||
|
auto addonId = query.allQueryItemValues("addonId")[0];
|
||||||
|
auto fileId = query.allQueryItemValues("fileId")[0];
|
||||||
|
auto array = new QByteArray();
|
||||||
|
auto req = unique_qobject_ptr<NetJob>(new NetJob("Curseforge Meta", APPLICATION->network()));
|
||||||
|
req->addNetAction(
|
||||||
|
Net::Download::makeByteArray(QUrl(QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(addonId, fileId)), array));
|
||||||
|
|
||||||
|
connect(req.get(), &NetJob::finished, [array] {
|
||||||
|
delete array;
|
||||||
|
});
|
||||||
|
connect(req.get(), &NetJob::failed, this, [this](QString reason){
|
||||||
|
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||||
|
});
|
||||||
|
connect(req.get(), &NetJob::succeeded, this, [this, array, addonId, fileId] {
|
||||||
|
qDebug() << "Returned CFURL Json:\n" << array->toStdString().c_str();
|
||||||
|
auto doc = Json::requireDocument(*array);
|
||||||
|
// No way to find out if it's a mod or a modpack before here
|
||||||
|
// And also we need to check if it ends with .zip, instead of any better way
|
||||||
|
auto fileName = Json::ensureString(Json::ensureObject(Json::ensureObject(doc.object()), "data"), "fileName");
|
||||||
|
if (fileName.endsWith(".zip")) {
|
||||||
|
// Have to use ensureString then use QUrl to get proper url encoding
|
||||||
|
auto dl_url = QUrl(
|
||||||
|
Json::ensureString(Json::ensureObject(Json::ensureObject(doc.object()), "data"), "downloadUrl", "", "downloadUrl"));
|
||||||
|
if (!dl_url.isValid()) {
|
||||||
|
CustomMessageBox::selectable(this, tr("Error"), tr("The modpack is blocked ! Please download it manually"), QMessageBox::Critical)->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo dl_file(dl_url.fileName());
|
||||||
|
QString pack_name = Json::ensureString(Json::ensureObject(Json::ensureObject(doc.object()), "data"), "displayName", dl_file.completeBaseName(), "displayName");
|
||||||
|
|
||||||
|
QMap<QString, QString> extra_info;
|
||||||
|
extra_info.insert("pack_id", addonId);
|
||||||
|
extra_info.insert("pack_version_id", fileId);
|
||||||
|
|
||||||
|
dialog->setSuggestedPack(pack_name, new InstanceImportTask(dl_url, this, std::move(extra_info)));
|
||||||
|
dialog->setSuggestedIcon("default");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
CustomMessageBox::selectable(this, tr("Error"), tr("This url isn't a valid modpack !"), QMessageBox::Critical)->show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ProgressDialog dlUrlDialod(this);
|
||||||
|
dlUrlDialod.setSkipButton(true, tr("Abort"));
|
||||||
|
dlUrlDialod.execWithTask(req.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
if(input.endsWith("?client=y")) {
|
if(input.endsWith("?client=y")) {
|
||||||
input.chop(9);
|
input.chop(9);
|
||||||
input.append("/file");
|
input.append("/file");
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>- CurseForge modpacks (ZIP)</string>
|
<string>- CurseForge modpacks (ZIP / curseforge:// URL)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
|
Loading…
Reference in New Issue
Block a user