Script: Gamelist Cleaner
-
Use at your own Risk!
And another one. I had this for a while and I just updated it to use the usual dialog UI and the option to select a specific system.
I made this before I decided to write my AutoPatchSelector script. Since my main system is a Pi 4 running TwisterOS, I can't use all those fancy Windows Tools. Luckily Skraper runs fine with the help of Mono, and TwisterOS can run some Windows Programs. And there is an older version of a GameList_Editor which is compatible with Wine/Box86. Even though it doesn't support all features of EmulationStation, like marquees for example. It was useful to edit all the Rom Hacks I had around before AutoPatchSelector.
Sadly the GameList_Editor also really messes up the format of the gamelist.xml files, it puts everything in one line. And Skraper also adds some useless stuff to the XML.
This script gets rid of that stuff and restores the format to be readable.
Features:
- It uses the Retropie style UI
- Everything is optional
- Create backup before it does work on the xml
- Do the selected options for all or a singular system
- Removes anything useless added by Skraper
- Can remove userdata (lastplayed/playcount)
- Can remove obsolete entries (Games which don't have a rom anymore)
- Sort the XML by game name (See Issues below)
- Add a padding to game names. It will add a space at the beginning and the end of the name. I use this for my personal theme to make the selector not so cramped.
- (Not optional) Format the XML. It will just indent the elements properly.
- Delete all backups.
Issues:
The sorting option sorts everything. Which can be confusing if you are used to manually edit the files.
A game entry will turn from something like this:<game> <name>A great game</name> <path>./AgreatGame.rom</path> <desc>It is a great game.</desc> <image>./images/AgratGame.png</image> ... </game>
To this:
<game> <desc>It is a great game.</desc> <image>./images/AgratGame.png</image> <name>A great game</name> <path>./AgreatGame.rom</path> ... </game>
See, how the elements inside the game elements are sorted? It's not great but I don't know enough about XML stylesheets, I was happy that it sorted the entries by the game name and didn't really cared much more.
Installation/Usage:
Like the other ones, save it to file with no spaces in the name and sh as ending.
Example:GameListCeaner.sh
Then put it in the RetroPie/retropiemenu directory for easy access.
Credits:
The code for deleting obsolete entries was taken and adapted from @meleu and his Cleaner scriptOh, I haven't really tested the GUI and selection of a single system, so please let me know if you have any issues.
Enjoy.#!/bin/bash #### Script Variables SCRIPTNAME="$(basename "${0}" | sed 's/\(.*\)\..*/\1/')" SCRIPTDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) #### Set directorys ROMDIR="${HOME}/RetroPie/roms" ##### Basic Variables DSHORT="--clear --title ${SCRIPTNAME} --backtitle ${SCRIPTNAME} --no-collapse --colors --stdout" SYSTEM=''; BACKUP=''; CLEAN=''; USER=''; OBSOLTE=; SORT=''; PADDING='' ###### Functions #### Main Menu function do_menu(){ while true; do do_status DOPTIO=(1 "Clean Gamelists" - "\Z1-- -- -- \Zn" 2 "Delete all Backups") DMENU=$(dialog ${DSHORT} --default-item "1" --cancel-label Exit --menu "\nSelect option:" 20 60 18 "${DOPTIO[@]}"); RC=$? case $RC in 1) exit;; 255) exit 1;; esac #0=Ok,1=Cancel,2=Help,3=Extra,4=ItemHelp,255=Escape case $DMENU in 1) do_options;; 2) do_delbak;; esac done } #### Set options function do_options(){ while true; do DOPTIO=(1 "Create Backups" on 2 "Clean Gamelists" on 3 "Remove Userdata (lastplayed/playcount)" off 4 "Remove obsolete entries" off 5 "Sort Gamelist" on 6 "Add Padding to Names" off ) DMENU=$(dialog ${DSHORT} --ok-label "All Systems" --extra-button --extra-label "Select System" --separate-output --checklist "\nSelect options:" 20 60 18 "${DOPTIO[@]}"); RC=$? for choice in $DMENU; do case $choice in 1) BACKUP='true';; 2) CLEAN='true';; 3) USER='true';; 4) OBSOLTE='true';; 5) SORT='true';; 6) PADDING='true';; esac; done case $RC in 0) do_cleaner;; 1) do_menu;; 3) do_system;; 255) exit 1;; esac done } #### Select system function do_system(){ let i=0; W=() while read -r line; do let i=$i+1; W+=($i "$line"); done < <( ls "${ROMDIR}" ) GETSYS=$(dialog ${DSHORT} --menu "\nSelect system:" 20 60 18 "${W[@]}"); RC=$? if [ $? -eq 0 ]; then SYSTEM=$( basename $(ls ${ROMDIR} | sed -n "`echo "$GETSYS p" | sed 's/ //'`") ); fi case $RC in 0) do_cleaner; exit;; 1) do_menu;; 255) exit 1;; esac } #### Clean function do_cleaner(){ if [[ -z $SYSTEM ]]; then GAMELISTS=$(ls ${ROMDIR}/*/gamelist.xml) else GAMELISTS=$(ls ${ROMDIR}/${SYSTEM}/gamelist.xml) fi dialog --no-collapse --infobox "\n Cleaning gamelists... please wait." 8 70 for FILE in $GAMELISTS; do GAMELIST="$(readlink -e "$FILE")" GAMELIST_DIR="$(dirname "$GAMELIST")" #backup if [ "${BACKUP}" == "true" ]; then cp "$FILE" "${GAMELIST_DIR}/gamelist.xml.bak" fi #clean if [ "${CLEAN}" == "true" ]; then xmlstarlet ed -L -d "//*/provider" "$FILE" xmlstarlet ed -L -d "//*/genreid" "$FILE" xmlstarlet ed -L -d "//*/game/@id" "$FILE" xmlstarlet ed -L -d "//*/game/@source" "$FILE" sed -i 's/<name> /<name>/g' "$FILE" sed -i 's/ <\/name>/<\/name>/g' "$FILE" fi #clean user data if [ "${USER}" == "true" ]; then xmlstarlet ed -L -d "//*/lastplayed" "$FILE" xmlstarlet ed -L -d "//*/playcount" "$FILE" fi #clean obsolete entries if [ "${OBSOLTE}" == "true" ]; then while read -r ITEM; do PATH="${ITEM}" if [[ -z $SYSTEM ]]; then [[ "${ITEM}" == ./* ]] && PATH="${GAMELIST_DIR}/$( basename "${ITEM}" )" else [[ "${ITEM}" == ./* ]] && PATH="${ROMDIR}/${SYSTEM}/$( basename "${ITEM}" )" fi PATH="$(echo "$PATH" | sed 's/&/\&/g')" [[ -f "$PATH" ]] && continue xmlstarlet ed -L -d "/gameList/game[path=\"${ITEM}\"]" "$FILE" done < <(xmlstarlet sel -t -v "/gameList/game/path" "$FILE") fi #sort if [ "${SORT}" == "true" ]; then echo '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">' > "$SCRIPTDIR/sort.xsl" echo '<xsl:output indent="yes"/>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:strip-space elements="*"/>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:template match="@*|node()">' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:copy>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:apply-templates select="@*|node()"/>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:copy>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:template>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:template match="/*">' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:copy>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:apply-templates select="@*|node()">' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:sort select="name"/>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:apply-templates>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:copy>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:template>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:template match="game">' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:copy>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:apply-templates select="@*"/>' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:apply-templates select="node()">' >> "$SCRIPTDIR/sort.xsl" echo '<xsl:sort select="name()"/>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:apply-templates>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:copy>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:template>' >> "$SCRIPTDIR/sort.xsl" echo '</xsl:stylesheet>' >> "$SCRIPTDIR/sort.xsl" xmlstarlet tr "$SCRIPTDIR/sort.xsl" "$FILE" >"${GAMELIST_DIR}/sorted.xml" mv -f "${GAMELIST_DIR}/sorted.xml" "${GAMELIST_DIR}/gamelist.xml" fi #indent if [ "${PADDING}" == "true" ]; then sed -i 's/<name>/<name> /g' "$FILE" sed -i 's/<\/name>/ <\/name>/g' "$FILE" fi #format xmlstarlet fo "$FILE" >"${GAMELIST_DIR}/clean.xml" mv -f "${GAMELIST_DIR}/clean.xml" "${GAMELIST_DIR}/gamelist.xml" sed -i '1d' "$FILE" sed -i '1s/^/<?xml version="1.0" encoding="utf-8" standalone="yes"?>\n/' "$FILE" done rm "$SCRIPTDIR/sort.xsl" dialog ${DSHORT} --no-collapse --ok-label "Finish" --msgbox "\n Cleaning done." 8 70 exit } #### Delete Backups function do_delbak(){ while true; do FILES=$(ls ${ROMDIR}/*/gamelist.xml.bak) dialog ${DSHORT} --defaultno --yesno "\nReally delete all gamelist backups?" 8 70; RC=$? case $RC in 0) for FILE in ${FILES}; do dialog --no-collapse --infobox "\n Deleting backups... please wait." 8 70; rm ${FILE}; done; break;; 1) break ;; 255) exit 1 ;; esac done } do_menu
-
Update: I did clean the code a bit
Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.
Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.