Game-compatibility - improved

This commit is contained in:
DanielSvoboda 2025-02-06 22:32:31 -03:00
parent 0d498f12b9
commit 550d4cbb34
4 changed files with 42 additions and 106 deletions

View File

@ -19,109 +19,48 @@ CompatibilityInfoClass::CompatibilityInfoClass()
CompatibilityInfoClass::~CompatibilityInfoClass() = default; CompatibilityInfoClass::~CompatibilityInfoClass() = default;
void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool forced) { void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool forced) {
if (!forced) if (!forced && LoadCompatibilityFile())
if (LoadCompatibilityFile())
return;
QNetworkReply* reply = FetchPage(1);
if (!WaitForReply(reply))
return; return;
QUrl url("https://github.com/DanielSvoboda/shadps4-game-compatibility/releases/latest/download/"
"compatibility_data.json");
QNetworkRequest request(url);
QNetworkReply* reply = m_network_manager->get(request);
QProgressDialog dialog(tr("Fetching compatibility data, please wait"), tr("Cancel"), 0, 0, QProgressDialog dialog(tr("Fetching compatibility data, please wait"), tr("Cancel"), 0, 0,
parent); parent);
dialog.setWindowTitle(tr("Loading...")); dialog.setWindowTitle(tr("Loading..."));
int remaining_pages = 0; if (!WaitForReply(reply)) {
if (reply->hasRawHeader("link")) {
QRegularExpression last_page_re("(\\d+)(?=>; rel=\"last\")");
QRegularExpressionMatch last_page_match =
last_page_re.match(QString(reply->rawHeader("link")));
if (last_page_match.hasMatch()) {
remaining_pages = last_page_match.captured(0).toInt() - 1;
}
}
if (reply->error() != QNetworkReply::NoError) {
reply->deleteLater(); reply->deleteLater();
QMessageBox::critical(parent, tr("Error"), QMessageBox::critical(parent, tr("Error"),
tr("Unable to update compatibility data! Try again later.")); tr("Tempo limite ao baixar os dados de compatibilidade."));
// Try loading compatibility_file.json again
if (!forced)
LoadCompatibilityFile();
return; return;
} }
ExtractCompatibilityInfo(reply->readAll()); if (reply->error() != QNetworkReply::NoError) {
QMessageBox::critical(parent, tr("Error"),
QVector<QNetworkReply*> replies(remaining_pages); tr("Unable to update compatibility data! Try again later.") +
QFutureWatcher<void> future_watcher; reply->errorString());
reply->deleteLater();
for (int i = 0; i < remaining_pages; i++) { return;
replies[i] = FetchPage(i + 2);
} }
future_watcher.setFuture(QtConcurrent::map(replies, WaitForReply)); QFile compatibility_file(m_compatibility_filename);
connect(&future_watcher, &QFutureWatcher<void>::finished, [&]() { if (!compatibility_file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
for (int i = 0; i < remaining_pages; i++) { QMessageBox::critical(parent, tr("Error"),
if (replies[i]->bytesAvailable()) { tr("Unable to open compatibility.json for writing."));
if (replies[i]->error() == QNetworkReply::NoError) { reply->deleteLater();
ExtractCompatibilityInfo(replies[i]->readAll()); return;
} }
replies[i]->deleteLater();
} else {
// This means the request timed out
return;
}
}
QFile compatibility_file(m_compatibility_filename); // Writes the received data to the file.
QByteArray json_data = reply->readAll();
compatibility_file.write(json_data);
compatibility_file.close();
reply->deleteLater();
if (!compatibility_file.open(QIODevice::WriteOnly | QIODevice::Truncate | LoadCompatibilityFile();
QIODevice::Text)) {
QMessageBox::critical(parent, tr("Error"),
tr("Unable to open compatibility.json for writing."));
return;
}
QJsonDocument json_doc;
m_compatibility_database["version"] = COMPAT_DB_VERSION;
json_doc.setObject(m_compatibility_database);
compatibility_file.write(json_doc.toJson());
compatibility_file.close();
dialog.reset();
});
connect(&future_watcher, &QFutureWatcher<void>::canceled, [&]() {
// Cleanup if user cancels pulling data
for (int i = 0; i < remaining_pages; i++) {
if (!replies[i]->bytesAvailable()) {
replies[i]->deleteLater();
} else if (!replies[i]->isFinished()) {
replies[i]->abort();
}
}
});
connect(&dialog, &QProgressDialog::canceled, &future_watcher, &QFutureWatcher<void>::cancel);
dialog.setRange(0, remaining_pages);
connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
&QProgressDialog::setValue);
dialog.exec();
}
QNetworkReply* CompatibilityInfoClass::FetchPage(int page_num) {
QUrl url = QUrl("https://api.github.com/repos/shadps4-emu/shadps4-game-compatibility/issues");
QUrlQuery query;
query.addQueryItem("per_page", QString("100"));
query.addQueryItem(
"tags", QString("status-ingame status-playable status-nothing status-boots status-menus"));
query.addQueryItem("page", QString::number(page_num));
url.setQuery(query);
QNetworkRequest request(url);
QNetworkReply* reply = m_network_manager->get(request);
return reply;
} }
bool CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) { bool CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) {
@ -193,14 +132,6 @@ bool CompatibilityInfoClass::LoadCompatibilityFile() {
return false; return false;
} }
// Check database version
int version_number;
if (json_doc.object()["version"].isDouble()) {
if (json_doc.object()["version"].toInt() < COMPAT_DB_VERSION)
return false;
} else
return false;
m_compatibility_database = json_doc.object(); m_compatibility_database = json_doc.object();
return true; return true;
} }

View File

@ -11,8 +11,6 @@
#include "common/config.h" #include "common/config.h"
#include "core/file_format/psf.h" #include "core/file_format/psf.h"
static constexpr int COMPAT_DB_VERSION = 1;
enum class CompatibilityStatus { enum class CompatibilityStatus {
Unknown, Unknown,
Nothing, Nothing,
@ -83,7 +81,6 @@ public:
const QString GetCompatStatusString(const CompatibilityStatus status); const QString GetCompatStatusString(const CompatibilityStatus status);
void ExtractCompatibilityInfo(QByteArray response); void ExtractCompatibilityInfo(QByteArray response);
static bool WaitForReply(QNetworkReply* reply); static bool WaitForReply(QNetworkReply* reply);
QNetworkReply* FetchPage(int page_num);
private: private:
QNetworkAccessManager* m_network_manager; QNetworkAccessManager* m_network_manager;

View File

@ -202,10 +202,14 @@ void MainWindow::CreateDockWindows() {
} }
void MainWindow::LoadGameLists() { void MainWindow::LoadGameLists() {
// Load compatibility database
if (Config::getCompatibilityEnabled())
m_compat_info->LoadCompatibilityFile();
// Update compatibility database // Update compatibility database
if (Config::getCheckCompatibilityOnStartup()) { if (Config::getCheckCompatibilityOnStartup())
m_compat_info->UpdateCompatibilityDatabase(this); m_compat_info->UpdateCompatibilityDatabase(this);
}
// Get game info from game folders. // Get game info from game folders.
m_game_info->GetGameInfo(this); m_game_info->GetGameInfo(this);
if (isTableList) { if (isTableList) {

View File

@ -159,14 +159,18 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
}); });
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
connect(ui->enableCompatibilityCheckBox, &QCheckBox::stateChanged, this, [this](int state) { connect(ui->enableCompatibilityCheckBox, &QCheckBox::stateChanged, this,
[this, m_compat_info](int state) {
#else #else
connect(ui->enableCompatibilityCheckBox, &QCheckBox::checkStateChanged, this, connect(ui->enableCompatibilityCheckBox, &QCheckBox::checkStateChanged, this,
[this](Qt::CheckState state) { [this, m_compat_info](Qt::CheckState state) {
#endif #endif
Config::setCompatibilityEnabled(state); Config::setCompatibilityEnabled(state);
emit CompatibilityChanged(); if (state) {
}); m_compat_info->LoadCompatibilityFile();
}
emit CompatibilityChanged();
});
} }
// Gui TAB // Gui TAB