// SPDX-License-Identifier: MIT // // ES-DE Frontend // GuiScraperSearch.h // // User interface for the scraper where the user is able to see an overview // of the game being scraped and an option to override the game search string. // Used by both single-game scraping from the GuiMetaDataEd menu as well as // to resolve scraping conflicts when run from GuiScraperMenu. // The function to properly save scraped metadata is located here too. // // This GUI is called from GuiScraperSingle for single-game scraping and // from GuiScraperMulti for multi-game scraping. // #ifndef ES_APP_GUIS_GUI_SCRAPER_SEARCH_H #define ES_APP_GUIS_GUI_SCRAPER_SEARCH_H #include "GuiComponent.h" #include "MiximageGenerator.h" #include "components/BusyComponent.h" #include "components/ComponentGrid.h" #include "scrapers/Scraper.h" #include "views/ViewController.h" #include <future> #include <thread> class ComponentList; class DateTimeEditComponent; class ImageComponent; class RatingComponent; class ScrollableContainer; class TextComponent; class GuiScraperSearch : public GuiComponent { public: enum SearchType { AUTOMATIC_MODE, SEMIAUTOMATIC_MODE, MANUAL_MODE }; GuiScraperSearch(SearchType searchType, unsigned int scrapeCount, int rowCount); ~GuiScraperSearch(); void search(ScraperSearchParams& params); void openInputScreen(ScraperSearchParams& from); void stop(); int getScraperResultsSize() { return static_cast<int>(mScraperResults.size()); } bool getAcceptedResult() { return mAcceptedResult; } SearchType getSearchType() const { return mSearchType; } bool getSavedNewMedia() { if (mMDResolveHandle != nullptr) return mMDResolveHandle->getSavedNewMedia(); return mScrapeResult.savedNewMedia; } static bool saveMetadata(const ScraperSearchResult& result, MetaDataList& metadata, FileData* scrapedGame); // Metadata assets will be resolved before calling the accept callback. void setAcceptCallback(const std::function<void(const ScraperSearchResult&)>& acceptCallback) { mAcceptCallback = acceptCallback; } void setSkipCallback(const std::function<void()>& skipCallback) { mSkipCallback = skipCallback; } void setCancelCallback(const std::function<void()>& cancelCallback) { mCancelCallback = cancelCallback; } void setRefineCallback(const std::function<void()>& refineCallback) { mRefineCallback = refineCallback; } bool input(InputConfig* config, Input input) override; void update(int deltaTime) override; void render(const glm::mat4& parentTrans) override; std::vector<HelpPrompt> getHelpPrompts() override; HelpStyle getHelpStyle() override { return ViewController::getInstance()->getViewHelpStyle(); } void onSizeChanged() override; void decreaseScrapeCount() { if (mScrapeCount > 0) --mScrapeCount; } void unsetRefinedSearch() { mRefinedSearch = false; } bool getRefinedSearch() { return mRefinedSearch; } bool getFoundGame() { return mFoundGame; } const std::string& getNameOverride() { return mLastSearch.nameOverride; } void onFocusGained() override { mGrid.onFocusGained(); } void onFocusLost() override { mGrid.onFocusLost(); } std::shared_ptr<ComponentList> getResultList() { return mResultList; } private: void updateView(); void updateThumbnail(); void updateInfoPane(); void resizeMetadata(); void onSearchError(const std::string& error, const bool retry, const bool fatalError, HttpReq::Status status = HttpReq::REQ_UNDEFINED_ERROR); void onSearchDone(std::vector<ScraperSearchResult>& results); int getSelectedIndex(); void calculateMD5Hash(std::string path) { mMD5Hash = Utils::Math::md5Hash(path, true); mMD5HashPromise.set_value(true); } // For TheGamesDB, retrieve URLs for the additional metadata assets // that need to be downloaded. void retrieveMediaURLs(ScraperSearchResult result); // Resolve any metadata assets that need to be downloaded and return. void returnResult(ScraperSearchResult result); Renderer* mRenderer; ComponentGrid mGrid; std::shared_ptr<TextComponent> mResultName; std::shared_ptr<ScrollableContainer> mDescContainer; std::shared_ptr<TextComponent> mResultDesc; std::shared_ptr<ImageComponent> mResultThumbnail; std::shared_ptr<ComponentList> mResultList; std::shared_ptr<ComponentGrid> mMD_Grid; std::shared_ptr<RatingComponent> mMD_Rating; std::shared_ptr<DateTimeEditComponent> mMD_ReleaseDate; std::shared_ptr<TextComponent> mMD_Developer; std::shared_ptr<TextComponent> mMD_Publisher; std::shared_ptr<TextComponent> mMD_Genre; std::shared_ptr<TextComponent> mMD_Players; std::shared_ptr<TextComponent> mMD_Filler; // Label-component pair. struct MetaDataPair { std::shared_ptr<TextComponent> first; std::shared_ptr<GuiComponent> second; bool resize; MetaDataPair(const std::shared_ptr<TextComponent>& f, const std::shared_ptr<GuiComponent>& s, bool r = true) : first(f) , second(s) , resize(r) { } }; std::vector<MetaDataPair> mMD_Pairs; SearchType mSearchType; ScraperSearchParams mLastSearch; ScraperSearchResult mScrapeResult; std::function<void(const ScraperSearchResult&)> mAcceptCallback; std::function<void()> mSkipCallback; std::function<void()> mCancelCallback; std::function<void()> mRefineCallback; int mRowCount; unsigned int mScrapeCount; bool mNextSearch; bool mHashSearch; bool mRefinedSearch; bool mBlockAccept; bool mAcceptedResult; bool mFoundGame; bool mScrapeRatings; bool mRetrySearch; int mRetryCount; int mRetryTimer; int mRetryAccumulator; int mAutomaticModeGameEntry; std::unique_ptr<ScraperSearchHandle> mSearchHandle; std::unique_ptr<ScraperSearchHandle> mMDRetrieveURLsHandle; std::unique_ptr<MDResolveHandle> mMDResolveHandle; std::vector<ScraperSearchResult> mScraperResults; std::map<std::string, std::unique_ptr<HttpReq>> mThumbnailReqMap; std::string mMD5Hash; std::thread mCalculateMD5HashThread; std::promise<bool> mMD5HashPromise; std::future<bool> mMD5HashFuture; std::unique_ptr<MiximageGenerator> mMiximageGenerator; std::thread mMiximageGeneratorThread; std::promise<bool> mGeneratorPromise; std::future<bool> mGeneratorFuture; bool mMiximageResult; std::string mResultMessage; BusyComponent mBusyAnim; }; #endif // ES_APP_GUIS_GUI_SCRAPER_SEARCH_H