mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-14 19:18:55 -07:00
Add the option to load decklists from Archidekt, Deckstats, Moxfield, TappedOut in deck editor and lobby (#6030)
* Add the option to load decklists from Archidekt, Deckstats, Moxfield, TappedOut in deck editor and lobby. Took 3 hours 34 minutes Took 9 seconds Took 12 seconds * Properly set quantities. Took 11 minutes * Warnings. Took 5 minutes * Static regexes. Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com> * Category loggings and better warnings. Took 18 minutes Took 42 seconds * use loadFromStream_Plain instead of manually adding CardNodes to the DeckList. Took 30 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de> Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
This commit is contained in:
parent
83b90d472f
commit
e05dad4267
13 changed files with 444 additions and 3 deletions
145
cockatrice/src/dialogs/dlg_load_deck_from_website.cpp
Normal file
145
cockatrice/src/dialogs/dlg_load_deck_from_website.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include "dlg_load_deck_from_website.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QEventLoop>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkReply>
|
||||
|
||||
DlgLoadDeckFromWebsite::DlgLoadDeckFromWebsite(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
nam = new QNetworkAccessManager(this);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
instructionLabel = new QLabel(this);
|
||||
layout->addWidget(instructionLabel);
|
||||
|
||||
urlEdit = new QLineEdit(this);
|
||||
urlEdit->setText(QApplication::clipboard()->text());
|
||||
|
||||
layout->addWidget(urlEdit);
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
layout->addWidget(buttonBox);
|
||||
|
||||
if (testValidUrl()) {
|
||||
QMetaObject::invokeMethod(this, "accept", Qt::QueuedConnection);
|
||||
hide();
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void DlgLoadDeckFromWebsite::retranslateUi()
|
||||
{
|
||||
instructionLabel->setText(tr("Paste a link to a decklist site here to import it.\n(Archidekt, Deckstats, Moxfield, "
|
||||
"and TappedOut are supported.)"));
|
||||
}
|
||||
|
||||
bool DlgLoadDeckFromWebsite::testValidUrl()
|
||||
{
|
||||
ParsedDeckInfo info;
|
||||
return DeckLinkToApiTransformer::parseDeckUrl(urlEdit->text(), info);
|
||||
}
|
||||
|
||||
void DlgLoadDeckFromWebsite::accept()
|
||||
{
|
||||
ParsedDeckInfo info;
|
||||
if (DeckLinkToApiTransformer::parseDeckUrl(urlEdit->text(), info)) {
|
||||
qCInfo(DlgLoadDeckFromWebsiteLog) << info.baseUrl << info.deckID << info.fullUrl;
|
||||
|
||||
auto jsonParser = createParserForProvider(info.provider);
|
||||
if (!jsonParser && info.provider != DeckProvider::Deckstats && info.provider != DeckProvider::TappedOut) {
|
||||
qCWarning(DlgLoadDeckFromWebsiteLog) << "No parser found for provider";
|
||||
QMessageBox::warning(this, tr("Load Deck from Website"),
|
||||
tr("No parser available for this deck provider.\n (Archidekt, Deckstats, Moxfield, "
|
||||
"and TappedOut are supported.)"));
|
||||
QDialog::reject();
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(QUrl(info.fullUrl));
|
||||
QNetworkReply *reply = nam->get(request);
|
||||
|
||||
QEventLoop loop;
|
||||
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(DlgLoadDeckFromWebsiteLog) << "Network error:" << reply->errorString();
|
||||
QMessageBox::warning(this, tr("Load Deck from Website"), tr("Network error: %1").arg(reply->errorString()));
|
||||
reply->deleteLater();
|
||||
QDialog::reject();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray responseData = reply->readAll();
|
||||
reply->deleteLater();
|
||||
|
||||
// Special handling for Deckstats and TappedOut .txt
|
||||
if (info.provider == DeckProvider::Deckstats || info.provider == DeckProvider::TappedOut) {
|
||||
QString deckText = QString::fromUtf8(responseData);
|
||||
if (deckText.isEmpty()) {
|
||||
qCWarning(DlgLoadDeckFromWebsiteLog) << "Response is empty";
|
||||
QMessageBox::warning(this, tr("Load Deck from Website"), tr("Received empty deck data."));
|
||||
QDialog::reject();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the plain text deck here
|
||||
DeckLoader *loader = new DeckLoader();
|
||||
QTextStream stream(&deckText);
|
||||
loader->loadFromStream_Plain(stream, false);
|
||||
loader->resolveSetNameAndNumberToProviderID();
|
||||
deck = loader;
|
||||
|
||||
QDialog::accept();
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal JSON parsing for other providers
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(responseData, &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qCWarning(DlgLoadDeckFromWebsiteLog) << "JSON parse error:" << parseError.errorString();
|
||||
QMessageBox::warning(this, tr("Load Deck from Website"),
|
||||
tr("Failed to parse deck data: %1").arg(parseError.errorString()));
|
||||
QDialog::reject();
|
||||
return;
|
||||
}
|
||||
|
||||
deck = jsonParser->parse(doc.object());
|
||||
QDialog::accept();
|
||||
|
||||
} else {
|
||||
qCInfo(DlgLoadDeckFromWebsiteLog) << "URL not recognized";
|
||||
QMessageBox::warning(this, tr("Load Deck from Website"),
|
||||
tr("The provided URL is not recognized as a valid deck URL.\n"
|
||||
"Valid deck URLs look like this:\n\n"
|
||||
"https://archidekt.com/decks/9999999\n"
|
||||
"https://deckstats.net/decks/99999/9999999-your-deck-name/en\n"
|
||||
"https://moxfield.com/decks/XYZxx-XYZ99Yyy-xyzXzzz\n"
|
||||
"https://tappedout.net/mtg-decks/your-deck-name/"));
|
||||
QDialog::reject();
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<IJsonDeckParser> DlgLoadDeckFromWebsite::createParserForProvider(DeckProvider provider)
|
||||
{
|
||||
switch (provider) {
|
||||
case DeckProvider::Archidekt:
|
||||
return QSharedPointer<IJsonDeckParser>(new ArchidektJsonParser());
|
||||
case DeckProvider::Moxfield:
|
||||
return QSharedPointer<IJsonDeckParser>(new MoxfieldJsonParser());
|
||||
default:
|
||||
return QSharedPointer<IJsonDeckParser>(nullptr);
|
||||
}
|
||||
}
|
||||
40
cockatrice/src/dialogs/dlg_load_deck_from_website.h
Normal file
40
cockatrice/src/dialogs/dlg_load_deck_from_website.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef DLG_LOAD_DECK_FROM_WEBSITE_H
|
||||
#define DLG_LOAD_DECK_FROM_WEBSITE_H
|
||||
|
||||
#include "../client/network/parsers/deck_link_to_api_transformer.h"
|
||||
#include "../client/network/parsers/interface_json_deck_parser.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(DlgLoadDeckFromWebsiteLog, "dlg_load_deck_from_website");
|
||||
|
||||
class DlgLoadDeckFromWebsite : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DlgLoadDeckFromWebsite(QWidget *parent);
|
||||
void retranslateUi();
|
||||
bool testValidUrl();
|
||||
DeckLoader *deck;
|
||||
|
||||
DeckLoader *getDeck()
|
||||
{
|
||||
return deck;
|
||||
}
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *nam;
|
||||
QVBoxLayout *layout;
|
||||
QLabel *instructionLabel;
|
||||
QLineEdit *urlEdit;
|
||||
|
||||
public slots:
|
||||
void accept() override;
|
||||
QSharedPointer<IJsonDeckParser> createParserForProvider(DeckProvider provider);
|
||||
};
|
||||
|
||||
#endif // DLG_LOAD_DECK_FROM_WEBSITE_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue