mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-18 05:05:46 -04:00
GameList: Add cover downloader
This commit is contained in:
@ -656,6 +656,14 @@ void FullscreenUI::Render()
|
||||
ImGuiFullscreen::ResetCloseMenuIfNeeded();
|
||||
}
|
||||
|
||||
void FullscreenUI::InvalidateCoverCache()
|
||||
{
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
|
||||
Host::RunOnCPUThread([]() { s_cover_image_map.clear(); });
|
||||
}
|
||||
|
||||
void FullscreenUI::ReturnToMainWindow()
|
||||
{
|
||||
if (s_pause_menu_was_open)
|
||||
|
@ -21,6 +21,7 @@ bool OpenLeaderboardsWindow();
|
||||
|
||||
void Shutdown();
|
||||
void Render();
|
||||
void InvalidateCoverCache();
|
||||
|
||||
// Returns true if the message has been dismissed.
|
||||
bool DrawErrorWindow(const char* message);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/byte_stream.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/http_downloader.h"
|
||||
#include "common/log.h"
|
||||
#include "common/make_array.h"
|
||||
#include "common/path.h"
|
||||
@ -18,9 +19,9 @@
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <ctime>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <tinyxml2.h>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
Log_SetChannel(GameList);
|
||||
|
||||
@ -688,3 +689,113 @@ size_t GameList::Entry::GetReleaseDateString(char* buffer, size_t buffer_size) c
|
||||
|
||||
return std::strftime(buffer, buffer_size, "%d %B %Y", &date_tm);
|
||||
}
|
||||
|
||||
bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, ProgressCallback* progress /*= nullptr*/)
|
||||
{
|
||||
if (!progress)
|
||||
progress = ProgressCallback::NullProgressCallback;
|
||||
|
||||
bool has_title = false;
|
||||
bool has_file_title = false;
|
||||
bool has_serial = false;
|
||||
for (const std::string& url_template : url_templates)
|
||||
{
|
||||
if (!has_title && url_template.find("${title}") != std::string::npos)
|
||||
has_title = true;
|
||||
if (!has_file_title && url_template.find("${filetitle}") != std::string::npos)
|
||||
has_file_title = true;
|
||||
if (!has_serial && url_template.find("${serial}") != std::string::npos)
|
||||
has_serial = true;
|
||||
}
|
||||
if (!has_title && !has_file_title && !has_serial)
|
||||
{
|
||||
progress->DisplayError("URL template must contain at least one of ${title}, ${filetitle}, or ${serial}.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> download_urls;
|
||||
{
|
||||
std::unique_lock lock(s_mutex);
|
||||
for (const GameList::Entry& entry : m_entries)
|
||||
{
|
||||
const std::string existing_path(GetCoverImagePathForEntry(&entry));
|
||||
if (!existing_path.empty())
|
||||
continue;
|
||||
|
||||
for (const std::string& url_template : url_templates)
|
||||
{
|
||||
std::string url(url_template);
|
||||
if (has_title)
|
||||
StringUtil::ReplaceAll(&url, "${title}", Common::HTTPDownloader::URLEncode(entry.title));
|
||||
if (has_file_title)
|
||||
{
|
||||
std::string display_name(FileSystem::GetDisplayNameFromPath(entry.path));
|
||||
StringUtil::ReplaceAll(&url, "${filetitle}",
|
||||
Common::HTTPDownloader::URLEncode(Path::GetFileTitle(display_name)));
|
||||
}
|
||||
if (has_serial)
|
||||
StringUtil::ReplaceAll(&url, "${serial}", Common::HTTPDownloader::URLEncode(entry.serial));
|
||||
|
||||
download_urls.emplace_back(entry.path, std::move(url));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (download_urls.empty())
|
||||
{
|
||||
progress->DisplayError("No URLs to download enumerated.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Common::HTTPDownloader> downloader(Common::HTTPDownloader::Create());
|
||||
if (!downloader)
|
||||
{
|
||||
progress->DisplayError("Failed to create HTTP downloader.");
|
||||
return false;
|
||||
}
|
||||
|
||||
progress->SetCancellable(true);
|
||||
progress->SetProgressRange(static_cast<u32>(download_urls.size()));
|
||||
|
||||
for (auto& [entry_path, url] : download_urls)
|
||||
{
|
||||
if (progress->IsCancelled())
|
||||
break;
|
||||
|
||||
// make sure it didn't get done already
|
||||
{
|
||||
std::unique_lock lock(s_mutex);
|
||||
const GameList::Entry* entry = GetEntryForPath(entry_path.c_str());
|
||||
if (!entry || !GetCoverImagePathForEntry(entry).empty())
|
||||
{
|
||||
progress->IncrementProgressValue();
|
||||
continue;
|
||||
}
|
||||
|
||||
progress->SetFormattedStatusText("Downloading cover for %s...", entry->title.c_str());
|
||||
}
|
||||
|
||||
// we could actually do a few in parallel here...
|
||||
std::string filename(Common::HTTPDownloader::URLDecode(url));
|
||||
downloader->CreateRequest(std::move(url), [entry_path = std::move(entry_path), filename = std::move(filename)](
|
||||
s32 status_code, Common::HTTPDownloader::Request::Data data) {
|
||||
if (status_code != Common::HTTPDownloader::HTTP_OK || data.empty())
|
||||
return;
|
||||
|
||||
std::unique_lock lock(s_mutex);
|
||||
const GameList::Entry* entry = GetEntryForPath(entry_path.c_str());
|
||||
if (!entry || !GetCoverImagePathForEntry(entry).empty())
|
||||
return;
|
||||
|
||||
std::string write_path(GetNewCoverImagePathForEntry(entry, filename.c_str()));
|
||||
if (write_path.empty())
|
||||
return;
|
||||
|
||||
FileSystem::WriteBinaryFile(write_path.c_str(), data.data(), data.size());
|
||||
Host::CoversChanged();
|
||||
});
|
||||
downloader->WaitForAllRequests();
|
||||
progress->IncrementProgressValue();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ void Refresh(bool invalidate_cache, bool only_cache = false, ProgressCallback* p
|
||||
std::string GetCoverImagePathForEntry(const Entry* entry);
|
||||
std::string GetCoverImagePath(const std::string& path, const std::string& serial, const std::string& title);
|
||||
std::string GetNewCoverImagePathForEntry(const Entry* entry, const char* new_filename);
|
||||
|
||||
bool DownloadCovers(const std::vector<std::string>& url_templates, ProgressCallback* progress = nullptr);
|
||||
}; // namespace GameList
|
||||
|
||||
namespace Host {
|
||||
@ -83,4 +85,8 @@ void RefreshGameListAsync(bool invalidate_cache);
|
||||
|
||||
/// Cancels game list refresh, if there is one in progress.
|
||||
void CancelGameListRefresh();
|
||||
|
||||
void DownloadCoversAsync(std::vector<std::string> url_templates);
|
||||
void CancelCoversDownload();
|
||||
void CoversChanged();
|
||||
} // namespace Host
|
||||
|
Reference in New Issue
Block a user