diff --git a/es-app/src/guis/GuiScraperMenu.cpp b/es-app/src/guis/GuiScraperMenu.cpp index 0b1d3d069..347e13d17 100644 --- a/es-app/src/guis/GuiScraperMenu.cpp +++ b/es-app/src/guis/GuiScraperMenu.cpp @@ -893,6 +893,28 @@ void GuiScraperMenu::openOtherOptions() } }); + // Whether to fallback to additional regions. + auto scraperRegionFallback = std::make_shared(mWindow); + scraperRegionFallback->setState(Settings::getInstance()->getBool("ScraperRegionFallback")); + s->addWithLabel("ENABLE FALLBACK TO ADDITIONAL REGIONS", scraperRegionFallback); + s->addSaveFunc([scraperRegionFallback, s] { + if (scraperRegionFallback->getState() != + Settings::getInstance()->getBool("ScraperRegionFallback")) { + Settings::getInstance()->setBool("ScraperRegionFallback", + scraperRegionFallback->getState()); + s->setNeedsSaving(); + } + }); + + // Regions are not supported by TheGamesDB, so gray out the option if this scraper is selected. + if (Settings::getInstance()->getString("Scraper") == "thegamesdb") { + scraperRegionFallback->setEnabled(false); + scraperRegionFallback->setOpacity(DISABLED_OPACITY); + scraperRegionFallback->getParent() + ->getChild(scraperRegionFallback->getChildIndex() - 1) + ->setOpacity(DISABLED_OPACITY); + } + // Retry search on peer verification errors (TLS/certificate issues). auto retry_peer_verification = std::make_shared(); retry_peer_verification->setState( diff --git a/es-app/src/scrapers/ScreenScraper.cpp b/es-app/src/scrapers/ScreenScraper.cpp index 9508f99cb..3cb775b3f 100644 --- a/es-app/src/scrapers/ScreenScraper.cpp +++ b/es-app/src/scrapers/ScreenScraper.cpp @@ -610,14 +610,14 @@ void ScreenScraperRequest::processMedia(ScraperSearchResult& result, std::string& fileFormat, std::string region) { - pugi::xml_node art = pugi::xml_node(nullptr); + pugi::xml_node art {pugi::xml_node(nullptr)}; // Do an XPath query for media[type='$media_type'], then filter by region. // We need to do this because any child of 'medias' has the form // // and we need to find the right media for the region. - pugi::xpath_node_set results = media_list.select_nodes( - (static_cast("media[@type='") + mediaType + "']").c_str()); + pugi::xpath_node_set results {media_list.select_nodes( + (static_cast("media[@type='") + mediaType + "']").c_str())}; if (results.size()) { // Videos and fan art don't have any region attributes, so just take the first entry @@ -626,13 +626,23 @@ void ScreenScraperRequest::processMedia(ScraperSearchResult& result, art = results.first().node(); } else { - // Region fallback: WOR(LD), US, CUS(TOM?), JP, EU. - for (auto _region : std::vector {region, "wor", "us", "cus", "jp", "eu"}) { + std::string otherRegion; + if (Settings::getInstance()->getBool("ScraperRegionFallback")) { + // In case none of the regular fallback regions are found, try whatever is the + // first region in the returned results. This should capture games only released + // for specific countries and such as well as invalid database entries where the + // wrong region was defined. This fallback also includes the ss/ScreenScraper + // region which adds media for unofficial games (e.g. for OpenBOR and PICO-8). + otherRegion = results.first().node().attribute("region").as_string(); + } + // Region fallback: world, USA, Japan, EU and custom. + for (auto regionEntry : + std::vector {region, "wor", "us", "jp", "eu", "cus", otherRegion}) { if (art) break; for (auto node : results) { - if (node.node().attribute("region").value() == _region) { + if (node.node().attribute("region").value() == regionEntry) { art = node.node(); break; } diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index e0f5032bb..b647c2ad8 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -127,6 +127,7 @@ void Settings::setDefaults() mBoolMap["ScraperRespectExclusions"] = {true, true}; mBoolMap["ScraperExcludeRecursively"] = {true, true}; mBoolMap["ScraperConvertUnderscores"] = {true, true}; + mBoolMap["ScraperRegionFallback"] = {true, true}; mBoolMap["ScraperRetryPeerVerification"] = {false, false}; // UI settings.