NOISSUE connect twitch URL resolving to modpack resolving. works now.
This commit is contained in:
parent
f74e3db804
commit
63330bf111
@ -1,7 +1,9 @@
|
|||||||
#include "FileResolvingTask.h"
|
#include "FileResolvingTask.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
|
||||||
const char * metabase = "https://cursemeta.dries007.net";
|
namespace {
|
||||||
|
const char * metabase = "https://cursemeta.dries007.net";
|
||||||
|
}
|
||||||
|
|
||||||
Flame::FileResolvingTask::FileResolvingTask(Flame::Manifest& toProcess)
|
Flame::FileResolvingTask::FileResolvingTask(Flame::Manifest& toProcess)
|
||||||
: m_toProcess(toProcess)
|
: m_toProcess(toProcess)
|
||||||
@ -34,70 +36,14 @@ void Flame::FileResolvingTask::netJobFinished()
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
for(auto & bytes: results)
|
for(auto & bytes: results)
|
||||||
{
|
{
|
||||||
|
auto & out = m_toProcess.files[index];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto doc = Json::requireDocument(bytes);
|
failed &= (!out.parseFromBytes(bytes));
|
||||||
auto obj = Json::requireObject(doc);
|
|
||||||
auto & out = m_toProcess.files[index];
|
|
||||||
// result code signifies true failure.
|
|
||||||
if(obj.contains("code"))
|
|
||||||
{
|
|
||||||
qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a negative result:";
|
|
||||||
qCritical() << bytes;
|
|
||||||
failed = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
out.fileName = Json::requireString(obj, "FileNameOnDisk");
|
|
||||||
QString rawUrl = Json::requireString(obj, "DownloadURL");
|
|
||||||
out.url = QUrl(rawUrl, QUrl::TolerantMode);
|
|
||||||
if(!out.url.isValid())
|
|
||||||
{
|
|
||||||
throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl));
|
|
||||||
}
|
|
||||||
// This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience
|
|
||||||
// It is also optional
|
|
||||||
QJsonObject projObj = Json::ensureObject(obj, "_Project", {});
|
|
||||||
if(!projObj.isEmpty())
|
|
||||||
{
|
|
||||||
QString strType = Json::ensureString(projObj, "PackageType", "mod").toLower();
|
|
||||||
if(strType == "singlefile")
|
|
||||||
{
|
|
||||||
out.type = File::Type::SingleFile;
|
|
||||||
}
|
|
||||||
else if(strType == "ctoc")
|
|
||||||
{
|
|
||||||
out.type = File::Type::Ctoc;
|
|
||||||
}
|
|
||||||
else if(strType == "cmod2")
|
|
||||||
{
|
|
||||||
out.type = File::Type::Cmod2;
|
|
||||||
}
|
|
||||||
else if(strType == "mod")
|
|
||||||
{
|
|
||||||
out.type = File::Type::Mod;
|
|
||||||
}
|
|
||||||
else if(strType == "folder")
|
|
||||||
{
|
|
||||||
out.type = File::Type::Folder;
|
|
||||||
}
|
|
||||||
else if(strType == "modpack")
|
|
||||||
{
|
|
||||||
out.type = File::Type::Modpack;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of unknown file type:" << strType;
|
|
||||||
out.type = File::Type::Unknown;
|
|
||||||
failed = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
out.targetFolder = Json::ensureString(projObj, "Path", "mods");
|
|
||||||
}
|
|
||||||
out.resolved = true;
|
|
||||||
}
|
}
|
||||||
catch (const JSONValidationError &e)
|
catch (const JSONValidationError &e)
|
||||||
{
|
{
|
||||||
auto & out = m_toProcess.files[index];
|
|
||||||
qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a parsing error:";
|
qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a parsing error:";
|
||||||
qCritical() << e.cause();
|
qCritical() << e.cause();
|
||||||
qCritical() << "JSON:";
|
qCritical() << "JSON:";
|
||||||
|
@ -64,3 +64,63 @@ void Flame::loadManifest(Flame::Manifest & m, const QString &filepath)
|
|||||||
}
|
}
|
||||||
loadManifestV1(m, obj);
|
loadManifestV1(m, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Flame::File::parseFromBytes(const QByteArray& bytes)
|
||||||
|
{
|
||||||
|
auto doc = Json::requireDocument(bytes);
|
||||||
|
auto obj = Json::requireObject(doc);
|
||||||
|
// result code signifies true failure.
|
||||||
|
if(obj.contains("code"))
|
||||||
|
{
|
||||||
|
qCritical() << "Resolving of" << projectId << fileId << "failed because of a negative result:";
|
||||||
|
qCritical() << bytes;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fileName = Json::requireString(obj, "FileNameOnDisk");
|
||||||
|
QString rawUrl = Json::requireString(obj, "DownloadURL");
|
||||||
|
url = QUrl(rawUrl, QUrl::TolerantMode);
|
||||||
|
if(!url.isValid())
|
||||||
|
{
|
||||||
|
throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl));
|
||||||
|
}
|
||||||
|
// This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience
|
||||||
|
// It is also optional
|
||||||
|
QJsonObject projObj = Json::ensureObject(obj, "_Project", {});
|
||||||
|
if(!projObj.isEmpty())
|
||||||
|
{
|
||||||
|
QString strType = Json::ensureString(projObj, "PackageType", "mod").toLower();
|
||||||
|
if(strType == "singlefile")
|
||||||
|
{
|
||||||
|
type = File::Type::SingleFile;
|
||||||
|
}
|
||||||
|
else if(strType == "ctoc")
|
||||||
|
{
|
||||||
|
type = File::Type::Ctoc;
|
||||||
|
}
|
||||||
|
else if(strType == "cmod2")
|
||||||
|
{
|
||||||
|
type = File::Type::Cmod2;
|
||||||
|
}
|
||||||
|
else if(strType == "mod")
|
||||||
|
{
|
||||||
|
type = File::Type::Mod;
|
||||||
|
}
|
||||||
|
else if(strType == "folder")
|
||||||
|
{
|
||||||
|
type = File::Type::Folder;
|
||||||
|
}
|
||||||
|
else if(strType == "modpack")
|
||||||
|
{
|
||||||
|
type = File::Type::Modpack;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCritical() << "Resolving of" << projectId << fileId << "failed because of unknown file type:" << strType;
|
||||||
|
type = File::Type::Unknown;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
targetFolder = Json::ensureString(projObj, "Path", "mods");
|
||||||
|
}
|
||||||
|
resolved = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -8,6 +8,9 @@ namespace Flame
|
|||||||
{
|
{
|
||||||
struct File
|
struct File
|
||||||
{
|
{
|
||||||
|
// NOTE: throws JSONValidationError
|
||||||
|
bool parseFromBytes(const QByteArray &bytes);
|
||||||
|
|
||||||
int projectId = 0;
|
int projectId = 0;
|
||||||
int fileId = 0;
|
int fileId = 0;
|
||||||
// NOTE: the opposite to 'optional'. This is at the time of writing unused.
|
// NOTE: the opposite to 'optional'. This is at the time of writing unused.
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#include "UrlResolvingTask.h"
|
#include "UrlResolvingTask.h"
|
||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
|
#include <Json.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
namespace {
|
namespace {
|
||||||
const char * metabase = "https://cursemeta.dries007.net";
|
const char * metabase = "https://cursemeta.dries007.net";
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
Flame::UrlResolvingTask::UrlResolvingTask(const QString& toProcess)
|
Flame::UrlResolvingTask::UrlResolvingTask(const QString& toProcess)
|
||||||
: m_url(toProcess)
|
: m_url(toProcess)
|
||||||
@ -13,12 +13,17 @@ Flame::UrlResolvingTask::UrlResolvingTask(const QString& toProcess)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Flame::UrlResolvingTask::executeTask()
|
void Flame::UrlResolvingTask::executeTask()
|
||||||
|
{
|
||||||
|
resolveUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flame::UrlResolvingTask::resolveUrl()
|
||||||
{
|
{
|
||||||
setStatus(tr("Resolving URL..."));
|
setStatus(tr("Resolving URL..."));
|
||||||
setProgress(0, 1);
|
setProgress(0, 1);
|
||||||
m_dljob.reset(new NetJob("URL resolver"));
|
m_dljob.reset(new NetJob("URL resolver"));
|
||||||
|
|
||||||
weAreDigging = false;
|
bool weAreDigging = false;
|
||||||
needle = QString();
|
needle = QString();
|
||||||
|
|
||||||
if(m_url.startsWith("https://")) {
|
if(m_url.startsWith("https://")) {
|
||||||
@ -48,17 +53,12 @@ void Flame::UrlResolvingTask::executeTask()
|
|||||||
}
|
}
|
||||||
auto dl = Net::Download::makeByteArray(QUrl(m_url), &results);
|
auto dl = Net::Download::makeByteArray(QUrl(m_url), &results);
|
||||||
m_dljob->addNetAction(dl);
|
m_dljob->addNetAction(dl);
|
||||||
connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::netJobFinished);
|
|
||||||
m_dljob->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Flame::UrlResolvingTask::netJobFinished()
|
|
||||||
{
|
|
||||||
if(weAreDigging) {
|
if(weAreDigging) {
|
||||||
processHTML();
|
connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::processHTML);
|
||||||
} else {
|
} else {
|
||||||
processCCIP();
|
connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::processCCIP);
|
||||||
}
|
}
|
||||||
|
m_dljob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Flame::UrlResolvingTask::processHTML()
|
void Flame::UrlResolvingTask::processHTML()
|
||||||
@ -83,7 +83,7 @@ void Flame::UrlResolvingTask::processHTML()
|
|||||||
qDebug() << "Found needle: " << found;
|
qDebug() << "Found needle: " << found;
|
||||||
// twitch://www.curseforge.com/minecraft/modpacks/ftb-sky-odyssey/download-client/2697088
|
// twitch://www.curseforge.com/minecraft/modpacks/ftb-sky-odyssey/download-client/2697088
|
||||||
m_url = found;
|
m_url = found;
|
||||||
executeTask();
|
resolveUrl();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emitFailed(tr("Couldn't find the end of the needle in the haystack..."));
|
emitFailed(tr("Couldn't find the end of the needle in the haystack..."));
|
||||||
@ -135,6 +135,36 @@ void Flame::UrlResolvingTask::processCCIP()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qDebug() << "Resolved" << m_url << "as" << m_result.projectId << "/" << m_result.fileId;
|
qDebug() << "Resolved" << m_url << "as" << m_result.projectId << "/" << m_result.fileId;
|
||||||
emitSucceeded();
|
resolveIDs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Flame::UrlResolvingTask::resolveIDs()
|
||||||
|
{
|
||||||
|
setStatus(tr("Resolving mod IDs..."));
|
||||||
|
m_dljob.reset(new NetJob("Mod id resolver"));
|
||||||
|
auto projectIdStr = QString::number(m_result.projectId);
|
||||||
|
auto fileIdStr = QString::number(m_result.fileId);
|
||||||
|
QString metaurl = QString("%1/%2/%3.json").arg(metabase, projectIdStr, fileIdStr);
|
||||||
|
auto dl = Net::Download::makeByteArray(QUrl(metaurl), &results);
|
||||||
|
m_dljob->addNetAction(dl);
|
||||||
|
connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::processCursemeta);
|
||||||
|
m_dljob->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flame::UrlResolvingTask::processCursemeta()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if(m_result.parseFromBytes(results)) {
|
||||||
|
emitSucceeded();
|
||||||
|
qDebug() << results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (const JSONValidationError &e) {
|
||||||
|
|
||||||
|
qCritical() << "Resolving of" << m_result.projectId << m_result.fileId << "failed because of a parsing error:";
|
||||||
|
qCritical() << e.cause();
|
||||||
|
qCritical() << "JSON:";
|
||||||
|
qCritical() << results;
|
||||||
|
}
|
||||||
|
emitFailed(tr("Failed to resolve the modpack file."));
|
||||||
|
}
|
||||||
|
@ -26,7 +26,11 @@ protected:
|
|||||||
protected slots:
|
protected slots:
|
||||||
void processCCIP();
|
void processCCIP();
|
||||||
void processHTML();
|
void processHTML();
|
||||||
void netJobFinished();
|
void processCursemeta();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resolveUrl();
|
||||||
|
void resolveIDs();
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
QString m_url;
|
QString m_url;
|
||||||
@ -34,7 +38,6 @@ private: /* data */
|
|||||||
Flame::File m_result;
|
Flame::File m_result;
|
||||||
QByteArray results;
|
QByteArray results;
|
||||||
NetJobPtr m_dljob;
|
NetJobPtr m_dljob;
|
||||||
bool weAreDigging = false;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "MultiMC.h"
|
#include "MultiMC.h"
|
||||||
#include "dialogs/NewInstanceDialog.h"
|
#include "dialogs/NewInstanceDialog.h"
|
||||||
|
#include <InstanceImportTask.h>
|
||||||
|
|
||||||
TwitchPage::TwitchPage(NewInstanceDialog* dialog, QWidget *parent)
|
TwitchPage::TwitchPage(NewInstanceDialog* dialog, QWidget *parent)
|
||||||
: QWidget(parent), ui(new Ui::TwitchPage), dialog(dialog)
|
: QWidget(parent), ui(new Ui::TwitchPage), dialog(dialog)
|
||||||
@ -42,6 +43,13 @@ void TwitchPage::checkDone()
|
|||||||
{
|
{
|
||||||
auto result = m_modIdResolver->getResults();
|
auto result = m_modIdResolver->getResults();
|
||||||
auto formatted = QString("Project %1, File %2").arg(result.projectId).arg(result.fileId);
|
auto formatted = QString("Project %1, File %2").arg(result.projectId).arg(result.fileId);
|
||||||
ui->twitchLabel->setText(formatted);
|
if(result.resolved && result.type == Flame::File::Type::Modpack) {
|
||||||
|
ui->twitchLabel->setText(formatted);
|
||||||
|
QFileInfo fi(result.fileName);
|
||||||
|
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(result.url));
|
||||||
|
} else {
|
||||||
|
ui->twitchLabel->setPixmap(QPixmap(QString::fromUtf8(":/assets/deadglitch")));
|
||||||
|
dialog->setSuggestedPack();
|
||||||
|
}
|
||||||
m_modIdResolver.reset();
|
m_modIdResolver.reset();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user