From 8233e2704ea3c61eb73283cc1dd9143d701d8713 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Thu, 30 Jul 2020 20:05:57 +0200 Subject: [PATCH] Added metadata editor button to delete media files from games and folders. --- NEWS.md | 1 + es-app/src/guis/GuiGamelistOptions.cpp | 46 ++++++++++-- es-app/src/guis/GuiMetaDataEd.cpp | 71 +++++++++++++++---- es-app/src/guis/GuiMetaDataEd.h | 6 +- .../src/views/gamelist/BasicGameListView.cpp | 52 +++++++------- es-app/src/views/gamelist/BasicGameListView.h | 1 + .../src/views/gamelist/GridGameListView.cpp | 35 ++++++++- es-app/src/views/gamelist/GridGameListView.h | 1 + es-app/src/views/gamelist/IGameListView.h | 1 + 9 files changed, 166 insertions(+), 48 deletions(-) diff --git a/NEWS.md b/NEWS.md index 32e103a0b..67a174b8b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -41,6 +41,7 @@ Many bugs have been fixed, and numerous features that were only partially implem * Speed improvements and optimizations, the application now starts faster and feels more responsive * Added metadata entry to mark games as broken/not working * Added metadata entry to indicate whether the file should be counted as a game (for example useful to exclude setup files and similar for DOS games) +* Added a button to the metadata editor to delete the media files for a game while retaining the game itself and the gamelist.xml entry * Moved all resources to a subdirectory structure and enabled the CMake install prefix variable to generate the resources search path * Changed theme directory to the install prefix (e.g. /usr/local/share/emulationstation/themes) with themes in the home directory taking precedence * No more attempts to open files directly under /etc, instead only the install prefix directory and the home directory are used diff --git a/es-app/src/guis/GuiGamelistOptions.cpp b/es-app/src/guis/GuiGamelistOptions.cpp index 36a4ef01a..910814e41 100644 --- a/es-app/src/guis/GuiGamelistOptions.cpp +++ b/es-app/src/guis/GuiGamelistOptions.cpp @@ -252,15 +252,47 @@ void GuiGamelistOptions::openMetaDataEd() p.game = file; p.system = file->getSystem(); - std::function deleteBtnFunc; + std::function deleteGameBtnFunc; + std::function deleteMediaBtnFunc; + + deleteMediaBtnFunc = [this, file] { + LOG(LogInfo) << "Deleting all game media files for '" << file->getFullPath() << "'."; + ViewController::get()->getGameListView( + file->getSystem()).get()->removeMedia(file); + }; if (file->getType() == FOLDER) { - deleteBtnFunc = nullptr; + deleteGameBtnFunc = [this, file] { + LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the folder '" << + file->getFullPath() << "'"; + ViewController::get()->getGameListView( + file->getSystem()).get()->removeMedia(file); + + // Manually reset all the metadata values, set the name to the actual folder name. + const std::vector& mdd = file->metadata.getMDD(); + for (auto it = mdd.cbegin(); it != mdd.cend(); it++) { + if (it->key == "name") { + file->metadata.set(it->key, file->getDisplayName()); + continue; + } + file->metadata.set(it->key, it->defaultValue); + } + + ViewController::get()->reloadGameListView(file->getParent()->getSystem()); + // Remove the folder entry from the gamelist.xml file. + file->setDeletionFlag(); + file->getParent()->getSystem()->writeMetaData(); + }; } else { - deleteBtnFunc = [this, file] { + deleteGameBtnFunc = [this, file] { + LOG(LogInfo) << "Deleting the game file '" << file->getFullPath() << + "', all its media files and its gamelist.xml entry."; CollectionSystemManager::get()->deleteCollectionFiles(file); - ViewController::get()->getGameListView(file->getSystem()).get()->remove(file, true); + ViewController::get()->getGameListView( + file->getSystem()).get()->removeMedia(file); + ViewController::get()->getGameListView( + file->getSystem()).get()->remove(file, true); }; } @@ -269,14 +301,16 @@ void GuiGamelistOptions::openMetaDataEd() file->metadata.getMDD(FOLDER_METADATA), p, Utils::FileSystem::getFileName(file->getPath()), std::bind( &IGameListView::onFileChanged, ViewController::get()->getGameListView( - file->getSystem()).get(), file, FILE_METADATA_CHANGED), deleteBtnFunc)); + file->getSystem()).get(), file, FILE_METADATA_CHANGED), + deleteGameBtnFunc, deleteMediaBtnFunc)); } else { mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata, file->metadata.getMDD(GAME_METADATA), p, Utils::FileSystem::getFileName(file->getPath()), std::bind( &IGameListView::onFileChanged, ViewController::get()->getGameListView( - file->getSystem()).get(), file, FILE_METADATA_CHANGED), deleteBtnFunc)); + file->getSystem()).get(), file, FILE_METADATA_CHANGED), + deleteGameBtnFunc, deleteMediaBtnFunc)); } } diff --git a/es-app/src/guis/GuiMetaDataEd.cpp b/es-app/src/guis/GuiMetaDataEd.cpp index 6821f46d9..1dc12bbb2 100644 --- a/es-app/src/guis/GuiMetaDataEd.cpp +++ b/es-app/src/guis/GuiMetaDataEd.cpp @@ -37,17 +37,17 @@ GuiMetaDataEd::GuiMetaDataEd( ScraperSearchParams scraperParams, const std::string& /*header*/, std::function saveCallback, - std::function deleteFunc) + std::function deleteGameFunc, + std::function deleteMediaFunc) : GuiComponent(window), mScraperParams(scraperParams), - mBackground(window, ":/graphics/frame.png"), mGrid(window, Vector2i(1, 3)), - mMetaDataDecl(mdd), mMetaData(md), mSavedCallback(saveCallback), - mDeleteFunc(deleteFunc) + mDeleteGameFunc(deleteGameFunc), + mDeleteMediaFunc(deleteMediaFunc) { addChild(&mBackground); addChild(&mGrid); @@ -237,14 +237,61 @@ GuiMetaDataEd::GuiMetaDataEd( buttons.push_back(std::make_shared(mWindow, "CANCEL", "cancel changes", [&] { delete this; })); - if (mDeleteFunc) { - auto deleteFileAndSelf = [&] { mDeleteFunc(); delete this; }; - auto deleteBtnFunc = [this, deleteFileAndSelf] { - mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), - "THIS WILL DELETE THE ACTUAL GAME FILE(S)!\nARE YOU SURE?", - "YES", deleteFileAndSelf, "NO", nullptr)); }; - buttons.push_back(std::make_shared(mWindow, "DELETE", - "delete game", deleteBtnFunc)); + if (scraperParams.game->getType() == FOLDER) { + if (mDeleteGameFunc) { + auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; }; + auto deleteGameBtnFunc = [this, deleteFilesAndSelf] { + mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), + "THIS WILL DELETE THE MEDIA FILES AND\n" + "THE GAMELIST.XML ENTRY FOR THIS FOLDER.\n" + "HOWEVER NEITHER THE FOLDER ITSELF OR\n" + "ANY DATA FOR THE FILES INSIDE THE FOLDER\n" + "WILL BE DELETED. ARE YOU SURE?", + "YES", deleteFilesAndSelf, "NO", nullptr)); }; + buttons.push_back(std::make_shared(mWindow, "DELETE", + "delete game", deleteGameBtnFunc)); + } + + if (mDeleteMediaFunc) { + auto deleteFilesAndSelf = [&] { mDeleteMediaFunc(); delete this; }; + auto deleteMediaBtnFunc = [this, deleteFilesAndSelf] { + mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), + "THIS WILL DELETE ALL THE MEDIA FILES\n" + "FOR THE ACTUAL FOLDER, BUT NO MEDIA\n" + "FOR ANY FILES INSIDE THE FOLDER WILL\n" + "BE DELETED. ARE YOU SURE?", + "YES", deleteFilesAndSelf, "NO", nullptr)); }; + buttons.push_back(std::make_shared(mWindow, "DELETE MEDIA", + "delete game", deleteMediaBtnFunc)); + } + } + else { + if (mDeleteGameFunc) { + auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; }; + auto deleteGameBtnFunc = [this, deleteFilesAndSelf] { + mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), + "THIS WILL DELETE THE GAME\n" + "FILE, ANY MEDIA FILES AND\n" + "THE GAMELIST.XML ENTRY.\n" + "ARE YOU SURE?", + "YES", deleteFilesAndSelf, "NO", nullptr)); }; + buttons.push_back(std::make_shared(mWindow, "DELETE", + "delete game", deleteGameBtnFunc)); + } + + if (mDeleteMediaFunc) { + auto deleteFilesAndSelf = [&] { mDeleteMediaFunc(); delete this; }; + auto deleteMediaBtnFunc = [this, deleteFilesAndSelf] { + mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), + "THIS WILL DELETE ALL GAME\n" + "MEDIA FILES, BUT WILL KEEP\n" + "THE ACTUAL GAME FILE AND\n" + "THE GAMELIST.XML ENTRY.\n" + "ARE YOU SURE?", + "YES", deleteFilesAndSelf, "NO", nullptr)); }; + buttons.push_back(std::make_shared(mWindow, "DELETE MEDIA", + "delete game", deleteMediaBtnFunc)); + } } mButtons = makeButtonGrid(mWindow, buttons); diff --git a/es-app/src/guis/GuiMetaDataEd.h b/es-app/src/guis/GuiMetaDataEd.h index e93b79c66..d9aae66b7 100644 --- a/es-app/src/guis/GuiMetaDataEd.h +++ b/es-app/src/guis/GuiMetaDataEd.h @@ -29,7 +29,8 @@ public: ScraperSearchParams params, const std::string& header, std::function savedCallback, - std::function deleteFunc); + std::function deleteGameFunc, + std::function deleteMediaFunc); bool input(InputConfig* config, Input input) override; void onSizeChanged() override; @@ -59,7 +60,8 @@ private: std::vector mMetaDataDecl; MetaDataList* mMetaData; std::function mSavedCallback; - std::function mDeleteFunc; + std::function mDeleteGameFunc; + std::function mDeleteMediaFunc; bool mMediaFilesUpdated; }; diff --git a/es-app/src/views/gamelist/BasicGameListView.cpp b/es-app/src/views/gamelist/BasicGameListView.cpp index bca093bbf..8ce59c048 100644 --- a/es-app/src/views/gamelist/BasicGameListView.cpp +++ b/es-app/src/views/gamelist/BasicGameListView.cpp @@ -135,33 +135,10 @@ void BasicGameListView::launch(FileData* game) void BasicGameListView::remove(FileData *game, bool deleteFile) { - // Actually delete the file on the filesystem. - if (deleteFile) { + // Delete the game file on the filesystem. + if (deleteFile) Utils::FileSystem::removeFile(game->getPath()); - // Remove all game media files as well. - if (Utils::FileSystem::exists(game->getVideoPath())) - Utils::FileSystem::removeFile(game->getVideoPath()); - - if (Utils::FileSystem::exists(game->getMiximagePath())) - Utils::FileSystem::removeFile(game->getMiximagePath()); - - if (Utils::FileSystem::exists(game->getScreenshotPath())) - Utils::FileSystem::removeFile(game->getScreenshotPath()); - - if (Utils::FileSystem::exists(game->getCoverPath())) - Utils::FileSystem::removeFile(game->getCoverPath()); - - if (Utils::FileSystem::exists(game->getMarqueePath())) - Utils::FileSystem::removeFile(game->getMarqueePath()); - - if (Utils::FileSystem::exists(game->get3DBoxPath())) - Utils::FileSystem::removeFile(game->get3DBoxPath()); - - if (Utils::FileSystem::exists(game->getThumbnailPath())) - Utils::FileSystem::removeFile(game->getThumbnailPath()); - } - FileData* parent = game->getParent(); // Select next element in list, or previous if none. if (getCursor() == game) { @@ -190,6 +167,31 @@ void BasicGameListView::remove(FileData *game, bool deleteFile) onFileChanged(parent, FILE_REMOVED); } +void BasicGameListView::removeMedia(FileData *game) +{ + // Remove all game media files on the filesystem. + if (Utils::FileSystem::exists(game->getVideoPath())) + Utils::FileSystem::removeFile(game->getVideoPath()); + + if (Utils::FileSystem::exists(game->getMiximagePath())) + Utils::FileSystem::removeFile(game->getMiximagePath()); + + if (Utils::FileSystem::exists(game->getScreenshotPath())) + Utils::FileSystem::removeFile(game->getScreenshotPath()); + + if (Utils::FileSystem::exists(game->getCoverPath())) + Utils::FileSystem::removeFile(game->getCoverPath()); + + if (Utils::FileSystem::exists(game->getMarqueePath())) + Utils::FileSystem::removeFile(game->getMarqueePath()); + + if (Utils::FileSystem::exists(game->get3DBoxPath())) + Utils::FileSystem::removeFile(game->get3DBoxPath()); + + if (Utils::FileSystem::exists(game->getThumbnailPath())) + Utils::FileSystem::removeFile(game->getThumbnailPath()); +} + std::vector BasicGameListView::getHelpPrompts() { std::vector prompts; diff --git a/es-app/src/views/gamelist/BasicGameListView.h b/es-app/src/views/gamelist/BasicGameListView.h index f1d96eb33..f0c54c881 100644 --- a/es-app/src/views/gamelist/BasicGameListView.h +++ b/es-app/src/views/gamelist/BasicGameListView.h @@ -36,6 +36,7 @@ protected: virtual std::string getQuickSystemSelectLeftButton() override; virtual void populateList(const std::vector& files) override; virtual void remove(FileData* game, bool deleteFile) override; + virtual void removeMedia(FileData* game) override; virtual void addPlaceholder(); TextListComponent mList; diff --git a/es-app/src/views/gamelist/GridGameListView.cpp b/es-app/src/views/gamelist/GridGameListView.cpp index 45f090961..7f1c242fd 100644 --- a/es-app/src/views/gamelist/GridGameListView.cpp +++ b/es-app/src/views/gamelist/GridGameListView.cpp @@ -450,7 +450,7 @@ void GridGameListView::launch(FileData* game) void GridGameListView::remove(FileData *game, bool deleteFile) { - // Actually delete the file on the filesystem. + // Delete the game file on the filesystem. if (deleteFile) Utils::FileSystem::removeFile(game->getPath()); @@ -472,12 +472,41 @@ void GridGameListView::remove(FileData *game, bool deleteFile) if (mGrid.size() == 0) addPlaceholder(); - // Remove before repopulating (removes from parent). - // Update the view, with game removed. + // If a game has been deleted, immediately remove the entry from gamelist.xml + // regardless of the value of the setting SaveGamelistsMode. + game->setDeletionFlag(); + parent->getSystem()->writeMetaData(); + + // Remove before repopulating (removes from parent), then update the view. delete game; onFileChanged(parent, FILE_REMOVED); } +void GridGameListView::removeMedia(FileData *game) +{ + // Remove all game media files on the filesystem. + if (Utils::FileSystem::exists(game->getVideoPath())) + Utils::FileSystem::removeFile(game->getVideoPath()); + + if (Utils::FileSystem::exists(game->getMiximagePath())) + Utils::FileSystem::removeFile(game->getMiximagePath()); + + if (Utils::FileSystem::exists(game->getScreenshotPath())) + Utils::FileSystem::removeFile(game->getScreenshotPath()); + + if (Utils::FileSystem::exists(game->getCoverPath())) + Utils::FileSystem::removeFile(game->getCoverPath()); + + if (Utils::FileSystem::exists(game->getMarqueePath())) + Utils::FileSystem::removeFile(game->getMarqueePath()); + + if (Utils::FileSystem::exists(game->get3DBoxPath())) + Utils::FileSystem::removeFile(game->get3DBoxPath()); + + if (Utils::FileSystem::exists(game->getThumbnailPath())) + Utils::FileSystem::removeFile(game->getThumbnailPath()); +} + std::vector GridGameListView::getMDLabels() { std::vector ret; diff --git a/es-app/src/views/gamelist/GridGameListView.h b/es-app/src/views/gamelist/GridGameListView.h index 6519c5e01..ce52019b4 100644 --- a/es-app/src/views/gamelist/GridGameListView.h +++ b/es-app/src/views/gamelist/GridGameListView.h @@ -43,6 +43,7 @@ protected: virtual std::string getQuickSystemSelectLeftButton() override; virtual void populateList(const std::vector& files) override; virtual void remove(FileData* game, bool deleteFile) override; + virtual void removeMedia(FileData* game) override; virtual void addPlaceholder(); ImageGridComponent mGrid; diff --git a/es-app/src/views/gamelist/IGameListView.h b/es-app/src/views/gamelist/IGameListView.h index 81250c70b..c1698e598 100644 --- a/es-app/src/views/gamelist/IGameListView.h +++ b/es-app/src/views/gamelist/IGameListView.h @@ -48,6 +48,7 @@ public: virtual bool input(InputConfig* config, Input input) override; virtual void remove(FileData* game, bool deleteFile) = 0; + virtual void removeMedia(FileData* game) = 0; virtual const char* getName() const = 0; virtual void launch(FileData* game) = 0;