diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index 6de20adb4..8a4dbe465 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -1201,56 +1201,51 @@ void GameList::CreateDiscSetEntries(const std::vector& excluded_pat std::string GameList::GetCoverImagePathForEntry(const Entry* entry) { - return GetCoverImagePath(entry->path, entry->serial, entry->GetSaveTitle()); + return GetCoverImagePath(entry->path, entry->serial, entry->GetSaveTitle(), entry->has_custom_title); } -static std::string GetFullCoverPath(std::string_view filename, std::string_view extension) +static std::string GetFullCoverPath(std::string_view title, std::string_view extension) { - return fmt::format("{}" FS_OSPATH_SEPARATOR_STR "{}.{}", EmuFolders::Covers, filename, extension); + std::string filename = fmt::format("{}.{}", title, extension); + Path::SanitizeFileName(&filename); + return Path::Combine(EmuFolders::Covers, filename); } std::string GameList::GetCoverImagePath(const std::string_view path, const std::string_view serial, - const std::string_view title) + const std::string_view title, bool is_custom_title) { static constexpr const std::array extensions = {"jpg", "jpeg", "png", "webp"}; std::string ret; - for (const char* extension : extensions) - { - // Prioritize lookup by serial (Most specific) - if (!serial.empty()) + const auto try_name = [&ret](std::string_view name) { + for (const char* extension : extensions) { - std::string cover_path(GetFullCoverPath(serial, extension)); + std::string cover_path = GetFullCoverPath(name, extension); if (FileSystem::FileExists(cover_path.c_str())) { ret = std::move(cover_path); - return ret; + return true; } } + return false; + }; - // Try file title (for modded games or specific like above) - const std::string_view file_title(Path::GetFileTitle(path)); - if (!file_title.empty() && title != file_title) - { - std::string cover_path(GetFullCoverPath(file_title, extension)); - if (FileSystem::FileExists(cover_path.c_str())) - { - ret = std::move(cover_path); - return ret; - } - } + // Check the title first if this is a custom title + if (is_custom_title && try_name(title)) + return ret; - // Last resort, check the game title - if (!title.empty()) - { - std::string cover_path(GetFullCoverPath(title, extension)); - if (FileSystem::FileExists(cover_path.c_str())) - { - ret = std::move(cover_path); - return ret; - } - } - } + // Prioritize lookup by serial (Most specific) + if (!serial.empty() && try_name(serial)) + return ret; + + // Try file title (for modded games or specific like above) + const std::string_view file_title = Path::GetFileTitle(path); + if (!file_title.empty() && (title != file_title || is_custom_title) && try_name(file_title)) + return ret; + + // Last resort, check the game title + if (!title.empty() && !is_custom_title && try_name(title)) + return ret; return ret; } diff --git a/src/core/game_list.h b/src/core/game_list.h index 0b294af30..34392f94d 100644 --- a/src/core/game_list.h +++ b/src/core/game_list.h @@ -143,7 +143,8 @@ std::string FormatTimestamp(std::time_t timestamp); TinyString FormatTimespan(std::time_t timespan, bool long_format = false); std::string GetCoverImagePathForEntry(const Entry* entry); -std::string GetCoverImagePath(const std::string_view path, const std::string_view serial, const std::string_view title); +std::string GetCoverImagePath(const std::string_view path, const std::string_view serial, const std::string_view title, + bool is_custom_title); std::string GetNewCoverImagePathForEntry(const Entry* entry, const char* new_filename, bool use_serial); /// Returns a list of (title, entry) for entries matching serials. Titles will match the gamedb title, diff --git a/src/duckstation-qt/gamelistwidget.cpp b/src/duckstation-qt/gamelistwidget.cpp index 1e51e1840..b84d3047b 100644 --- a/src/duckstation-qt/gamelistwidget.cpp +++ b/src/duckstation-qt/gamelistwidget.cpp @@ -312,9 +312,11 @@ void GameListModel::loadOrGenerateCover(const GameList::Entry* ge) QtAsyncTask::create(this, [path = ge->path, serial = ge->serial, save_title = std::string(ge->GetSaveTitle()), display_title = QtUtils::StringViewToQString(ge->GetDisplayTitle(m_show_localized_titles)), placeholder_image = m_placeholder_image, list = this, width = getCoverArtSize(), - height = getCoverArtSize(), scale = m_cover_scale, dpr = m_device_pixel_ratio]() mutable { + height = getCoverArtSize(), scale = m_cover_scale, dpr = m_device_pixel_ratio, + is_custom_title = ge->has_custom_title]() mutable { QImage image; - loadOrGenerateCover(image, placeholder_image, width, height, scale, dpr, path, serial, save_title, display_title); + loadOrGenerateCover(image, placeholder_image, width, height, scale, dpr, path, serial, save_title, display_title, + is_custom_title); return [path = std::move(path), image = std::move(image), list, scale]() { list->coverLoaded(path, image, scale); }; }); } @@ -353,9 +355,10 @@ void GameListModel::createPlaceholderImage(QImage& image, const QImage& placehol void GameListModel::loadOrGenerateCover(QImage& image, const QImage& placeholder_image, int width, int height, float scale, qreal dpr, const std::string& path, const std::string& serial, - const std::string& save_title, const QString& display_title) + const std::string& save_title, const QString& display_title, + bool is_custom_title) { - const std::string cover_path(GameList::GetCoverImagePath(path, serial, save_title)); + const std::string cover_path = GameList::GetCoverImagePath(path, serial, save_title, is_custom_title); if (!cover_path.empty()) { image.load(QString::fromStdString(cover_path)); diff --git a/src/duckstation-qt/gamelistwidget.h b/src/duckstation-qt/gamelistwidget.h index a69ebe94f..6ec97d087 100644 --- a/src/duckstation-qt/gamelistwidget.h +++ b/src/duckstation-qt/gamelistwidget.h @@ -130,7 +130,7 @@ private: static void loadOrGenerateCover(QImage& image, const QImage& placeholder_image, int width, int height, float scale, qreal dpr, const std::string& path, const std::string& serial, - const std::string& save_title, const QString& display_title); + const std::string& save_title, const QString& display_title, bool is_custom_title); static void createPlaceholderImage(QImage& image, const QImage& placeholder_image, int width, int height, float scale, const QString& title);