From 4fb12a48015a05df2c820da38cf8fd76092c5241 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sat, 14 Nov 2020 20:46:08 +0100 Subject: [PATCH] Fixed an issue where the wrong thumbnail could be displayed in the scraper. --- es-app/src/guis/GuiScraperSearch.cpp | 64 ++++++++++++++++------------ es-app/src/guis/GuiScraperSearch.h | 2 +- es-app/src/scrapers/Scraper.cpp | 6 +-- es-app/src/scrapers/Scraper.h | 4 +- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/es-app/src/guis/GuiScraperSearch.cpp b/es-app/src/guis/GuiScraperSearch.cpp index 9569cf32a..06cc0d984 100644 --- a/es-app/src/guis/GuiScraperSearch.cpp +++ b/es-app/src/guis/GuiScraperSearch.cpp @@ -140,8 +140,8 @@ GuiScraperSearch::~GuiScraperSearch() if (mMDResolveHandle) mMDResolveHandle.reset(); - if (mThumbnailReq) - mThumbnailReq.reset(); + if (mThumbnailReqMap.size() > 0) + mThumbnailReqMap.clear(); HttpReq::cleanupCurlMulti(); } @@ -287,7 +287,7 @@ void GuiScraperSearch::search(const ScraperSearchParams& params) mResultList->clear(); mScraperResults.clear(); mMDRetrieveURLsHandle.reset(); - mThumbnailReq.reset(); + mThumbnailReqMap.clear(); mMDResolveHandle.reset(); updateInfoPane(); @@ -297,7 +297,7 @@ void GuiScraperSearch::search(const ScraperSearchParams& params) void GuiScraperSearch::stop() { - mThumbnailReq.reset(); + mThumbnailReqMap.clear(); mSearchHandle.reset(); mMDResolveHandle.reset(); mMDRetrieveURLsHandle.reset(); @@ -353,14 +353,14 @@ void GuiScraperSearch::onSearchDone(const std::vector& resu // If there is no thumbnail to download and we're in semi-automatic mode, proceed to return // the results or we'll get stuck forever waiting for a thumbnail to be downloaded. if (mSearchType == ACCEPT_SINGLE_MATCHES && results.size() == 1 && - mScraperResults.front().ThumbnailImageUrl == "") + mScraperResults.front().thumbnailImageUrl == "") returnResult(mScraperResults.front()); // For automatic mode, if there's no thumbnail to download or no matching games found, // proceed directly or we'll get stuck forever. if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) { if (mScraperResults.size() == 0 || (mScraperResults.size() > 0 && - mScraperResults.front().ThumbnailImageUrl == "")) { + mScraperResults.front().thumbnailImageUrl == "")) { if (mScraperResults.size() == 0) mSkipCallback(); else @@ -423,12 +423,12 @@ void GuiScraperSearch::updateInfoPane() mResultThumbnail->setImage(""); const std::string& thumb = res.screenshotUrl.empty() ? res.coverUrl : res.screenshotUrl; - mScraperResults[i].ThumbnailImageUrl = thumb; + mScraperResults[i].thumbnailImageUrl = thumb; // Cache the thumbnail image in mScraperResults so that we don't need to download // it every time the list is scrolled back and forth. - if (mScraperResults[i].ThumbnailImageData.size() > 0) { - std::string content = mScraperResults[i].ThumbnailImageData; + if (mScraperResults[i].thumbnailImageData.size() > 0) { + std::string content = mScraperResults[i].thumbnailImageData; mResultThumbnail->setImage(content.data(), content.length()); mGrid.onSizeChanged(); // A hack to fix the thumbnail position since its size changed. } @@ -437,14 +437,16 @@ void GuiScraperSearch::updateInfoPane() else { if (!thumb.empty()) { // Make sure we don't attempt to download the same thumbnail twice. - if (!mThumbnailReq && mScraperResults[i].thumbnailDownloadStatus != IN_PROGRESS) { + if (mScraperResults[i].thumbnailDownloadStatus != IN_PROGRESS) { mScraperResults[i].thumbnailDownloadStatus = IN_PROGRESS; - mThumbnailReq = std::unique_ptr(new HttpReq(thumb)); + // Add an entry into the thumbnail map, this way we can track and download + // each thumbnail separately even as they're downloading while scrolling + // through the result list. + mThumbnailReqMap.insert(std::pair>(mScraperResults[i].thumbnailImageUrl, + std::unique_ptr(new HttpReq(thumb)))); } } - else { - mThumbnailReq.reset(); - } } // Metadata. @@ -528,8 +530,13 @@ void GuiScraperSearch::update(int deltaTime) if (mBlockAccept) mBusyAnim.update(deltaTime); - if (mThumbnailReq && mThumbnailReq->status() != HttpReq::REQ_IN_PROGRESS) - updateThumbnail(); + // Check if the thumbnail for the currently selected game has finished downloading. + if (mScraperResults.size() > 0) { + auto it = mThumbnailReqMap.find(mScraperResults[mResultList-> + getCursorId()].thumbnailImageUrl); + if (it != mThumbnailReqMap.end() && it->second->status() != HttpReq::REQ_IN_PROGRESS) + updateThumbnail(); + } if (mSearchHandle && mSearchHandle->status() != ASYNC_IN_PROGRESS) { auto status = mSearchHandle->status(); @@ -610,26 +617,29 @@ void GuiScraperSearch::update(int deltaTime) void GuiScraperSearch::updateThumbnail() { - if (mThumbnailReq && mThumbnailReq->status() == HttpReq::REQ_SUCCESS) { + auto it = mThumbnailReqMap.find(mScraperResults[mResultList->getCursorId()].thumbnailImageUrl); + + if (it != mThumbnailReqMap.end() && it->second->status() == HttpReq::REQ_SUCCESS) { // Save thumbnail to mScraperResults cache and set the flag that the // thumbnail download has been completed for this game. - for (auto i = 0; i < mScraperResults.size(); i++) { - if (mScraperResults[i].thumbnailDownloadStatus == IN_PROGRESS) { - mScraperResults[i].ThumbnailImageData = mThumbnailReq->getContent(); - mScraperResults[i].thumbnailDownloadStatus = COMPLETED; - } + if (mScraperResults[mResultList->getCursorId()].thumbnailDownloadStatus == IN_PROGRESS) { + mScraperResults[mResultList->getCursorId()].thumbnailImageData = + it->second->getContent(); + mScraperResults[mResultList->getCursorId()].thumbnailDownloadStatus = COMPLETED; } // Activate the thumbnail in the GUI. - std::string content = mThumbnailReq->getContent(); - mResultThumbnail->setImage(content.data(), content.length()); - mGrid.onSizeChanged(); // A hack to fix the thumbnail position since its size changed. + std::string content = mScraperResults[mResultList->getCursorId()].thumbnailImageData; + if (content.size() > 0) { + mResultThumbnail->setImage(content.data(), content.length()); + mGrid.onSizeChanged(); // A hack to fix the thumbnail position since its size changed. + } } else { - LOG(LogWarning) << "thumbnail req failed: " << mThumbnailReq->getErrorMsg(); + LOG(LogWarning) << "Thumbnail download failed: " << it->second->getErrorMsg(); mResultThumbnail->setImage(""); } - mThumbnailReq.reset(); + mThumbnailReqMap.erase(it); // When the thumbnail has been downloaded and we are in automatic mode, or if // we are in semi-automatic mode with a single matching game result, we proceed diff --git a/es-app/src/guis/GuiScraperSearch.h b/es-app/src/guis/GuiScraperSearch.h index fc340b31c..8f8d95e40 100644 --- a/es-app/src/guis/GuiScraperSearch.h +++ b/es-app/src/guis/GuiScraperSearch.h @@ -127,7 +127,7 @@ private: std::unique_ptr mMDRetrieveURLsHandle; std::unique_ptr mMDResolveHandle; std::vector mScraperResults; - std::unique_ptr mThumbnailReq; + std::map> mThumbnailReqMap; BusyComponent mBusyAnim; }; diff --git a/es-app/src/scrapers/Scraper.cpp b/es-app/src/scrapers/Scraper.cpp index f63475be1..a8832faaa 100644 --- a/es-app/src/scrapers/Scraper.cpp +++ b/es-app/src/scrapers/Scraper.cpp @@ -239,8 +239,8 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result, // If the image is cached already as the thumbnail, then we don't need // to download it again, in this case just save it to disk and resize it. - if (mResult.ThumbnailImageUrl == it->fileURL && - mResult.ThumbnailImageData.size() > 0) { + if (mResult.thumbnailImageUrl == it->fileURL && + mResult.thumbnailImageData.size() > 0) { // Remove any existing media file before attempting to write a new one. // This avoids the problem where there's already a file for this media type @@ -268,7 +268,7 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result, return; } - const std::string& content = mResult.ThumbnailImageData; + const std::string& content = mResult.thumbnailImageData; stream.write(content.data(), content.length()); stream.close(); if (stream.bad()) { diff --git a/es-app/src/scrapers/Scraper.h b/es-app/src/scrapers/Scraper.h index 2f75cc113..d6c65bd15 100644 --- a/es-app/src/scrapers/Scraper.h +++ b/es-app/src/scrapers/Scraper.h @@ -53,8 +53,8 @@ struct ScraperSearchResult { enum downloadStatus thumbnailDownloadStatus = NOT_STARTED; enum downloadStatus mediaFilesDownloadStatus = NOT_STARTED; - std::string ThumbnailImageData; // Thumbnail cache, will contain entire image. - std::string ThumbnailImageUrl; + std::string thumbnailImageData; // Thumbnail cache, this will contain the entire image. + std::string thumbnailImageUrl; std::string box3dUrl; std::string coverUrl;