RetroPie forum home
    • Recent
    • Tags
    • Popular
    • Home
    • Docs
    • Register
    • Login

    Script: Gamelist Cleaner

    Scheduled Pinned Locked Moved Ideas and Development
    scriptgamelist.xmlcleaninggui
    2 Posts 1 Posters 642 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • E
      EctoOne
      last edited by EctoOne

      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 script

      Oh, 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/&amp;/\&/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
      
      
      1 Reply Last reply Reply Quote 0
      • E
        EctoOne
        last edited by

        Update: I did clean the code a bit

        1 Reply Last reply Reply Quote 0
        • First post
          Last post

        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.