Made the automatic gamelist view style work with the new media handling logic.

This commit is contained in:
Leon Styhre 2020-07-13 20:10:09 +02:00
parent 09bbb925f9
commit 6199f7371d
8 changed files with 82 additions and 19 deletions

View file

@ -1,8 +1,26 @@
EmulationStation Desktop Edition - User Guide EmulationStation Desktop Edition - User Guide
============================================= =============================================
**Note:** This document is intended as a quick start guide, for more in-depth information and details on how to compile EmulationStation and perform more advanced configuration, please refer to the [INSTALL.md](INSTALL.md) document.
### Getting started ### Getting started
Getting started with EmulationStation is very easy, just make sure to install the software properly, either manually as built from source code or using one of the supplied packages. On Windows you'll use the installer instead of a package.
Upon first startup, ES will create its home directory, by default the location is ~/.emulationstation.
On Unix this defaults to /home/<username>/.emulationstation/ and on Windows it defaults to C:\Users\<username>\.emulationstation\
A settings file, `es_settings.cfg` will be generated with all the default settings, and a `es_systems.cfg` file will also be copied from the program resource folder, that contains the game ROM and emulator settings.
There's a log file in the home directory as well named `es_log.txt`, please refer to this in case on any errors as it should provide information on what went wrong.
Upon startup with the default settings, ES is set to the gamelist view style `AUTOMATIC`. In this mode the application will look for any game media files (videos and images) and set the view style accordingly. If at least one image is found for any game for a certain system, the view style `DETAILED` will be shown and if at least one video file is found, the view style `VIDEO` will be selected. The gamelist view styles are described in more detail later in this document.
### Main screen
### Main menu ### Main menu

View file

@ -292,6 +292,8 @@ void GuiMetaDataEd::fetchDone(const ScraperSearchResult& result)
MetaDataList* metadata = nullptr; MetaDataList* metadata = nullptr;
metadata = new MetaDataList(*mMetaData); metadata = new MetaDataList(*mMetaData);
mMediaFilesUpdated = result.savedNewImages;
// Check if any values were manually changed before starting the scraping. // Check if any values were manually changed before starting the scraping.
// If so, it's these values we should compare against when scraping, not // If so, it's these values we should compare against when scraping, not
// the values previously saved for the game. // the values previously saved for the game.
@ -356,8 +358,7 @@ void GuiMetaDataEd::close()
std::function<void()> closeFunc; std::function<void()> closeFunc;
closeFunc = [this] { delete this; }; closeFunc = [this] { delete this; };
if (dirty) if (dirty) {
{
// Changes were made, ask if the user wants to save them. // Changes were made, ask if the user wants to save them.
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"SAVE CHANGES?", "SAVE CHANGES?",
@ -366,6 +367,9 @@ void GuiMetaDataEd::close()
)); ));
} }
else { else {
// Always save if the media files have been changed (i.e. newly scraped images).
if (mMediaFilesUpdated)
save();
closeFunc(); closeFunc();
} }
} }

View file

@ -62,6 +62,7 @@ private:
std::function<void()> mDeleteFunc; std::function<void()> mDeleteFunc;
bool mMetadataUpdated; bool mMetadataUpdated;
bool mMediaFilesUpdated;
}; };
#endif // ES_APP_GUIS_GUI_META_DATA_ED_H #endif // ES_APP_GUIS_GUI_META_DATA_ED_H

View file

@ -11,10 +11,11 @@
#include "utils/StringUtil.h" #include "utils/StringUtil.h"
#include "FileData.h" #include "FileData.h"
#include "GamesDBJSONScraper.h" #include "GamesDBJSONScraper.h"
#include "ScreenScraper.h"
#include "Log.h" #include "Log.h"
#include "ScreenScraper.h"
#include "Settings.h" #include "Settings.h"
#include "SystemData.h" #include "SystemData.h"
#include <FreeImage.h> #include <FreeImage.h>
#include <fstream> #include <fstream>
@ -45,14 +46,15 @@ std::unique_ptr<ScraperSearchHandle> startMediaURLsFetch(const std::string& game
ScraperSearchParams params; ScraperSearchParams params;
// Check if the scraper in the settings still exists as a registered scraping source. // Check if the scraper in the settings still exists as a registered scraping source.
if (scraper_request_funcs.find(name) == scraper_request_funcs.end()) if (scraper_request_funcs.find(name) == scraper_request_funcs.end()) {
LOG(LogWarning) << "Warning - Configured scraper (" << name << LOG(LogWarning) << "Warning - Configured scraper (" << name <<
") unavailable, scraping aborted."; ") unavailable, scraping aborted.";
else }
else {
// Specifically use the TheGamesDB function as this type of request // Specifically use the TheGamesDB function as this type of request
// will never occur for ScreenScraper. // will never occur for ScreenScraper.
thegamesdb_generate_json_scraper_requests(gameIDs, handle->mRequestQueue, thegamesdb_generate_json_scraper_requests(gameIDs, handle->mRequestQueue, handle->mResults);
handle->mResults); }
return handle; return handle;
} }
@ -167,6 +169,8 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
std::vector<struct mediaFileInfoStruct> scrapeFiles; std::vector<struct mediaFileInfoStruct> scrapeFiles;
mResult.savedNewImages = false;
if (Settings::getInstance()->getBool("Scrape3DBoxes") && result.box3dUrl != "") { if (Settings::getInstance()->getBool("Scrape3DBoxes") && result.box3dUrl != "") {
mediaFileInfo.fileURL = result.box3dUrl; mediaFileInfo.fileURL = result.box3dUrl;
mediaFileInfo.fileFormat = result.box3dFormat; mediaFileInfo.fileFormat = result.box3dFormat;
@ -265,11 +269,13 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
setError("Error saving resized image. Out of memory? Disk full?"); setError("Error saving resized image. Out of memory? Disk full?");
return; return;
} }
mResult.savedNewImages = true;
} }
// If it's not cached, then initiate the download. // If it's not cached, then initiate the download.
else { else {
mFuncs.push_back(ResolvePair(downloadImageAsync(it->fileURL, filePath, mFuncs.push_back(ResolvePair(downloadImageAsync(it->fileURL, filePath,
it->existingMediaFile), [this, filePath] { it->existingMediaFile, mResult.savedNewImages), [this, filePath] {
})); }));
} }
} }
@ -300,12 +306,13 @@ void MDResolveHandle::update()
} }
std::unique_ptr<ImageDownloadHandle> downloadImageAsync(const std::string& url, std::unique_ptr<ImageDownloadHandle> downloadImageAsync(const std::string& url,
const std::string& saveAs, const std::string& existingMediaFile) const std::string& saveAs, const std::string& existingMediaFile, bool& savedNewImage)
{ {
return std::unique_ptr<ImageDownloadHandle>(new ImageDownloadHandle( return std::unique_ptr<ImageDownloadHandle>(new ImageDownloadHandle(
url, url,
saveAs, saveAs,
existingMediaFile, existingMediaFile,
savedNewImage,
Settings::getInstance()->getInt("ScraperResizeMaxWidth"), Settings::getInstance()->getInt("ScraperResizeMaxWidth"),
Settings::getInstance()->getInt("ScraperResizeMaxHeight"))); Settings::getInstance()->getInt("ScraperResizeMaxHeight")));
} }
@ -314,6 +321,7 @@ ImageDownloadHandle::ImageDownloadHandle(
const std::string& url, const std::string& url,
const std::string& path, const std::string& path,
const std::string& existingMediaPath, const std::string& existingMediaPath,
bool& savedNewImage,
int maxWidth, int maxWidth,
int maxHeight) int maxHeight)
: mSavePath(path), : mSavePath(path),
@ -322,6 +330,7 @@ ImageDownloadHandle::ImageDownloadHandle(
mMaxHeight(maxHeight), mMaxHeight(maxHeight),
mReq(new HttpReq(url)) mReq(new HttpReq(url))
{ {
mSavedNewImagePtr = &savedNewImage;
} }
void ImageDownloadHandle::update() void ImageDownloadHandle::update()
@ -377,6 +386,9 @@ void ImageDownloadHandle::update()
return; return;
} }
// If this image was successfully saved, update savedNewImages in ScraperSearchResult.
*mSavedNewImagePtr = true;
setStatus(ASYNC_DONE); setStatus(ASYNC_DONE);
} }

View file

@ -64,6 +64,9 @@ struct ScraperSearchResult {
std::string coverFormat; std::string coverFormat;
std::string marqueeFormat; std::string marqueeFormat;
std::string screenshotFormat; std::string screenshotFormat;
// Indicate whether any new images were downloaded and saved.
bool savedNewImages;
}; };
// So let me explain why I've abstracted this so heavily. // So let me explain why I've abstracted this so heavily.
@ -184,6 +187,7 @@ public:
const std::string& url, const std::string& url,
const std::string& path, const std::string& path,
const std::string& existingMediaPath, const std::string& existingMediaPath,
bool& savedNewImage,
int maxWidth, int maxWidth,
int maxHeight); int maxHeight);
@ -193,6 +197,7 @@ private:
std::unique_ptr<HttpReq> mReq; std::unique_ptr<HttpReq> mReq;
std::string mSavePath; std::string mSavePath;
std::string mExistingMediaFile; std::string mExistingMediaFile;
bool *mSavedNewImagePtr;
int mMaxWidth; int mMaxWidth;
int mMaxHeight; int mMaxHeight;
}; };
@ -206,7 +211,7 @@ std::string getSaveAsPath(const ScraperSearchParams& params,
// Will resize according to Settings::getInt("ScraperResizeMaxWidth") and // Will resize according to Settings::getInt("ScraperResizeMaxWidth") and
// Settings::getInt("ScraperResizeMaxHeight"). // Settings::getInt("ScraperResizeMaxHeight").
std::unique_ptr<ImageDownloadHandle> downloadImageAsync(const std::string& url, std::unique_ptr<ImageDownloadHandle> downloadImageAsync(const std::string& url,
const std::string& saveAs, const std::string& existingMediaPath); const std::string& saveAs, const std::string& existingMediaPath, bool& savedNewImage);
// Resolves all metadata assets that need to be downloaded. // Resolves all metadata assets that need to be downloaded.
std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result, std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result,

View file

@ -326,7 +326,7 @@ std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* syste
selectedViewType = VIDEO; selectedViewType = VIDEO;
break; break;
} }
else if (!(*it)->getThumbnailPath().empty()) { else if (!(*it)->getImagePath().empty()) {
selectedViewType = DETAILED; selectedViewType = DETAILED;
// Don't break out in case any subsequent files have videos. // Don't break out in case any subsequent files have videos.
} }

View file

@ -13,11 +13,8 @@
#include "Settings.h" #include "Settings.h"
#include "SystemData.h" #include "SystemData.h"
BasicGameListView::BasicGameListView( BasicGameListView::BasicGameListView(Window* window, FileData* root)
Window* window, : ISimpleGameListView(window, root), mList(window)
FileData* root)
: ISimpleGameListView(window, root),
mList(window)
{ {
mList.setSize(mSize.x(), mSize.y() * 0.8f); mList.setSize(mSize.x(), mSize.y() * 0.8f);
mList.setPosition(0, mSize.y() * 0.2f); mList.setPosition(0, mSize.y() * 0.2f);
@ -38,8 +35,7 @@ void BasicGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
void BasicGameListView::onFileChanged(FileData* file, FileChangeType change) void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
{ {
if (change == FILE_METADATA_CHANGED) if (change == FILE_METADATA_CHANGED) {
{
// Might switch to a detailed view. // Might switch to a detailed view.
ViewController::get()->reloadGameListView(this); ViewController::get()->reloadGameListView(this);
return; return;
@ -146,6 +142,28 @@ void BasicGameListView::remove(FileData *game, bool deleteFile)
if (deleteFile) if (deleteFile)
Utils::FileSystem::removeFile(game->getPath()); 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(); FileData* parent = game->getParent();
// Select next element in list, or previous if none. // Select next element in list, or previous if none.
if (getCursor() == game) { if (getCursor() == game) {
@ -164,6 +182,11 @@ void BasicGameListView::remove(FileData *game, bool deleteFile)
if (mList.size() == 0) if (mList.size() == 0)
addPlaceholder(); addPlaceholder();
// 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. // Remove before repopulating (removes from parent), then update the view.
delete game; delete game;
onFileChanged(parent, FILE_REMOVED); onFileChanged(parent, FILE_REMOVED);

View file

@ -77,7 +77,7 @@ void Settings::setDefaults()
// UI settings. // UI settings.
mStringMap["StartupSystem"] = ""; mStringMap["StartupSystem"] = "";
mStringMap["GamelistViewStyle"] = "detailed"; mStringMap["GamelistViewStyle"] = "automatic";
mStringMap["TransitionStyle"] = "instant"; mStringMap["TransitionStyle"] = "instant";
mStringMap["ThemeSet"] = ""; mStringMap["ThemeSet"] = "";
mStringMap["UIMode"] = "Full"; mStringMap["UIMode"] = "Full";