| 
									
										
										
										
											2020-09-21 17:17:34 +00:00
										 |  |  | //  SPDX-License-Identifier: MIT
 | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-09-21 17:17:34 +00:00
										 |  |  | //  EmulationStation Desktop Edition
 | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | //  GamesDBJSONScraper.cpp
 | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | //  Functions specifically for scraping from thegamesdb.net
 | 
					
						
							|  |  |  | //  Called from Scraper.
 | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-18 16:58:43 +00:00
										 |  |  | #if defined(_MSC_VER) // MSVC compiler.
 | 
					
						
							|  |  |  | #define _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | #include "scrapers/GamesDBJSONScraper.h"
 | 
					
						
							|  |  |  | #include "scrapers/GamesDBJSONScraperResources.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "FileData.h"
 | 
					
						
							|  |  |  | #include "Log.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-21 17:17:34 +00:00
										 |  |  | #include "MameNames.h"
 | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | #include "PlatformId.h"
 | 
					
						
							|  |  |  | #include "Settings.h"
 | 
					
						
							|  |  |  | #include "SystemData.h"
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  | #include "utils/StringUtil.h"
 | 
					
						
							|  |  |  | #include "utils/TimeUtil.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-21 17:17:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-06 16:41:21 +00:00
										 |  |  | #include "rapidjson/document.h"
 | 
					
						
							|  |  |  | #include "rapidjson/error/en.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-21 17:17:34 +00:00
										 |  |  | #include <exception>
 | 
					
						
							|  |  |  | #include <map>
 | 
					
						
							| 
									
										
										
										
											2020-06-24 15:38:41 +00:00
										 |  |  | #include <pugixml.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | using namespace PlatformIds; | 
					
						
							|  |  |  | using namespace rapidjson; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-08 21:58:06 +00:00
										 |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     TheGamesDBJSONRequestResources resources; | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 11:09:55 +00:00
										 |  |  |     const std::map<PlatformId, std::string> gamesdb_new_platformid_map { | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {THREEDO, "25"}, | 
					
						
							|  |  |  |         {COMMODORE_AMIGA, "4911"}, | 
					
						
							|  |  |  |         {COMMODORE_AMIGA_CD32, "4947"}, | 
					
						
							|  |  |  |         {AMSTRAD_CPC, "4914"}, | 
					
						
							|  |  |  |         {APPLE_II, "4942"}, | 
					
						
							|  |  |  |         {ARCADE, "23"}, | 
					
						
							| 
									
										
										
										
											2022-05-23 16:50:23 +00:00
										 |  |  |         {ATOMISWAVE, "23"}, | 
					
						
							|  |  |  |         {SEGA_NAOMI, "23"}, | 
					
						
							| 
									
										
										
										
											2022-05-19 15:32:12 +00:00
										 |  |  |         {ARCADIA_2001, "4963"}, | 
					
						
							| 
									
										
										
										
											2022-05-12 20:45:52 +00:00
										 |  |  |         {BALLY_ASTROCADE, "4968"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {ATARI_800, "4943"}, | 
					
						
							|  |  |  |         {ATARI_2600, "22"}, | 
					
						
							|  |  |  |         {ATARI_5200, "26"}, | 
					
						
							|  |  |  |         {ATARI_7800, "27"}, | 
					
						
							|  |  |  |         {ATARI_JAGUAR, "28"}, | 
					
						
							|  |  |  |         {ATARI_JAGUAR_CD, "29"}, | 
					
						
							|  |  |  |         {ATARI_LYNX, "4924"}, | 
					
						
							|  |  |  |         {ATARI_ST, "4937"}, | 
					
						
							|  |  |  |         {ATARI_XE, "30"}, | 
					
						
							| 
									
										
										
										
											2023-02-24 21:02:53 +00:00
										 |  |  |         {BBC_MICRO, "5013"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {CAVESTORY, "1"}, | 
					
						
							|  |  |  |         {COLECOVISION, "31"}, | 
					
						
							|  |  |  |         {COMMODORE_64, "40"}, | 
					
						
							|  |  |  |         {COMMODORE_VIC20, "4945"}, | 
					
						
							| 
									
										
										
										
											2022-07-04 17:50:19 +00:00
										 |  |  |         {CREATRONIC_MEGA_DUCK, "4948"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {DAPHNE, "23"}, | 
					
						
							| 
									
										
										
										
											2022-07-06 18:10:28 +00:00
										 |  |  |         {FUJITSU_FM_TOWNS, "4932"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {INTELLIVISION, "32"}, | 
					
						
							|  |  |  |         {APPLE_MACINTOSH, "37"}, | 
					
						
							|  |  |  |         {GOOGLE_ANDROID, "4916"}, | 
					
						
							| 
									
										
										
										
											2023-02-03 19:16:29 +00:00
										 |  |  |         {LCD_GAMES, "4951"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {MICROSOFT_XBOX, "14"}, | 
					
						
							|  |  |  |         {MICROSOFT_XBOX_360, "15"}, | 
					
						
							|  |  |  |         {MOONLIGHT, "1"}, | 
					
						
							|  |  |  |         {MSX, "4929"}, | 
					
						
							|  |  |  |         {MSX2, "4929"}, | 
					
						
							|  |  |  |         {MSX_TURBO_R, "4929"}, | 
					
						
							|  |  |  |         {SNK_NEO_GEO, "24"}, | 
					
						
							| 
									
										
										
										
											2022-04-10 10:13:35 +00:00
										 |  |  |         {SNK_NEO_GEO_CD, "4956"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {SNK_NEO_GEO_POCKET, "4922"}, | 
					
						
							|  |  |  |         {SNK_NEO_GEO_POCKET_COLOR, "4923"}, | 
					
						
							|  |  |  |         {NINTENDO_3DS, "4912"}, | 
					
						
							|  |  |  |         {NINTENDO_64, "3"}, | 
					
						
							|  |  |  |         {NINTENDO_DS, "8"}, | 
					
						
							|  |  |  |         {NINTENDO_FAMICOM, "7"}, | 
					
						
							|  |  |  |         {NINTENDO_FAMICOM_DISK_SYSTEM, "4936"}, | 
					
						
							|  |  |  |         {NINTENDO_ENTERTAINMENT_SYSTEM, "7"}, | 
					
						
							|  |  |  |         {NINTENDO_GAME_BOY, "4"}, | 
					
						
							|  |  |  |         {NINTENDO_GAME_BOY_ADVANCE, "5"}, | 
					
						
							|  |  |  |         {NINTENDO_GAME_BOY_COLOR, "41"}, | 
					
						
							|  |  |  |         {NINTENDO_GAMECUBE, "2"}, | 
					
						
							|  |  |  |         {NINTENDO_WII, "9"}, | 
					
						
							|  |  |  |         {NINTENDO_WII_U, "38"}, | 
					
						
							|  |  |  |         {NINTENDO_VIRTUAL_BOY, "4918"}, | 
					
						
							|  |  |  |         {NINTENDO_GAME_AND_WATCH, "4950"}, | 
					
						
							|  |  |  |         {NINTENDO_POKEMON_MINI, "4957"}, | 
					
						
							|  |  |  |         {NINTENDO_SATELLAVIEW, "6"}, | 
					
						
							|  |  |  |         {NINTENDO_SWITCH, "4971"}, | 
					
						
							|  |  |  |         {BANDAI_SUFAMI_TURBO, "6"}, | 
					
						
							| 
									
										
										
										
											2022-07-13 17:00:30 +00:00
										 |  |  |         {DRAGON32, "4952"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {DOS, "1"}, | 
					
						
							| 
									
										
										
										
											2022-06-12 13:41:48 +00:00
										 |  |  |         {TANGERINE_ORIC, "4986"}, | 
					
						
							| 
									
										
										
										
											2022-01-03 17:22:41 +00:00
										 |  |  |         {GAMEENGINE_SCUMMVM, "1"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {PC, "1"}, | 
					
						
							| 
									
										
										
										
											2022-05-14 10:02:24 +00:00
										 |  |  |         {PC_WINDOWS, "1"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {VALVE_STEAM, "1"}, | 
					
						
							|  |  |  |         {NEC_PCFX, "4930"}, | 
					
						
							|  |  |  |         {PHILIPS_CDI, "4917"}, | 
					
						
							| 
									
										
										
										
											2022-04-10 10:37:04 +00:00
										 |  |  |         {SAMCOUPE, "4979"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {SEGA_32X, "33"}, | 
					
						
							|  |  |  |         {SEGA_CD, "21"}, | 
					
						
							|  |  |  |         {SEGA_DREAMCAST, "16"}, | 
					
						
							|  |  |  |         {SEGA_GAME_GEAR, "20"}, | 
					
						
							|  |  |  |         {SEGA_GENESIS, "18"}, | 
					
						
							|  |  |  |         {SEGA_MASTER_SYSTEM, "35"}, | 
					
						
							|  |  |  |         {SEGA_MEGA_DRIVE, "36"}, | 
					
						
							|  |  |  |         {SEGA_SATURN, "17"}, | 
					
						
							|  |  |  |         {SEGA_SG1000, "4949"}, | 
					
						
							|  |  |  |         {SONY_PLAYSTATION, "10"}, | 
					
						
							|  |  |  |         {SONY_PLAYSTATION_2, "11"}, | 
					
						
							|  |  |  |         {SONY_PLAYSTATION_3, "12"}, | 
					
						
							|  |  |  |         {SONY_PLAYSTATION_4, "4919"}, | 
					
						
							|  |  |  |         {SONY_PLAYSTATION_VITA, "39"}, | 
					
						
							|  |  |  |         {SONY_PLAYSTATION_PORTABLE, "13"}, | 
					
						
							|  |  |  |         {SUPER_NINTENDO, "6"}, | 
					
						
							|  |  |  |         {SHARP_X1, "4977"}, | 
					
						
							|  |  |  |         {SHARP_X68000, "4931"}, | 
					
						
							|  |  |  |         {NEC_SUPERGRAFX, "34"}, | 
					
						
							|  |  |  |         {NEC_PC_8800, "4933"}, | 
					
						
							|  |  |  |         {NEC_PC_9800, "4934"}, | 
					
						
							|  |  |  |         {NEC_PC_ENGINE, "34"}, | 
					
						
							|  |  |  |         {NEC_PC_ENGINE_CD, "4955"}, | 
					
						
							|  |  |  |         {BANDAI_WONDERSWAN, "4925"}, | 
					
						
							|  |  |  |         {BANDAI_WONDERSWAN_COLOR, "4926"}, | 
					
						
							|  |  |  |         {SINCLAIR_ZX_SPECTRUM, "4913"}, | 
					
						
							| 
									
										
										
										
											2022-04-10 10:37:04 +00:00
										 |  |  |         {SINCLAIR_ZX81_SINCLAR, "5010"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {VIDEOPAC_ODYSSEY2, "4927"}, | 
					
						
							|  |  |  |         {VECTREX, "4939"}, | 
					
						
							| 
									
										
										
										
											2023-02-01 21:30:43 +00:00
										 |  |  |         {VTECH_VSMILE, "4988"}, | 
					
						
							| 
									
										
										
										
											2022-07-04 17:50:19 +00:00
										 |  |  |         {WATARA_SUPERVISION, "4959"}, | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  |         {TANDY_COLOR_COMPUTER, "4941"}, | 
					
						
							| 
									
										
										
										
											2022-06-12 13:41:48 +00:00
										 |  |  |         {TANDY_TRS80, "4941"}, | 
					
						
							|  |  |  |         {TEXAS_INSTRUMENTS_TI99, "4953"}}; | 
					
						
							| 
									
										
										
										
											2021-11-13 13:27:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | } // namespace
 | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  | void thegamesdb_generate_json_scraper_requests( | 
					
						
							|  |  |  |     const ScraperSearchParams& params, | 
					
						
							|  |  |  |     std::queue<std::unique_ptr<ScraperRequest>>& requests, | 
					
						
							|  |  |  |     std::vector<ScraperSearchResult>& results) | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     resources.prepare(); | 
					
						
							| 
									
										
										
										
											2022-01-16 17:18:28 +00:00
										 |  |  |     std::string path {"https://api.thegamesdb.net/v1"}; | 
					
						
							|  |  |  |     bool usingGameID {false}; | 
					
						
							|  |  |  |     const std::string apiKey {std::string("apikey=") + resources.getApiKey()}; | 
					
						
							|  |  |  |     std::string cleanName {params.nameOverride}; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     if (!cleanName.empty() && cleanName.substr(0, 3) == "id:") { | 
					
						
							| 
									
										
										
										
											2022-01-16 17:18:28 +00:00
										 |  |  |         std::string gameID {cleanName.substr(3)}; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         path += "/Games/ByGameID?" + apiKey + | 
					
						
							|  |  |  |                 "&fields=players,publishers,genres,overview,last_updated,rating," | 
					
						
							|  |  |  |                 "platform,coop,youtube,os,processor,ram,hdd,video,sound,alternates&id=" + | 
					
						
							|  |  |  |                 HttpReq::urlEncode(gameID); | 
					
						
							|  |  |  |         usingGameID = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2020-06-25 17:52:38 +00:00
										 |  |  |         if (cleanName.empty()) { | 
					
						
							| 
									
										
										
										
											2020-10-10 11:05:12 +00:00
										 |  |  |             // If the setting to search based on the metadata name has been set, then search
 | 
					
						
							|  |  |  |             // using this regardless of whether the entry is an arcade game.
 | 
					
						
							|  |  |  |             if (Settings::getInstance()->getBool("ScraperSearchMetadataName")) { | 
					
						
							| 
									
										
										
										
											2020-11-14 14:30:49 +00:00
										 |  |  |                 cleanName = Utils::String::removeParenthesis(params.game->metadata.get("name")); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-25 17:52:38 +00:00
										 |  |  |             else { | 
					
						
							| 
									
										
										
										
											2020-10-10 11:05:12 +00:00
										 |  |  |                 // If not searching based on the metadata name, then check whether it's an
 | 
					
						
							|  |  |  |                 // arcade game and if so expand to the full game name. This is required as
 | 
					
						
							|  |  |  |                 // TheGamesDB has issues with searching using the short MAME names.
 | 
					
						
							| 
									
										
										
										
											2021-12-17 19:18:47 +00:00
										 |  |  |                 if (params.game->isArcadeGame()) { | 
					
						
							| 
									
										
										
										
											2021-11-17 20:32:40 +00:00
										 |  |  |                     cleanName = MameNames::getInstance().getCleanName(params.game->getCleanName()); | 
					
						
							| 
									
										
										
										
											2021-12-17 19:18:47 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 else { | 
					
						
							|  |  |  |                     if (params.game->getType() == GAME && | 
					
						
							|  |  |  |                         Utils::FileSystem::isDirectory(params.game->getFullPath())) { | 
					
						
							|  |  |  |                         // For the special case where a directory has a supported file extension
 | 
					
						
							|  |  |  |                         // and is therefore interpreted as a file, exclude the extension from the
 | 
					
						
							|  |  |  |                         // search.
 | 
					
						
							|  |  |  |                         cleanName = Utils::FileSystem::getStem(params.game->getCleanName()); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     else { | 
					
						
							|  |  |  |                         cleanName = params.game->getCleanName(); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-06-25 17:52:38 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-21 20:10:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Trim leading and trailing whitespaces.
 | 
					
						
							| 
									
										
										
										
											2021-09-25 16:01:41 +00:00
										 |  |  |         cleanName = Utils::String::trim(cleanName); | 
					
						
							| 
									
										
										
										
											2021-09-21 20:10:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-09 13:14:48 +00:00
										 |  |  |         if (Settings::getInstance()->getBool("ScraperConvertUnderscores")) | 
					
						
							|  |  |  |             cleanName = Utils::String::replace(cleanName, "_", " "); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-25 18:37:41 +00:00
										 |  |  |         path += "/Games/ByGameName?" + apiKey + | 
					
						
							|  |  |  |                 "&fields=players,publishers,genres,overview,last_updated,rating," | 
					
						
							|  |  |  |                 "platform,coop,youtube,os,processor,ram,hdd,video,sound,alternates&name=" + | 
					
						
							|  |  |  |                 HttpReq::urlEncode(cleanName); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (usingGameID) { | 
					
						
							| 
									
										
										
										
											2022-01-15 12:38:09 +00:00
										 |  |  |         // If we have the ID already, we don't need the GetGamelist request.
 | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         requests.push(std::unique_ptr<ScraperRequest>(new TheGamesDBJSONRequest(results, path))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         std::string platformQueryParam; | 
					
						
							|  |  |  |         auto& platforms = params.system->getPlatformIds(); | 
					
						
							|  |  |  |         if (!platforms.empty()) { | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |             bool first {true}; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |             platformQueryParam += "&filter%5Bplatform%5D="; | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             for (auto platformIt = platforms.cbegin(); // Line break.
 | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |                  platformIt != platforms.cend(); ++platformIt) { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |                 auto mapIt = gamesdb_new_platformid_map.find(*platformIt); | 
					
						
							|  |  |  |                 if (mapIt != gamesdb_new_platformid_map.cend()) { | 
					
						
							|  |  |  |                     if (!first) | 
					
						
							|  |  |  |                         platformQueryParam += ","; | 
					
						
							|  |  |  |                     platformQueryParam += HttpReq::urlEncode(mapIt->second); | 
					
						
							|  |  |  |                     first = false; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else { | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |                     LOG(LogWarning) | 
					
						
							|  |  |  |                         << "TheGamesDB scraper: No support for platform \"" | 
					
						
							|  |  |  |                         << getPlatformName(*platformIt) << "\", search will be inaccurate"; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             path += platformQueryParam; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-02-08 19:56:11 +00:00
										 |  |  |         else { | 
					
						
							|  |  |  |             LOG(LogWarning) << "TheGamesDB scraper: No platform defined, search will be inaccurate"; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         requests.push( | 
					
						
							|  |  |  |             std::unique_ptr<ScraperRequest>(new TheGamesDBJSONRequest(requests, results, path))); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | void thegamesdb_generate_json_scraper_requests( | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     const std::string& gameIDs, | 
					
						
							|  |  |  |     std::queue<std::unique_ptr<ScraperRequest>>& requests, | 
					
						
							|  |  |  |     std::vector<ScraperSearchResult>& results) | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     resources.prepare(); | 
					
						
							|  |  |  |     std::string path = "https://api.thegamesdb.net/v1"; | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |     const std::string apiKey {std::string("apikey=") + resources.getApiKey()}; | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     path += "/Games/Images/GamesImages?" + apiKey + "&games_id=" + gameIDs; | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     requests.push( | 
					
						
							|  |  |  |         std::unique_ptr<ScraperRequest>(new TheGamesDBJSONRequest(requests, results, path))); | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     std::string getStringOrThrow(const Value& v, const std::string& key) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!v.HasMember(key.c_str()) || !v[key.c_str()].IsString()) { | 
					
						
							|  |  |  |             throw std::runtime_error( | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |                 "rapidjson internal assertion failure: missing or non string key:" + key); | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         return v[key.c_str()].GetString(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     int getIntOrThrow(const Value& v, const std::string& key) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!v.HasMember(key.c_str()) || !v[key.c_str()].IsInt()) { | 
					
						
							|  |  |  |             throw std::runtime_error( | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |                 "rapidjson internal assertion failure: missing or non int key:" + key); | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         return v[key.c_str()].GetInt(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     int getIntOrThrow(const Value& v) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!v.IsInt()) { | 
					
						
							|  |  |  |             throw std::runtime_error("rapidjson internal assertion failure: not an int"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return v.GetInt(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     std::string getDeveloperString(const Value& v) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!v.IsArray()) | 
					
						
							|  |  |  |             return ""; | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         std::string out = ""; | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |         bool first {true}; | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |         for (int i = 0; i < static_cast<int>(v.Size()); ++i) { | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             auto mapIt = resources.gamesdb_new_developers_map.find(getIntOrThrow(v[i])); | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             if (mapIt == resources.gamesdb_new_developers_map.cend()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             if (!first) | 
					
						
							|  |  |  |                 out += ", "; | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             out += mapIt->second; | 
					
						
							|  |  |  |             first = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return out; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     std::string getPublisherString(const Value& v) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!v.IsArray()) | 
					
						
							|  |  |  |             return ""; | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |         std::string out; | 
					
						
							|  |  |  |         bool first {true}; | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |         for (int i = 0; i < static_cast<int>(v.Size()); ++i) { | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             auto mapIt = resources.gamesdb_new_publishers_map.find(getIntOrThrow(v[i])); | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             if (mapIt == resources.gamesdb_new_publishers_map.cend()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             if (!first) | 
					
						
							|  |  |  |                 out += ", "; | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             out += mapIt->second; | 
					
						
							|  |  |  |             first = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return out; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     std::string getGenreString(const Value& v) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!v.IsArray()) | 
					
						
							|  |  |  |             return ""; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |         std::string out; | 
					
						
							|  |  |  |         bool first {true}; | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |         for (int i = 0; i < static_cast<int>(v.Size()); ++i) { | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             auto mapIt = resources.gamesdb_new_genres_map.find(getIntOrThrow(v[i])); | 
					
						
							| 
									
										
										
										
											2020-11-08 21:58:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             if (mapIt == resources.gamesdb_new_genres_map.cend()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             if (!first) | 
					
						
							|  |  |  |                 out += ", "; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |             out += mapIt->second; | 
					
						
							|  |  |  |             first = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return out; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |     void processGame(const Value& game, std::vector<ScraperSearchResult>& results) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         ScraperSearchResult result; | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 17:37:43 +00:00
										 |  |  |         // Platform IDs.
 | 
					
						
							|  |  |  |         if (game.HasMember("platform") && game["platform"].IsInt()) { | 
					
						
							|  |  |  |             for (auto& platform : gamesdb_new_platformid_map) { | 
					
						
							|  |  |  |                 if (platform.second == std::to_string(game["platform"].GetInt())) | 
					
						
							|  |  |  |                     result.platformIDs.push_back(platform.first); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (result.platformIDs.empty()) | 
					
						
							|  |  |  |             result.platformIDs.push_back(PlatformId::PLATFORM_UNKNOWN); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         if (game.HasMember("id") && game["id"].IsInt()) | 
					
						
							|  |  |  |             result.gameID = std::to_string(getIntOrThrow(game, "id")); | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         result.mdl.set("name", getStringOrThrow(game, "game_title")); | 
					
						
							|  |  |  |         LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Name: " << result.mdl.get("name"); | 
					
						
							| 
									
										
										
										
											2020-07-08 15:01:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         if (game.HasMember("overview") && game["overview"].IsString()) | 
					
						
							|  |  |  |             result.mdl.set("desc", Utils::String::replace(game["overview"].GetString(), "\r", "")); | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         if (game.HasMember("release_date") && game["release_date"].IsString()) { | 
					
						
							|  |  |  |             result.mdl.set("releasedate", Utils::Time::DateTime(Utils::Time::stringToTime( | 
					
						
							|  |  |  |                                               game["release_date"].GetString(), "%Y-%m-%d"))); | 
					
						
							|  |  |  |             LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (unparsed): " | 
					
						
							|  |  |  |                           << game["release_date"].GetString(); | 
					
						
							|  |  |  |             LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (parsed): " | 
					
						
							|  |  |  |                           << result.mdl.get("releasedate"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-02 12:19:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         if (game.HasMember("developers") && game["developers"].IsArray()) { | 
					
						
							|  |  |  |             result.mdl.set("developer", getDeveloperString(game["developers"])); | 
					
						
							|  |  |  |             LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Developer: " | 
					
						
							|  |  |  |                           << result.mdl.get("developer"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-02 12:19:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         if (game.HasMember("publishers") && game["publishers"].IsArray()) { | 
					
						
							|  |  |  |             result.mdl.set("publisher", getPublisherString(game["publishers"])); | 
					
						
							|  |  |  |             LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Publisher: " | 
					
						
							|  |  |  |                           << result.mdl.get("publisher"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-02 12:19:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         if (game.HasMember("genres") && game["genres"].IsArray()) { | 
					
						
							|  |  |  |             result.mdl.set("genre", getGenreString(game["genres"])); | 
					
						
							|  |  |  |             LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Genre: " | 
					
						
							|  |  |  |                           << result.mdl.get("genre"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-02 12:19:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         if (game.HasMember("players") && game["players"].IsInt()) { | 
					
						
							|  |  |  |             result.mdl.set("players", std::to_string(game["players"].GetInt())); | 
					
						
							|  |  |  |             LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Players: " | 
					
						
							|  |  |  |                           << result.mdl.get("players"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-08 15:01:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         result.mediaURLFetch = NOT_STARTED; | 
					
						
							|  |  |  |         results.push_back(result); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | } // namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  | void processMediaURLs(const Value& images, | 
					
						
							|  |  |  |                       const std::string& base_url, | 
					
						
							|  |  |  |                       std::vector<ScraperSearchResult>& results) | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     ScraperSearchResult result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Step through each game ID in the JSON server response.
 | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |     for (auto it = images.MemberBegin(); it != images.MemberEnd(); ++it) { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         result.gameID = it->name.GetString(); | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |         const Value& gameMedia {images[it->name]}; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         result.coverUrl = ""; | 
					
						
							| 
									
										
										
										
											2022-01-15 12:16:23 +00:00
										 |  |  |         result.fanartUrl = ""; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         result.marqueeUrl = ""; | 
					
						
							|  |  |  |         result.screenshotUrl = ""; | 
					
						
							| 
									
										
										
										
											2021-10-28 19:00:23 +00:00
										 |  |  |         result.titlescreenUrl = ""; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         // Quite excessive testing for valid values, but you never know what the server has
 | 
					
						
							|  |  |  |         // returned and we don't want to crash the program due to malformed data.
 | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         if (gameMedia.IsArray()) { | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |             for (SizeType i = 0; i < gameMedia.Size(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |                 std::string mediatype; | 
					
						
							|  |  |  |                 std::string mediaside; | 
					
						
							|  |  |  |                 if (gameMedia[i]["type"].IsString()) | 
					
						
							|  |  |  |                     mediatype = gameMedia[i]["type"].GetString(); | 
					
						
							|  |  |  |                 if (gameMedia[i]["side"].IsString()) | 
					
						
							|  |  |  |                     mediaside = gameMedia[i]["side"].GetString(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (mediatype == "boxart" && mediaside == "front") | 
					
						
							|  |  |  |                     if (gameMedia[i]["filename"].IsString()) | 
					
						
							|  |  |  |                         result.coverUrl = base_url + gameMedia[i]["filename"].GetString(); | 
					
						
							| 
									
										
										
										
											2022-01-15 12:16:23 +00:00
										 |  |  |                 if (mediatype == "boxart" && mediaside == "back") | 
					
						
							|  |  |  |                     if (gameMedia[i]["filename"].IsString()) | 
					
						
							|  |  |  |                         result.backcoverUrl = base_url + gameMedia[i]["filename"].GetString(); | 
					
						
							|  |  |  |                 // Only process the first fanart result.
 | 
					
						
							|  |  |  |                 if (mediatype == "fanart" && result.fanartUrl == "") | 
					
						
							|  |  |  |                     if (gameMedia[i]["filename"].IsString()) | 
					
						
							|  |  |  |                         result.fanartUrl = base_url + gameMedia[i]["filename"].GetString(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |                 if (mediatype == "clearlogo") | 
					
						
							|  |  |  |                     if (gameMedia[i]["filename"].IsString()) | 
					
						
							|  |  |  |                         result.marqueeUrl = base_url + gameMedia[i]["filename"].GetString(); | 
					
						
							|  |  |  |                 if (mediatype == "screenshot") | 
					
						
							|  |  |  |                     if (gameMedia[i]["filename"].IsString()) | 
					
						
							|  |  |  |                         result.screenshotUrl = base_url + gameMedia[i]["filename"].GetString(); | 
					
						
							| 
									
										
										
										
											2021-10-28 19:00:23 +00:00
										 |  |  |                 if (mediatype == "titlescreen") | 
					
						
							|  |  |  |                     if (gameMedia[i]["filename"].IsString()) | 
					
						
							|  |  |  |                         result.titlescreenUrl = base_url + gameMedia[i]["filename"].GetString(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         result.mediaURLFetch = COMPLETED; | 
					
						
							|  |  |  |         results.push_back(result); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-06 11:10:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-26 16:34:33 +00:00
										 |  |  | void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req, | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |                                     std::vector<ScraperSearchResult>& results) | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     assert(req->status() == HttpReq::REQ_SUCCESS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Document doc; | 
					
						
							|  |  |  |     doc.Parse(req->getContent().c_str()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (doc.HasParseError()) { | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |         std::string err {std::string("TheGamesDBJSONRequest - Error parsing JSON \n\t") + | 
					
						
							|  |  |  |                          GetParseError_En(doc.GetParseError())}; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         setError(err); | 
					
						
							|  |  |  |         LOG(LogError) << err; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If the response contains the 'images' object, then it's a game media URL request.
 | 
					
						
							|  |  |  |     if (doc.HasMember("data") && doc["data"].HasMember("images") && | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         doc["data"]["images"].IsObject()) { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |         const Value& images {doc["data"]["images"]}; | 
					
						
							|  |  |  |         const Value& base_url {doc["data"]["base_url"]}; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         std::string baseImageUrlLarge; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (base_url.HasMember("large") && base_url["large"].IsString()) { | 
					
						
							|  |  |  |             baseImageUrlLarge = base_url["large"].GetString(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							| 
									
										
										
										
											2021-01-26 16:28:54 +00:00
										 |  |  |             LOG(LogWarning) << "TheGamesDBJSONRequest - No URL path for large images\n"; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             processMediaURLs(images, baseImageUrlLarge, results); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         catch (std::runtime_error& e) { | 
					
						
							| 
									
										
										
										
											2020-07-26 21:30:45 +00:00
										 |  |  |             LOG(LogError) << "Error while processing media URLs: " << e.what(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Find how many more requests we can make before the scraper
 | 
					
						
							|  |  |  |         // request allowance counter is reset.
 | 
					
						
							|  |  |  |         if (doc.HasMember("remaining_monthly_allowance") && doc.HasMember("extra_allowance")) { | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |             for (size_t i = 0; i < results.size(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |                 results[i].scraperRequestAllowance = | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |                     doc["remaining_monthly_allowance"].GetInt() + doc["extra_allowance"].GetInt(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-08-06 10:52:06 +00:00
										 |  |  |             LOG(LogDebug) << "TheGamesDBJSONRequest::process(): " | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |                              "Remaining monthly scraping allowance: " | 
					
						
							|  |  |  |                           << results.back().scraperRequestAllowance; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // These process steps are for the initial scraping response.
 | 
					
						
							|  |  |  |     if (!doc.HasMember("data") || !doc["data"].HasMember("games") || | 
					
						
							| 
									
										
										
										
											2021-07-07 18:03:42 +00:00
										 |  |  |         !doc["data"]["games"].IsArray()) { | 
					
						
							| 
									
										
										
										
											2021-01-26 16:28:54 +00:00
										 |  |  |         LOG(LogWarning) << "TheGamesDBJSONRequest - Response had no game data\n"; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 17:59:27 +00:00
										 |  |  |     const Value& games {doc["data"]["games"]}; | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |     resources.ensureResources(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 16:35:34 +00:00
										 |  |  |     for (int i = 0; i < static_cast<int>(games.Size()); ++i) { | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         auto& v = games[i]; | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             processGame(v, results); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         catch (std::runtime_error& e) { | 
					
						
							| 
									
										
										
										
											2020-07-26 21:30:45 +00:00
										 |  |  |             LOG(LogError) << "Error while processing game: " << e.what(); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:25:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-14 14:30:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (results.size() == 0) { | 
					
						
							| 
									
										
										
										
											2021-01-26 16:28:54 +00:00
										 |  |  |         LOG(LogDebug) << "TheGamesDBJSONRequest::process(): No games found"; | 
					
						
							| 
									
										
										
										
											2020-11-14 14:30:49 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-08 02:08:11 +00:00
										 |  |  | } |