Skip to content

Commit cd502c4

Browse files
committed
Adjust artwork and filetypes for batocera:
- Have wheel transparent when using for marquee. - Use wheel resource as value for marquee in gamelist - Use thumbnail xml element for cover display - Configurable path specifications for batocera and others (e.g., home path) - Update docs (for batocera frontend)
1 parent aeac8e3 commit cd502c4

20 files changed

Lines changed: 199 additions & 80 deletions

batocera-artwork.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<!-- Just the screenshot without any decorations or scaling -->
32
<artwork>
3+
<!-- copies the resourcetypes without any artwork applied to the respective mediafolder -->
44
<output type="screenshot"/>
5+
<output type="marquee" resource="wheel" />
6+
<output type="cover" />
7+
<output type="wheel" />
58
</artwork>

config.ini.example

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,9 @@ cacheRefresh="true"
193193
cacheScreenshots="false"
194194

195195
[batocera]
196-
artworkXml="batocera-artwork.xml"
196+
artworkXml="batocera-artwork.xml"
197+
;gameListFolder="~/path/to/mounted/userdata/roms"
198+
; relative to gameListFolder
199+
inputFolder="."
200+
mediaFolder="."
201+
;videos="true"

docs/CONFIGINI.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ This is an alphabetical index of all configuration options their usage level and
103103
| [includePattern](CONFIGINI.md#includepattern) | Advanced | Y | Y | Y | |
104104
| [innerBracketsReplace](CONFIGINI.md#innerbracketsreplace) | Expert | Y | | | |
105105
| [innerParenthesesReplace](CONFIGINI.md#innerparenthesesreplace) | Expert | Y | | | |
106-
| [inputFolder](CONFIGINI.md#inputfolder) | Advanced | Y | Y | | |
106+
| [inputFolder](CONFIGINI.md#inputfolder) | Advanced | Y | Y | Y | |
107107
| [interactive](CONFIGINI.md#interactive) | Basic | Y | Y | | Y |
108108
| [jpgQuality](CONFIGINI.md#jpgquality) | Advanced | Y | Y | | Y |
109109
| [keepDiscInfo](CONFIGINI.md#keepdiscinfo) | Expert | Y | Y | | |
@@ -150,10 +150,12 @@ Sets the rom input folder. By default Skyscraper will look for roms in the `/hom
150150

151151
!!! note
152152

153-
If this is set in the `[main]` section it will automatically add `/<PLATFORM>` to the end of the path. If you want better control consider adding it to a `[<PLATFORM>]` section instead where it will be used as is.
153+
If this is set in the `[main]` or `[<FRONTEND>]` section it will automatically add `/<PLATFORM>` to the end of the path. If you want better control consider adding it to a `[<PLATFORM>]` section instead where it will be used as is.
154154

155155
Default value: `/home/<USER>/RetroPie/roms/<PLATFORM>`
156-
Allowed in sections: `[main]`, `[<PLATFORM>]`
156+
Allowed in sections: `[main]`, `[<PLATFORM>]`, `[<FRONTEND>]`
157+
158+
The default is valid for the most frontends, very few [frontends](FRONTENDS.md) do use a different default value.
157159

158160
---
159161

@@ -168,6 +170,8 @@ Sets the game list export folder. By default Skyscraper exports the game list to
168170
Default value: `/home/<USER>/RetroPie/roms/<PLATFORM>`
169171
Allowed in sections: `[main]`, `[<PLATFORM>]`, `[<FRONTEND>]`
170172

173+
The default is valid for the most frontends, very few [frontends](FRONTENDS.md) do use a different default value.
174+
171175
---
172176

173177
#### gameListFilename
@@ -201,6 +205,8 @@ Read more about the [artwork compositing](ARTWORK.md).
201205
Default value: `/home/<USER>/RetroPie/roms/<PLATFORM>/media`
202206
Allowed in sections: `[main]`, `[<PLATFORM>]`, `[<FRONTEND>]`
203207

208+
The default is valid for the most frontends, very few [frontends](FRONTENDS.md) do use a different default value.
209+
204210
---
205211

206212
#### mediaFolderHidden

docs/FRONTENDS.md

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
When generating a game list with Skyscraper you have the option of generating it for several different frontends. A frontend is the graphical interface that lists and launches your games.
44

5-
Setting a frontend when generating a game list is done by setting the `-f <FRONTEND>` command-line parameter as explained [in the commandline documentation](CLIHELP.md#-f-frontend) or by setting it in `/home/<USER>/.skyscraper/config.ini` as explained [config file documentation](CONFIGINI.md#frontend). Use for the `<FRONTEND>` value the frontend name all lowercase and with alphabetical characters only: `emulationstation`, `esde`, `pegasus`, `retrobat`, `attractmode`. Some frontends have further options that are either optional or required. Check the frontend sections below for more information on this.
5+
!!! danger inline end "Backup Any Manual Changes of Your Gamelists"
66

7-
!!! warning
7+
Skyscraper will overwrite your game list (obviously). So if you have spend a lot of time hand-crafting metadata in a game list for any frontend, please remember to create a backup before overwriting it with Skyscraper. You can also tell Skyscraper to auto-backup old game lists prior to overwriting them. Read more about the [`gameListBackup` config option](CONFIGINI.md#gamelistbackup).
88

9-
Skyscraper will overwrite your game list (obviously). So if you have spend a lot of time hand-crafting metadata in a game list for any frontend, please remember to create a backup before overwriting it with Skyscraper. You can also tell Skyscraper to auto-backup old game lists prior to overwriting them. Read more about the [`gamelistbackup` config option](CONFIGINI.md#gamelistbackup).
9+
Setting a frontend when generating a game list is done by setting the `-f <FRONTEND>` command-line parameter as explained [in the commandline documentation](CLIHELP.md#-f-frontend) or by setting it in `/home/<USER>/.skyscraper/config.ini` as explained [config file documentation](CONFIGINI.md#frontend). Use for the `<FRONTEND>` value the frontend name all lowercase and with alphabetical characters only: `emulationstation`, `esde`, `pegasus`, `retrobat`, `attractmode`. Some frontends have further options that are either optional or required. Check the frontend sections below for more information on this.
1010

1111
When generating a game list for any frontend, Skyscraper will try to preserve certain metadata. Check the frontend sections below for more information on what metadata is preserved per frontend.
1212

@@ -21,7 +21,7 @@ This is the default frontend used when generating a game list with Skyscraper. I
2121

2222
Skyscraper will preserve the following metadata when re-generating a game list for EmulationStation: `favorite`, `hidden`, `kidgame`, `lastplayed`, `playcount`, `sortname`. Also existing `<folder/>` elements of a gamelist file will be preserved. The user editable sub-XML elements for a folder are listed in the [`Metadata.cpp` of EmulationStation](https://github.com/RetroPie/EmulationStation/blob/01de7618d0d248fa2ff1eacde09a20d9d2af5f10/es-app/src/MetaData.cpp#L30).
2323

24-
!!! warning
24+
!!! warning "Folder Data is Not Cached"
2525

2626
Folder data is not cached by Skyscraper, thus if you delete your `gamelist.xml`, Skyscraper can not restore the edited folder elements from cache.
2727

@@ -124,7 +124,7 @@ This is the complete set of scraping binary data supported by Skyscraper:
124124

125125
| Batocera Gamelist XML-Element | Skyscraper support |
126126
| :---------------------------- | :----------------: |
127-
| boxart ||
127+
| thumbnail (cover) ||
128128
| fanart ||
129129
| image (in game Screenshot) ||
130130
| manual ||
@@ -139,13 +139,17 @@ every `<PLATFORM>` you scrape.
139139
- Default game list filename: `gamelist.xml`
140140
- Default media file location: `/userdata/roms/<PLATFORM>/{images,videos,manuals}`
141141

142+
If you set a game list location and do not specifiy the ROM folder (input
143+
folder) and media folder, then these are set relatively to the game list folder.
144+
142145
#### Metadata preservation
143146

144-
These extra elements are preserved.
147+
These extra elements are preserved when they are present in the Gamelist file.
145148

146149
| Batocera Gamelist XML-Element | When present in Gamelist |
147150
| :---------------------------- | :-----------------------: |
148151
| `bezel` | Preserved |
152+
| `boxart` | Preserved |
149153
| `boxback` | Preserved |
150154
| `cartridge` | Preserved |
151155
| `magazine` | Preserved |
@@ -155,7 +159,7 @@ These extra elements are preserved.
155159
| `thumbnail` | Preserved |
156160
| `titleshot` | Preserved |
157161

158-
Also all other non scrapable elements are preserved (Batocera EmulationStation
162+
Also, all other non scrapable elements are preserved (Batocera EmulationStation
159163
adds those on occasion) like: `cheevosHash`, `cheevosId`, `scrap`, ...
160164

161165
#### Usage of Skyscraper for Batocera
@@ -178,7 +182,7 @@ Windows desktop users can use SMB shares and can adapt the following steps.
178182
1. Mount the root folder of Batocera in your Desktop system. Let the mountpoint
179183
be `/home/mylogin/bato_sshfs` in this example:
180184
```bash
181-
mount -t sshfs root@<batocera-IP-address>:/ /home/mylogin/bato_sshfs
185+
mount -t sshfs root@batocera:/ /home/mylogin/bato_sshfs
182186
```
183187
2. Change to the platform folder (in this case `snes`) you want to scrape:
184188
```bash
@@ -193,7 +197,24 @@ Windows desktop users can use SMB shares and can adapt the following steps.
193197
You can also set the values for [input-](CONFIGINI.md#inputfolder) (`-i`),
194198
[gamelist-](CONFIGINI.md#gamelistfolder) (`-g`) und
195199
[media-folder](CONFIGINI.md#mediafolder) (`-o`) permanently in the Skyscraper
196-
config file.
200+
config file. You can find a sample configuration at the `[batocera]` section
201+
(at the end of `config.ini.example`):
202+
```ini
203+
[batocera]
204+
artworkXml="batocera-artwork.xml"
205+
gameListFolder="~/bato_sshfs/userdata/roms"
206+
; relative to gameListFolder
207+
inputFolder="."
208+
mediaFolder="."
209+
;videos="true"
210+
```
211+
With this addition the Skyscraper invocation is reduced to:
212+
```bash
213+
Skyscraper -f batocera -p <platform>
214+
```
215+
You may also set the default [frontend in the
216+
configuration](CONFIGINI.md#frontend), then you can even drop the `-f` CLI
217+
parameter.
197218
4. Afterwards run the gamelist creation and media file deployment from
198219
cache:
199220
```bash
@@ -220,7 +241,7 @@ Windows desktop users can use SMB shares and can adapt the following steps.
220241
of. Also you will have to add your credentials for Screenscraper for example in
221242
the [config file of Skyscraper](CONFIGINI.md#usercreds).
222243

223-
For general advise on SSH usage see the [Batocera
244+
For general advise on SSH usage and the default password see the [Batocera
224245
documentation](https://wiki.batocera.org/security).
225246

226247
### Attract-Mode

docs/PATHHANDLING.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
## Path Logic in Skyscraper
22

3+
!!! tip inline end "Absolute Paths"
4+
5+
You may use `~/` at the beginning of the path. This will be replaced with
6+
the current [home directory](https://doc.qt.io/qt-6/qdir.html#homePath)
7+
specific to the OS platform. The notation `~account/some/path` is not
8+
supported.
9+
310
This page describes how Skyscraper processes the different paths and especially
411
how the absolute path is calculated when a you provide a relative path.
512

@@ -66,12 +73,12 @@ error message.
6673

6774
If you define a relative path Gamelist folder either via `-g` or via
6875
`gameListFolder=` (INI-file) and are using a frontend for EmulationStation (or
69-
any other frontend, which is _not_ Pegasus) then the configuration for input
70-
folder _must_ be provided absolute and can not be relative. In turn, the media
71-
folder, if it is a relative path, is then assumed to be relative to the input
72-
folder.
76+
any other frontend, which is _neither_ Pegasus _nor_ Batocera) then the
77+
configuration for input folder _must_ be provided absolute and can not be
78+
relative. In turn, the media folder, if it is a relative path, is then assumed
79+
to be relative to the input folder.
7380

74-
However, if you selected the Pegasus frontend then the input folder may be
81+
However, if you selected the Pegasus or Batocera frontend then the input folder may be
7582
relative. The input folder and media folder, when relative, are then interpreted
7683
by Skyscraper to be relative to the game list folder.
7784

src/attractmode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ QString AttractMode::getMediaTypeFolder(QString type, bool detectVideoPath) {
321321
while (!emulatorFile.atEnd()) {
322322
QByteArray line = emulatorFile.readLine();
323323
line = line.trimmed();
324-
line.replace("~", QDir::homePath().toUtf8());
324+
line.replace("~/", QDir::homePath().toUtf8() + "/");
325325
line.replace("$HOME", QDir::homePath().toUtf8());
326326
QString lookFor = "artwork";
327327
if (line.left(lookFor.length()) == lookFor) {

src/batocera.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ static const QString baseFolder() { return QString("/userdata/roms/"); }
3333

3434
inline const QStringList binaryGamelistElems() {
3535
// using enum GameEntry::Elem; TODO --> std-c++-20 onwards
36-
return QStringList({GameEntry::getTag(GameEntry::Elem::COVER, true),
36+
return QStringList({GameEntry::getTag(GameEntry::Elem::COVER),
3737
GameEntry::getTag(GameEntry::Elem::SCREENSHOT),
3838
GameEntry::getTag(GameEntry::Elem::MARQUEE),
39+
GameEntry::getTag(GameEntry::Elem::WHEEL),
3940
GameEntry::getTag(GameEntry::Elem::FANART),
4041
GameEntry::getTag(GameEntry::Elem::MANUAL),
4142
GameEntry::getTag(GameEntry::Elem::VIDEO), "bezel",
4243
"boxart", "boxback", "cartridge", "magazine", "map",
43-
"mix", "music", "thumbnail", "titleshot"});
44+
"mix", "music", /*"thumbnail", -> COVER */ "titleshot"});
4445
};
4546

4647
void Batocera::setConfig(Settings *config) {
@@ -53,13 +54,13 @@ void Batocera::setConfig(Settings *config) {
5354
}
5455
}
5556

56-
QString Batocera::getInputFolder() { return baseFolder() % config->platform; }
57+
QString Batocera::getInputFolder() { return config->gameListFolder; }
5758

5859
QString Batocera::getGameListFolder() {
5960
return baseFolder() % config->platform;
6061
}
6162

62-
QString Batocera::getMediaFolder() { return baseFolder() % config->platform; }
63+
QString Batocera::getMediaFolder() { return config->gameListFolder; }
6364

6465
QString Batocera::getCoversFolder() { return config->mediaFolder % "/images"; }
6566
QString Batocera::getScreenshotsFolder() { return getCoversFolder(); }
@@ -81,9 +82,11 @@ QStringList Batocera::createEsVariantXml(const GameEntry &entry) {
8182
entry.extraTagNames(GameEntry::Format::BATOCERA, entry);
8283

8384
const QMap<QString, QString> scrapedBinsMap = {
84-
{GameEntry::getTag(GameEntry::Elem::COVER, true), entry.coverFile},
85+
{GameEntry::getTag(GameEntry::Elem::COVER, false), entry.coverFile},
86+
//{"boxart", entry.coverFile},
8587
{GameEntry::getTag(GameEntry::Elem::SCREENSHOT), entry.screenshotFile},
8688
{GameEntry::getTag(GameEntry::Elem::MARQUEE), entry.marqueeFile},
89+
{GameEntry::getTag(GameEntry::Elem::WHEEL), entry.wheelFile},
8790
{GameEntry::getTag(GameEntry::Elem::FANART), entry.fanartFile},
8891
{GameEntry::getTag(GameEntry::Elem::MANUAL), entry.manualFile},
8992
{GameEntry::getTag(GameEntry::Elem::VIDEO), entry.videoFile}};
@@ -96,8 +99,8 @@ QStringList Batocera::createEsVariantXml(const GameEntry &entry) {
9699
if (binaryGamelistElems().contains(el)) {
97100
if (!scrapedBinsMap.keys().contains(el)) {
98101
// write back binaries which are currently not scraped by
99-
// Skyscraper
100-
l.append(elem(el, entry.getEsExtra(el), addEmptyElem(), true));
102+
// Skyscraper, set isPath to false to avoid any changes
103+
l.append(elem(el, entry.getEsExtra(el), addEmptyElem(), false));
101104
} else {
102105
qWarning() << "Twin element" << el
103106
<< "detected in extra-elements for" << entry.path;

src/batocera.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ class Batocera : public EmulationStation {
6969
static QPair<QString, QString> getFilenameParams(QString k) {
7070
QMap<QString, QPair<QString, QString>> cacheResFn = {
7171
// key: "binary type in cache", value: <"-postfix", ".ext">
72-
{"cover", QPair<QString, QString>("boxart", "jpg")},
72+
{"cover", QPair<QString, QString>("thumb", "jpg")},
7373
{"fanart", QPair<QString, QString>("fanart", "jpg")},
7474
{"manual", QPair<QString, QString>("manual", "pdf")},
7575
{"marquee", QPair<QString, QString>("marquee", "jpg")},
7676
{"screenshot", QPair<QString, QString>("image", "jpg")},
77-
// 'texture' not in Bato
7877
{"video", QPair<QString, QString>("video", "mp4")},
79-
{"wheel", QPair<QString, QString>("wheel", "jpg")},
78+
{"wheel", QPair<QString, QString>("wheel", "png")},
79+
// 'texture' not in Bato
8080
};
8181
return cacheResFn[k];
8282
}

src/compositor.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <QDir>
5252
#include <QDomDocument>
5353
#include <QFileInfo>
54+
#include <QMimeDatabase>
5455
#include <QPainter>
5556
#include <QSettings>
5657
#include <QStringBuilder>
@@ -298,6 +299,8 @@ void Compositor::saveAll(GameEntry &game, QString completeBaseName,
298299
fn.prepend("/" % subPath);
299300
createSubfolder = true;
300301
}
302+
QMimeDatabase db;
303+
QRegularExpression reExt("^(.+)(\\.[^\\.]+)$");
301304

302305
for (auto &output : outputs.getLayers()) {
303306
QString filename = fn;
@@ -347,16 +350,24 @@ void Compositor::saveAll(GameEntry &game, QString completeBaseName,
347350
}
348351
}
349352

353+
QByteArray mediaData;
354+
QString fnExt;
350355
if (output.resource == "cover") {
351-
output.setCanvas(QImage::fromData(game.coverData));
356+
mediaData = game.coverData;
352357
} else if (output.resource == "screenshot") {
353-
output.setCanvas(QImage::fromData(game.screenshotData));
358+
mediaData = game.screenshotData;
354359
} else if (output.resource == "wheel") {
355-
output.setCanvas(QImage::fromData(game.wheelData));
360+
mediaData = game.wheelData;
356361
} else if (output.resource == "marquee") {
357-
output.setCanvas(QImage::fromData(game.marqueeData));
362+
mediaData = game.marqueeData;
358363
} else if (output.resource == "texture") {
359-
output.setCanvas(QImage::fromData(game.textureData));
364+
mediaData = game.textureData;
365+
}
366+
367+
output.setCanvas(QImage::fromData(mediaData));
368+
if (isBatocera) {
369+
QMimeType mime = db.mimeTypeForData(mediaData);
370+
fnExt = mime.preferredSuffix();
360371
}
361372

362373
if (output.canvas.isNull() && output.hasLayers()) {
@@ -383,6 +394,11 @@ void Compositor::saveAll(GameEntry &game, QString completeBaseName,
383394
}
384395
}
385396

397+
// check if image format matches extension
398+
if (isBatocera) {
399+
filename = filename.replace(reExt, "\\1." % fnExt);
400+
}
401+
386402
if (output.resType == "cover" && output.save(filename)) {
387403
game.coverFile = filename;
388404
} else if (output.resType == "screenshot" && output.save(filename)) {

src/config.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,3 +369,12 @@ QString Config::lexicallyNormalPath(const QString &pathWithDots) {
369369
std::filesystem::path(pathWithDots.toStdString()).lexically_normal();
370370
return QString(result.string().c_str());
371371
}
372+
373+
QString &Config::expandHomePath(QString &path) {
374+
if (path.startsWith("~/")) {
375+
path.remove(0, 1);
376+
path = QDir::homePath() % path;
377+
// "~account/folder" not supported
378+
}
379+
return path;
380+
}

0 commit comments

Comments
 (0)