Skip to content

Commit cb822f1

Browse files
authored
Minor enhancements and edge-case fixes (#181)
- fix edge case when romname contains roman and european numbers - remove empty gamelist media subfolders after creating gamelist - provide hint when game is 'almost' matched on how to support the matching - provide hint/warning when exprected file is missing to complete artwork as defined in artwork XML file - check well-formedness of artwork XML before entering threading - test: remove surplus test - 'Skyscraper -h' help texts adjusted
1 parent f8d0573 commit cb822f1

11 files changed

Lines changed: 80 additions & 51 deletions

File tree

src/abstractscraper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ void AbstractScraper::runPasses(QList<GameEntry> &gameEntries,
684684
}
685685
if (!candidates.empty()) {
686686
candidates.sort(Qt::CaseInsensitive);
687-
QString pad1 = candidates.length() > 3 ? "\n " : " ";
687+
QString pad1 = candidates.length() > 3 ? "\n " : "";
688688
QString pad2 = candidates.length() > 3 ? "\n " : ", ";
689689
debug.append(QString("Candidates: ") + pad1 +
690690
candidates.join(pad2) + "\n");

src/cli.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,8 @@ void Cli::createParser(QCommandLineParser *parser, QString platforms) {
272272
parser->addOption(uOption);
273273
parser->addOption(verbosityOption);
274274
parser->addVersionOption();
275-
parser->addPositionalArgument(
276-
"romfile", "Specific ROM to scrape, optionally.", "[<romfile>]");
275+
parser->addPositionalArgument("romfile(s)", "Specific ROM(s) to scrape",
276+
"[<romfile> [<romfile> [<romfile> ... ]]]");
277277
}
278278

279279
void Cli::subCommandUsage(const QString subCmd) {

src/compositor.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,35 +57,33 @@
5757

5858
Compositor::Compositor(Settings *config) { this->config = config; }
5959

60-
bool Compositor::processXml() {
61-
Layer newOutputs;
62-
63-
// Check document for errors before running through it
64-
// FIXME: Segfault wenn fishy artwork file und threads > 1
65-
// precheck in static methode auslagern (braucht eh nur artworkXml als param)
66-
// und vor scraperworker spawn testen (nur wenn scraper == "cache")
60+
bool Compositor::preCheckArtworkXml(const QString &artworkXml) {
61+
// Check document for errors before running through it with threads
6762
QDomDocument doc;
6863
QString eMsg;
6964
int eLine;
7065
#if QT_VERSION < 0x060800
71-
if (!doc.setContent(config->artworkXml, false, &eMsg, &eLine)) {
66+
if (!doc.setContent(artworkXml, false, &eMsg, &eLine)) {
7267
#else
73-
QDomDocument::ParseResult p = QDomDocument::setContent(f.readAll());
68+
QDomDocument::ParseResult p = doc.setContent(artworkXml);
7469
eMsg = p.errorMessage;
7570
eLine = p.errorLine;
7671
if (!p) {
7772
#endif
7873
qWarning() << "XML error:" << eMsg << "at line" << eLine;
7974
return false;
8075
}
76+
return true;
77+
}
78+
79+
void Compositor::processXml() {
8180
QXmlStreamReader xml(config->artworkXml);
81+
Layer newOutputs;
8282

8383
// Init recursive parsing
8484
addChildLayers(newOutputs, xml);
85-
8685
// Assign global outputs to these new outputs
8786
outputs = newOutputs;
88-
return true;
8987
}
9088

9189
void Compositor::addChildLayers(Layer &layer, QXmlStreamReader &xml) {
@@ -374,7 +372,7 @@ void Compositor::saveAll(GameEntry &game, QString completeBaseName,
374372
if (!QDir().mkpath(fi.absolutePath())) {
375373
qWarning() << "Path could not be created" << fi.absolutePath()
376374
<< " Check file permissions, gamelist binary data "
377-
"maybe incomplete.";
375+
"may be incomplete.";
378376
}
379377
}
380378

@@ -419,6 +417,14 @@ void Compositor::processChildLayers(GameEntry &game, Layer &layer) {
419417
// If no meaningful canvas could be created, stop processing this
420418
// layer branch entirely
421419
if (thisLayer.canvas.isNull()) {
420+
qWarning()
421+
<< QString("Output of resource '%1' defined in artwork "
422+
"file, but no such data present for game '%2'. "
423+
"Output may not be as expected. To remediate "
424+
"this warning: Re-scrape to get the missing "
425+
"resource or adjust the artwork file.")
426+
.arg(thisLayer.resource)
427+
.arg(game.title);
422428
continue;
423429
}
424430

src/compositor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class Compositor : public QObject {
3838

3939
public:
4040
Compositor(Settings *config);
41-
bool processXml();
41+
static bool preCheckArtworkXml(const QString &artworkXml);
42+
void processXml();
4243
void saveAll(GameEntry &game, QString completeBaseName,
4344
bool isBatocera = false);
4445
QString getSubpath(const QString &absPath);

src/nametools.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ int NameTools::getNumeral(const QString baseName) {
279279
QString roman = match.captured(1);
280280
numeral =
281281
arabicRomanNumerals().key(roman, QString::number(numeral)).toInt();
282+
// 'Mega Man V MSU-1' (roman number wins)
283+
return numeral;
282284
}
283285

284286
// Check for european digits

src/scraperworker.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,7 @@ void ScraperWorker::run() {
104104
platformOrig = config.platform;
105105

106106
Compositor compositor(&config);
107-
if (!compositor.processXml()) {
108-
printf("Something went wrong when parsing artwork xml from '%s', "
109-
"please check the file for errors. Now exiting...\n",
110-
config.artworkConfig.toStdString().c_str());
111-
exit(1);
112-
}
107+
compositor.processXml();
113108

114109
while (queue->hasEntry()) {
115110
// takeEntry() also unlocks the mutex that was locked in hasEntry()
@@ -258,9 +253,18 @@ void ScraperWorker::run() {
258253
game.parNotes = NameTools::getUniqueNotes(game.parNotes, '(');
259254

260255
if (!game.found) {
256+
QString hint =
257+
gameEntries.length() == 0
258+
? " :("
259+
: QString(", but %1 candidate%1: Use --verbosity 3 or "
260+
"--flags interactive or --query '...' or set an "
261+
"alias (aliasMap.csv). =8^)")
262+
.arg(gameEntries.length() == 1 ? "" : "s")
263+
.arg(gameEntries.length());
261264
output.append(
262-
QString("\033[1;33m---- Game '%1' not found :( ----\033[0m\n\n")
263-
.arg(info.completeBaseName()));
265+
QString("\033[1;33m---- Game '%1' not found%2 ----\033[0m\n\n")
266+
.arg(info.completeBaseName())
267+
.arg(hint));
264268
game.resetMedia();
265269
if (!forceEnd) {
266270
forceEnd = limitReached(output);

src/skyscraper.cpp

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "attractmode.h"
2929
#include "batocera.h"
3030
#include "cli.h"
31+
#include "compositor.h"
3132
#include "config.h"
3233
#include "emulationstation.h"
3334
#include "esde.h"
@@ -396,6 +397,14 @@ void Skyscraper::run() {
396397
}
397398
}
398399
printf("\n");
400+
401+
if (!Compositor::preCheckArtworkXml(config.artworkXml)) {
402+
printf("Parsing artwork XML from '%s', failed, see above."
403+
"Check the file for errors. Now exiting...\n",
404+
config.artworkConfig.toStdString().c_str());
405+
exit(1);
406+
}
407+
399408
if (!doCacheScraping) {
400409
printf("Starting scraping run on \033[1;32m%d\033[0m files using "
401410
"\033[1;32m%d\033[0m threads.\nSit back, relax and let me do "
@@ -445,7 +454,7 @@ void Skyscraper::prepareFileQueue() {
445454
QDir inputDir(config.inputFolder, getPlatformFileExtensions(), QDir::Name,
446455
filter);
447456
if (!inputDir.exists()) {
448-
printf("Input folder '\033[1;32m%s\033[0m' doesn't exist or can't be "
457+
printf("Input folder '\033[1;31m%s\033[0m' doesn't exist or can't be "
449458
"accessed by current user. Please check path and permissions.\n",
450459
inputDir.absolutePath().toStdString().c_str());
451460
exit(1);
@@ -588,20 +597,17 @@ void Skyscraper::setFolder(const bool doCacheScraping, QString &outFolder,
588597

589598
void Skyscraper::checkForFolder(QDir &folder, bool create) {
590599
if (!folder.exists()) {
591-
printf("Folder '%s' doesn't exist",
592-
folder.absolutePath().toStdString().c_str());
593600
if (create) {
594-
printf(", trying to create it... ");
595-
fflush(stdout);
596-
if (folder.mkpath(folder.absolutePath())) {
597-
printf("\033[1;32mSuccess!\033[0m\n");
598-
} else {
599-
printf("\033[1;32mFailed!\033[0m Please check path and "
600-
"permissions, now exiting...\n");
601+
if (!folder.mkpath(folder.absolutePath())) {
602+
printf(
603+
"Create folder '\033[1;31m%s\033[0m' failed! Please "
604+
"check path and filesystem permissions, now exiting...\n",
605+
folder.absolutePath().toStdString().c_str());
601606
exit(1);
602607
}
603608
} else {
604-
printf(", can't continue...\n");
609+
printf("Folder '%s' doesn't exist, can't continue...\n",
610+
folder.absolutePath().toStdString().c_str());
605611
exit(1);
606612
}
607613
}
@@ -772,6 +778,18 @@ void Skyscraper::checkThreads() {
772778
printf("\n\n");
773779
}
774780

781+
if (doCacheScraping) {
782+
QStringList mediaDirs = {
783+
config.coversFolder, config.screenshotsFolder,
784+
config.wheelsFolder, config.marqueesFolder,
785+
config.texturesFolder, config.videosFolder,
786+
config.manualsFolder, config.fanartsFolder};
787+
for (const auto &f : mediaDirs) {
788+
QDir dir(f);
789+
dir.rmdir(f);
790+
}
791+
}
792+
775793
// All done, now clean up and exit to terminal
776794
emit finished();
777795
}
@@ -936,7 +954,7 @@ void Skyscraper::loadConfig(const QCommandLineParser &parser) {
936954
}
937955
}
938956

939-
// defaults are always absolute, thus input and mediafolder will be
957+
// defaults are always absolute, thus input- and mediafolder will be
940958
// unchanged by these calls
941959
if (config.frontend == "pegasus") {
942960
config.inputFolder =
@@ -1016,10 +1034,7 @@ void Skyscraper::loadConfig(const QCommandLineParser &parser) {
10161034
}
10171035
if (requestedFileInfo.exists()) {
10181036
QString romPath = requestedFileInfo.absoluteFilePath();
1019-
if (config.frontend == "emulationstation" ||
1020-
config.frontend == "esde") {
1021-
romPath = normalizePath(requestedFileInfo);
1022-
}
1037+
romPath = normalizePath(requestedFileInfo);
10231038
if (!romPath.isEmpty()) {
10241039
cliFiles.append(romPath);
10251040
// Always set refresh and unattend true if user has supplied
@@ -1031,12 +1046,12 @@ void Skyscraper::loadConfig(const QCommandLineParser &parser) {
10311046
continue;
10321047
}
10331048
}
1034-
printf("Filename: '\033[1;32m%s\033[0m' requested either on "
1035-
"command line or with '--includefrom' neither found in platform "
1036-
"folder '%s' nor in current directory!\n\nPlease verify the "
1037-
"filename and try again...\n",
1038-
requestedFile.toStdString().c_str(),
1039-
config.platform.toStdString().c_str());
1049+
printf("Filename: '\033[1;33m%s\033[0m' requested either on command "
1050+
"line or with '--includefrom' not found in(side) the input "
1051+
"directory '\033[1;33m%s\033[0m'!\n\nPlease verify the filename "
1052+
"and try again...\n",
1053+
requestedFileInfo.fileName().toStdString().c_str(),
1054+
config.inputFolder.toStdString().c_str());
10401055
exit(1);
10411056
}
10421057

@@ -1116,8 +1131,10 @@ QString Skyscraper::normalizePath(QFileInfo fileInfo) {
11161131
// normalize paths for single romfiles provided at the CLI.
11171132
// format will be: config.inputFolder + relative-path-of-romfile
11181133
QString canonicalRomPath = fileInfo.canonicalFilePath();
1134+
11191135
// for Windows
11201136
QString cleanRomPath = QDir::cleanPath(canonicalRomPath);
1137+
11211138
QListIterator<QString> iter(cleanRomPath.split("/"));
11221139
iter.toBack();
11231140
QString relativeRomPath;

src/strtools.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ QString StrTools::getVersionHeader() {
290290
dashesString = dashesString % "-";
291291
}
292292

293-
return QString("\033[1;34m" % dashesString % "\033[0m\n\033[1;33m" %
293+
return QString("\033[1;34m" % dashesString % "\033[0m\n\033[1m" %
294294
headerString % "\033[0m\n\033[1;34m" % dashesString %
295295
"\033[0m\n");
296296
}
@@ -364,7 +364,7 @@ QString StrTools::tidyText(QString text, bool ignoreBangs) {
364364
int ctr = 0;
365365
int tmpCtr = -1;
366366
bool itemize = false;
367-
QRegularExpression re("^[\\*●]\\s+");
367+
QRegularExpression re("^[\\*●]\\s+");
368368
QString tmpPiggy;
369369
for (auto l : pars) {
370370
ctr++;

src/xmlreader.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ bool XmlReader::setFile(QString filename) {
4545
#if QT_VERSION < 0x060800
4646
if (setContent(f.readAll(), false, &eMsg, &eLine)) {
4747
#else
48-
// FIXME: compile against 6.8 or later
49-
QDomDocument::ParseResult p = QDomDocument::setContent(f.readAll());
48+
QDomDocument::ParseResult p = setContent(f.readAll());
5049
eMsg = p.errorMessage;
5150
eLine = p.errorLine;
5251
if (p) {

test/nametools/test_nametools.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ private slots:
6767
}
6868
QCOMPARE(NameTools::getNumeral("Blarf 0"), 1);
6969
QCOMPARE(NameTools::getNumeral("Blarf -1"), 1);
70+
QCOMPARE(NameTools::getNumeral("Mega Man V MSU-1"), 5);
7071
}
7172

7273
void testGetSqrNotes() {

0 commit comments

Comments
 (0)