diff --git a/src/arcadedb.cpp b/src/arcadedb.cpp index ca7779e4..2bc495d5 100644 --- a/src/arcadedb.cpp +++ b/src/arcadedb.cpp @@ -72,6 +72,7 @@ void ArcadeDB::getSearchResults(QList &gameEntries, game.title = jsonObj.value("title").toString(); game.platform = platform; + game.releaseDate = jsonObj.value("year").toString(); gameEntries.append(game); } diff --git a/src/igdb.cpp b/src/igdb.cpp index 9bbc6f73..dd37b953 100644 --- a/src/igdb.cpp +++ b/src/igdb.cpp @@ -71,7 +71,9 @@ void Igdb::getSearchResults(QList &gameEntries, QString searchName, // null") limiter.exec(); netComm->request(baseUrl + "/search/", - "fields game.name,game.platforms.name; search \"" + + "fields " + "game.name,game.platforms.name,game.release_dates.date," + "game.release_dates.platform; search \"" + searchName + "\"; where game != null & game.version_parent = null;", headers); @@ -102,10 +104,24 @@ void Igdb::getSearchResults(QList &gameEntries, QString searchName, QJsonArray jsonPlatforms = jsonGame.toObject()["game"].toObject()["platforms"].toArray(); for (const auto &jsonPlatform : jsonPlatforms) { - game.id.append( - ";" + QString::number(jsonPlatform.toObject()["id"].toInt())); + int platformId = jsonPlatform.toObject()["id"].toInt(); + game.id.append(";" + QString::number(platformId)); game.platform = jsonPlatform.toObject()["name"].toString(); if (platformMatch(game.platform, platform)) { + QJsonArray jsonReleaseDates = jsonGame.toObject()["game"] + .toObject()["release_dates"] + .toArray(); + for (const auto &releaseDate : jsonReleaseDates) { + if (releaseDate.toObject()["platform"].toInt() == + platformId) { + game.releaseDate = + QDateTime::fromMSecsSinceEpoch( + (qint64)releaseDate.toObject()["date"].toInt() * + 1000) + .date() + .toString(Qt::ISODate); + } + } gameEntries.append(game); } } @@ -165,7 +181,7 @@ void Igdb::getReleaseDate(GameEntry &game) { game.releaseDate = QDateTime::fromMSecsSinceEpoch( (qint64)jsonDate.toObject()["date"].toInt() * 1000) - .toString("yyyyMMdd"); + .toString("yyyy-MM-dd"); regionMatch = true; break; } diff --git a/src/mobygames.cpp b/src/mobygames.cpp index 0013fc5a..844c130f 100644 --- a/src/mobygames.cpp +++ b/src/mobygames.cpp @@ -121,6 +121,7 @@ void MobyGames::getSearchResults(QList &gameEntries, StrTools::unMagic( "175;229;170;189;188;202;211;117;164;165;185;209;" "164;234;180;155;199;209;224;231;193;190;173;175"); + game.releaseDate = jsonPlatform["first_release_date"].toString(); game.platform = jsonPlatform["platform_name"].toString(); bool matchPlafId = gamePlafId == platformId; if (platformMatch(game.platform, platform) || matchPlafId) { diff --git a/src/scraperworker.cpp b/src/scraperworker.cpp index a35b21fa..5ad9a9cb 100644 --- a/src/scraperworker.cpp +++ b/src/scraperworker.cpp @@ -41,11 +41,14 @@ #include "thegamesdb.h" #include "worldofspectrum.h" +#include #include #include #include #include +constexpr int UNDEF_YEAR = -1; + ScraperWorker::ScraperWorker(QSharedPointer queue, QSharedPointer cache, QSharedPointer manager, @@ -201,7 +204,18 @@ void ScraperWorker::run() { } game.found = false; } else { - game = getBestEntry(gameEntries, compareTitle, lowestDistance); + int compareYear = UNDEF_YEAR; + QString baseParNotes = + NameTools::getParNotes(info.completeBaseName()); + // If baseParNotes matches (NNNN), compareYear = NNNN + QRegularExpressionMatch match = + QRegularExpression("\\((\\d{4})\\)").match(baseParNotes); + if (match.hasMatch()) { + QString yyyy = match.captured(1); + compareYear = yyyy.toInt(); + } + game = getBestEntry(gameEntries, compareTitle, compareYear, + lowestDistance); if (config.interactive && !fromCache) { game = getEntryFromUser(gameEntries, game, compareTitle, lowestDistance); @@ -527,13 +541,30 @@ unsigned int ScraperWorker::editDistance(const std::string &s1, } GameEntry ScraperWorker::getBestEntry(const QList &gameEntries, - QString compareTitle, + QString compareTitle, int compareYear, int &lowestDistance) { GameEntry game; - // If scraper provides only one match, always return that match - if (scraper->getType() == scraper->MatchType::MATCH_ONE || - config.scraper == "cache" || + // If scraper provides only one match, always return that match unless we're + // comparing years. + int releaseYear = UNDEF_YEAR; + if (scraper->getType() == scraper->MatchType::MATCH_ONE) { + GameEntry entry = gameEntries.first(); + // If year was specified, and doesn't match, return null game. + if (compareYear != -1) { // Year was specified in title - "(NNNN)" + releaseYear = getReleaseYear(entry.releaseDate); + if (releaseYear != -1) { // We got year from releaseDate + if (compareYear != releaseYear) { + return game; // Null game + } + } + } + lowestDistance = 0; + game = gameEntries.first(); + game.title = StrTools::xmlUnescape(game.title); + return game; + } + if (config.scraper == "cache" || (config.scraper == "openretro" && gameEntries.first().url.isEmpty())) { lowestDistance = 0; game = gameEntries.first(); @@ -559,6 +590,15 @@ GameEntry ScraperWorker::getBestEntry(const QList &gameEntries, continue; } } + // If year was specified, and doesn't match, skip. + if (compareYear != -1) { // Year was specified in title - "(NNNN)" + releaseYear = getReleaseYear(entry.releaseDate); + if (releaseYear != -1) { // We got year from releaseDate + if (compareYear != releaseYear) { + continue; + } + } + } if (config.scraper != "openretro") { // Remove all brackets from name, since we pretty much NEVER want // these @@ -728,17 +768,18 @@ GameEntry ScraperWorker::getEntryFromUser(const QList &gameEntries, bool suggestedShown = false; for (int a = 1; a <= gameEntries.length(); ++a) { QString suggested = ""; - if (gameEntries.at(a - 1).title == suggestedGame.title && - !suggestedShown) { + if (gameEntries.at(a - 1).id == suggestedGame.id && !suggestedShown) { suggested = " <-- Skyscraper's choice"; suggestedShown = true; } printf("\033[1;32m%d%s\033[0m: Title: '\033[1;32m%s\033[0m'%s\n " - "platform: '\033[1;33m%s\033[0m'\n", + "platform: '\033[1;33m%s\033[0m'\n " + "release date: '\033[1;33m%s\033[0m'\n", a, QString((a <= 9 ? " " : "")).toStdString().c_str(), gameEntries.at(a - 1).title.toStdString().c_str(), suggested.toStdString().c_str(), - gameEntries.at(a - 1).platform.toStdString().c_str()); + gameEntries.at(a - 1).platform.toStdString().c_str(), + gameEntries.at(a - 1).releaseDate.toStdString().c_str()); } printf("\033[1;32m-1\033[0m: \033[1;33mNONE OF THE ABOVE!\033[0m\n"); printf("\033[1;34mPlease choose the preferred entry\033[0m (Or press enter " @@ -819,6 +860,21 @@ void ScraperWorker::copyMedia(const QString &mediaType, } } } + +int ScraperWorker::getReleaseYear(const QString releaseDateString) { + // Most scrapers use "yyyy-MM-dd" format + QDate releaseDate = QDate::fromString(releaseDateString, Qt::ISODate); + if (releaseDate.isValid()) { + return releaseDate.year(); + } + // Some scrapers just give us the year + releaseDate = QDate::fromString(releaseDateString, "yyyy"); + if (releaseDate.isValid()) { + return releaseDate.year(); + } + return UNDEF_YEAR; +} + // --- Console colors --- // Black 0;30 Dark Gray 1;30 // Red 0;31 Light Red 1;31 diff --git a/src/scraperworker.h b/src/scraperworker.h index f8c5c0a6..168b2d6e 100644 --- a/src/scraperworker.h +++ b/src/scraperworker.h @@ -67,13 +67,15 @@ class ScraperWorker : public QObject { unsigned int editDistance(const std::string &s1, const std::string &s2); GameEntry getBestEntry(const QList &gameEntries, - QString compareTitle, int &lowestDistance); + QString compareTitle, int compareYear, + int &lowestDistance); GameEntry getEntryFromUser(const QList &gameEntries, const GameEntry &suggestedGame, const QString &compareTitle, int &lowestDistance); int getSearchMatch(const QString &title, const QString &compareTitle, const int &lowestDistance); + int getReleaseYear(const QString releaseDateString); bool limitReached(QString &output); void copyMedia(const QString &mediaType, const QString &completeBaseName, @@ -82,9 +84,9 @@ class ScraperWorker : public QObject { // TODO: Remove, replaced with AbstractScraper::MatchType /* QStringList const directMatchScrapers = {"cache", "import", "arcadedb", - "screenscraper", "esgamelist"}; - QStringList const searchBasedScrapers = {"thegamesdb", "mobygames", - "igdb", "worldofspectrum"}; + "screenscraper", "esgamelist"}; + QStringList const searchBasedScrapers = {"thegamesdb", "mobygames", "igdb", + "worldofspectrum"}; QStringList const variableScrapers = {"openretro"}; */ }; diff --git a/src/screenscraper.cpp b/src/screenscraper.cpp index 6d0ec6bb..9062cc5f 100644 --- a/src/screenscraper.cpp +++ b/src/screenscraper.cpp @@ -254,6 +254,7 @@ void ScreenScraper::getSearchResults(QList &gameEntries, game.url = gameUrl; game.platform = jsonObj["systeme"].toObject()["text"].toString(); + game.releaseDate = getJsonText(jsonObj["dates"].toArray(), REGION); // Only check if platform is empty, it's always correct when using // ScreenScraper diff --git a/src/thegamesdb.cpp b/src/thegamesdb.cpp index db5d7972..406a02f3 100644 --- a/src/thegamesdb.cpp +++ b/src/thegamesdb.cpp @@ -106,6 +106,9 @@ void TheGamesDb::getSearchResults(QList &gameEntries, // Remove anything at the end with a parentheses. 'thegamesdb' has a // habit of adding for instance '(1993)' to the name. game.title = game.title.left(game.title.indexOf("(")).simplified(); + if (jsonGame["release_date"] != QJsonValue::Undefined) { + game.releaseDate = jsonGame["release_date"].toString(); + } int gamePlafId = jsonGame["platform"].toInt(); game.platform = platformMap[QString::number(gamePlafId)].toString(); bool matchPlafId = gamePlafId == platformId;