Merge branch 'cooker' of https://github.com/RetroDECK/RetroDECK into cooker

This commit is contained in:
XargonWan 2025-03-26 12:44:30 +09:00
commit e1580ade33
17 changed files with 891 additions and 368 deletions

View file

@ -1,6 +1,6 @@
[ [
{ {
"parserType": "Glob", "parserType": "Manual",
"configTitle": "RetroDECK Steam Sync", "configTitle": "RetroDECK Steam Sync",
"steamDirectory": "${steamdirglobal}", "steamDirectory": "${steamdirglobal}",
"romDirectory": "${romsdirglobal}", "romDirectory": "${romsdirglobal}",
@ -8,11 +8,9 @@
"RetroDECK" "RetroDECK"
], ],
"executableArgs": "", "executableArgs": "",
"executableModifier": "\"${exePath}\"", "executableModifier": "",
"startInDirectory": "", "startInDirectory": "",
"titleModifier": "${fuzzyTitle}", "titleModifier": "${fuzzyTitle}",
"fetchControllerTemplatesButton": null,
"removeControllersButton": null,
"steamInputEnabled": "2", "steamInputEnabled": "2",
"imageProviders": [ "imageProviders": [
"sgdb", "sgdb",
@ -29,7 +27,7 @@
] ]
}, },
"parserInputs": { "parserInputs": {
"glob": "${title}.sh" "manualManifests": "${romsdirglobal}"
}, },
"executable": { "executable": {
"path": "", "path": "",
@ -108,7 +106,6 @@
], ],
"sizes": [], "sizes": [],
"sizesHero": [], "sizesHero": [],
"sizesTall": null,
"sizesIcon": [] "sizesIcon": []
} }
}, },
@ -256,4 +253,4 @@
"parserId": "173908444383456337", "parserId": "173908444383456337",
"version": 25 "version": 25
} }
] ]

View file

@ -2,7 +2,7 @@
compress_game() { compress_game() {
# Function for compressing one or more files to .chd format # Function for compressing one or more files to .chd format
# USAGE: compress_game $format $full_path_to_input_file $system(optional) # USAGE: compress_game $format $full_path_to_input_file $cleanup_choice $system(optional)
local file="$2" local file="$2"
local filename_no_path=$(basename "$file") local filename_no_path=$(basename "$file")
local filename_no_extension="${filename_no_path%.*}" local filename_no_extension="${filename_no_path%.*}"
@ -11,8 +11,9 @@ compress_game() {
local dest_file=$(dirname "$(realpath "$file")")"/""$filename_no_extension" local dest_file=$(dirname "$(realpath "$file")")"/""$filename_no_extension"
if [[ "$1" == "chd" ]]; then if [[ "$1" == "chd" ]]; then
case "$3" in # Check platform-specific compression options case "$4" in # Check platform-specific compression options
"psp" ) "psp" )
log d "Compressing PSP game $source_file into $dest_file"
/app/bin/chdman createdvd --hunksize 2048 -i "$source_file" -o "$dest_file".chd -c zstd /app/bin/chdman createdvd --hunksize 2048 -i "$source_file" -o "$dest_file".chd -c zstd
;; ;;
"ps2" ) "ps2" )
@ -32,7 +33,7 @@ compress_game() {
dolphin-tool convert -f rvz -b 131072 -c zstd -l 5 -i "$source_file" -o "$dest_file.rvz" dolphin-tool convert -f rvz -b 131072 -c zstd -l 5 -i "$source_file" -o "$dest_file.rvz"
fi fi
if [[ $post_compression_cleanup == "true" ]]; then # Remove file(s) if requested if [[ "$3" == "true" ]]; then # Remove file(s) if requested
if [[ -f "${file%.*}.$1" ]]; then if [[ -f "${file%.*}.$1" ]]; then
log i "Performing post-compression file cleanup" log i "Performing post-compression file cleanup"
if [[ "$file" == *".cue" ]]; then if [[ "$file" == *".cue" ]]; then
@ -149,13 +150,13 @@ find_compatible_games() {
compression_format="$1" compression_format="$1"
fi fi
local compressable_systems_list local compressible_systems_list
if [[ "$compression_format" == "all" ]]; then if [[ "$compression_format" == "all" ]]; then
compressable_systems_list=$(jq -r '.compression_targets | to_entries[] | .value[]' "$features") compressible_systems_list=$(jq -r '.compression_targets | to_entries[] | .value[]' "$features")
log d "compressable_systems_list: $compressable_systems_list" log d "compressible_systems_list: $compressible_systems_list"
else else
compressable_systems_list=$(jq -r '.compression_targets["'"$compression_format"'"][]' "$features") compressible_systems_list=$(jq -r '.compression_targets["'"$compression_format"'"][]' "$features")
log d "compressable_systems_list: $compressable_systems_list" log d "compressible_systems_list: $compressible_systems_list"
fi fi
log d "Finding compatible games for compression ($1)" log d "Finding compatible games for compression ($1)"
@ -163,59 +164,51 @@ find_compatible_games() {
while IFS= read -r system; do while IFS= read -r system; do
log d "Checking system: $system" log d "Checking system: $system"
local compression_candidates if [[ -d "$roms_folder/$system" ]]; then
compression_candidates=$(find "$roms_folder/$system" -type f -not -iname "*.txt") local compression_candidates
if [[ -n "$compression_candidates" ]]; then compression_candidates=$(find "$roms_folder/$system" -type f -not -iname "*.txt")
while IFS= read -r game; do if [[ -n "$compression_candidates" ]]; then
log d "Checking game: $game" while IFS= read -r game; do
local compatible_compression_format log d "Checking game: $game"
compatible_compression_format=$(find_compatible_compression_format "$game") local compatible_compression_format
local file_ext="${game##*.}" compatible_compression_format=$(find_compatible_compression_format "$game")
case "$compression_format" in if [[ -f "${game%.*}.$compatible_compression_format" ]]; then # If a compressed version of this game already exists
"chd") log d "Skipping $game because a $compatible_compression_format version already exists."
if [[ "$compatible_compression_format" == "chd" ]]; then continue
if [[ "$file_ext" == "chd" ]]; then fi
log d "Skipping $game because it is already a CHD file." local file_ext="${game##*.}"
elif [[ ! -f "${game%.*}.chd" ]]; then case "$compression_format" in
"chd")
if [[ "$compatible_compression_format" == "chd" ]]; then
log d "Game $game is compatible with CHD compression" log d "Game $game is compatible with CHD compression"
echo "${game}^chd" >> "$output_file" echo "${game}^chd" >> "$output_file"
fi fi
fi ;;
;; "zip")
"zip") if [[ "$compatible_compression_format" == "zip" ]]; then
if [[ "$compatible_compression_format" == "zip" ]]; then
if [[ "$file_ext" == "zip" ]]; then
log d "Skipping $game because it is already a ZIP file."
elif [[ ! -f "${game%.*}.zip" ]]; then
log d "Game $game is compatible with ZIP compression" log d "Game $game is compatible with ZIP compression"
echo "${game}^zip" >> "$output_file" echo "${game}^zip" >> "$output_file"
fi fi
fi ;;
;; "rvz")
"rvz") if [[ "$compatible_compression_format" == "rvz" ]]; then
if [[ "$compatible_compression_format" == "rvz" ]]; then
if [[ "$file_ext" == "rvz" ]]; then
log d "Skipping $game because it is already an RVZ file."
elif [[ ! -f "${game%.*}.rvz" ]]; then
log d "Game $game is compatible with RVZ compression" log d "Game $game is compatible with RVZ compression"
echo "${game}^rvz" >> "$output_file" echo "${game}^rvz" >> "$output_file"
fi fi
fi ;;
;; "all")
"all") if [[ "$compatible_compression_format" != "none" ]]; then
if [[ "$compatible_compression_format" != "none" ]]; then
if [[ "$file_ext" == "$compatible_compression_format" ]]; then
log d "Skipping $game because it is already in $compatible_compression_format format."
else
log d "Game $game is compatible with $compatible_compression_format compression" log d "Game $game is compatible with $compatible_compression_format compression"
echo "${game}^${compatible_compression_format}" >> "$output_file" echo "${game}^${compatible_compression_format}" >> "$output_file"
fi fi
fi ;;
;; esac
esac done < <(printf '%s\n' "$compression_candidates")
done < <(printf '%s\n' "$compression_candidates") fi
else
log d "Rom folder for $system is missing, skipping"
fi fi
done < <(printf '%s\n' "$compressable_systems_list") done < <(printf '%s\n' "$compressible_systems_list")
log d "Compatible games have been written to $output_file" log d "Compatible games have been written to $output_file"
cat "$output_file" cat "$output_file"
@ -226,23 +219,32 @@ cli_compress_single_game() {
# USAGE: cli_compress_single_game $full_file_path # USAGE: cli_compress_single_game $full_file_path
local file=$(realpath "$1") local file=$(realpath "$1")
read -p "Do you want to have the original file removed after compression is complete? Please answer y/n and press Enter: " post_compression_cleanup read -p "Do you want to have the original file removed after compression is complete? Please answer y/n and press Enter: " post_compression_cleanup
read -p "RetroDECK will now attempt to compress your selected game. Press Enter key to continue..." if [[ "$post_compression_cleanup" == "y" || "$post_compression_cleanup" == "n" ]]; then
if [[ ! -z "$file" ]]; then read -p "RetroDECK will now attempt to compress your selected game. Press Enter key to continue..."
if [[ -f "$file" ]]; then if [[ ! -z "$file" ]]; then
local system=$(echo "$file" | grep -oE "$roms_folder/[^/]+" | grep -oE "[^/]+$") if [[ -f "$file" ]]; then
local compatible_compression_format=$(find_compatible_compression_format "$file") local system=$(echo "$file" | grep -oE "$roms_folder/[^/]+" | grep -oE "[^/]+$")
if [[ ! $compatible_compression_format == "none" ]]; then local compatible_compression_format=$(find_compatible_compression_format "$file")
log i "$(basename "$file") can be compressed to $compatible_compression_format" if [[ ! $compatible_compression_format == "none" ]]; then
compress_game "$compatible_compression_format" "$file" "$system" log i "$(basename "$file") can be compressed to $compatible_compression_format"
if [[ "$post_compression_cleanup" == "y" ]]; then
post_compression_cleanup="true"
else
post_compression_cleanup="false"
fi
compress_game "$compatible_compression_format" "$file" "$post_compression_cleanup" "$system"
else
log w "$(basename "$file") does not have any compatible compression formats."
fi
else else
log w "$(basename "$file") does not have any compatible compression formats." log w "File not found, please specify the full path to the file to be compressed."
fi fi
else else
log w "File not found, please specify the full path to the file to be compressed." log i "Please use this command format \"--compress-one <path to file to compress>\""
fi fi
else else
log i "Please use this command format \"--compress-one <path to file to compress>\"" log i "The response for post-compression file cleanup was not correct. Please try again."
fi fi
} }
cli_compress_all_games() { cli_compress_all_games() {
@ -257,31 +259,39 @@ cli_compress_all_games() {
local compressable_game="" local compressable_game=""
local all_compressable_games=() local all_compressable_games=()
if [[ $compression_format == "all" ]]; then if [[ $compression_format == "all" ]]; then
local compressable_systems_list=$(jq -r '.compression_targets | to_entries[] | .value[]' $features) local compressible_systems_list=$(jq -r '.compression_targets | to_entries[] | .value[]' $features)
else else
local compressable_systems_list=$(jq -r '.compression_targets["'"$compression_format"'"][]' $features) local compressible_systems_list=$(jq -r '.compression_targets["'"$compression_format"'"][]' $features)
fi fi
read -p "Do you want to have the original files removed after compression is complete? Please answer y/n and press Enter: " post_compression_cleanup read -p "Do you want to have the original files removed after compression is complete? Please answer y/n and press Enter: " post_compression_cleanup
read -p "RetroDECK will now attempt to compress all compatible games. Press Enter key to continue..." if [[ "$post_compression_cleanup" == "y" || "$post_compression_cleanup" == "n" ]]; then
read -p "RetroDECK will now attempt to compress all compatible games. Press Enter key to continue..."
while IFS= read -r system # Find and validate all games that are able to be compressed with this compression type if [[ "$post_compression_cleanup" == "y" ]]; then
do post_compression_cleanup="true"
local compression_candidates=$(find "$roms_folder/$system" -type f -not -iname "*.txt")
if [[ ! -z "$compression_candidates" ]]; then
log i "Checking files for $system"
while IFS= read -r file
do
local compatible_compression_format=$(find_compatible_compression_format "$file")
if [[ ! "$compatible_compression_format" == "none" ]]; then
log i "$(basename "$file") can be compressed to $compatible_compression_format"
compress_game "$compatible_compression_format" "$file" "$system"
else
log w "No compatible compression format found for $(basename "$file")"
fi
done < <(printf '%s\n' "$compression_candidates")
else else
log w "No compatible files found for compression in $system" post_compression_cleanup="false"
fi fi
done < <(printf '%s\n' "$compressable_systems_list") while IFS= read -r system # Find and validate all games that are able to be compressed with this compression type
do
local compression_candidates=$(find "$roms_folder/$system" -type f -not -iname "*.txt")
if [[ ! -z "$compression_candidates" ]]; then
log i "Checking files for $system"
while IFS= read -r file
do
local compatible_compression_format=$(find_compatible_compression_format "$file")
if [[ ! "$compatible_compression_format" == "none" ]]; then
log i "$(basename "$file") can be compressed to $compatible_compression_format"
compress_game "$compatible_compression_format" "$file" "$post_compression_cleanup" "$system"
else
log w "No compatible compression format found for $(basename "$file")"
fi
done < <(printf '%s\n' "$compression_candidates")
else
log w "No compatible files found for compression in $system"
fi
done < <(printf '%s\n' "$compressible_systems_list")
else
log i "The response for post-compression file cleanup was not correct. Please try again."
fi
} }

View file

@ -23,14 +23,14 @@ find_empty_rom_folders() {
if [[ $count -eq 0 ]]; then if [[ $count -eq 0 ]]; then
# Directory is empty # Directory is empty
empty_rom_folders_list=("${empty_rom_folders_list[@]}" "false" "$(realpath $dir)") empty_rom_folders_list=("${empty_rom_folders_list[@]}" "false" "$(realpath "$dir")")
all_empty_folders=("${all_empty_folders[@]}" "$(realpath $dir)") all_empty_folders=("${all_empty_folders[@]}" "$(realpath "$dir")")
echo "$(realpath $dir)" >> "$godot_empty_roms_folders" # Godot data transfer temp file echo "$(realpath "$dir")" >> "$godot_empty_roms_folders" # Godot data transfer temp file
elif [[ $count -eq 1 ]] && [[ "$(basename "${files[0]}")" == "systeminfo.txt" ]]; then elif [[ $count -eq 1 ]] && [[ "$(basename "${files[0]}")" == "systeminfo.txt" ]]; then
# Directory contains only systeminfo.txt # Directory contains only systeminfo.txt
empty_rom_folders_list=("${empty_rom_folders_list[@]}" "false" "$(realpath $dir)") empty_rom_folders_list=("${empty_rom_folders_list[@]}" "false" "$(realpath "$dir")")
all_empty_folders=("${all_empty_folders[@]}" "$(realpath $dir)") all_empty_folders=("${all_empty_folders[@]}" "$(realpath "$dir")")
echo "$(realpath $dir)" >> "$godot_empty_roms_folders" # Godot data transfer temp file echo "$(realpath "$dir")" >> "$godot_empty_roms_folders" # Godot data transfer temp file
elif [[ $count -eq 2 ]] && [[ "$files" =~ "systeminfo.txt" ]]; then elif [[ $count -eq 2 ]] && [[ "$files" =~ "systeminfo.txt" ]]; then
contains_helper_file="false" contains_helper_file="false"
for helper_file in "${all_helper_files[@]}" # Compare helper file list to dir file list for helper_file in "${all_helper_files[@]}" # Compare helper file list to dir file list
@ -42,9 +42,9 @@ find_empty_rom_folders() {
done done
if [[ "$contains_helper_file" == "true" ]]; then if [[ "$contains_helper_file" == "true" ]]; then
# Directory contains only systeminfo.txt and a helper file # Directory contains only systeminfo.txt and a helper file
empty_rom_folders_list=("${empty_rom_folders_list[@]}" "false" "$(realpath $dir)") empty_rom_folders_list=("${empty_rom_folders_list[@]}" "false" "$(realpath "$dir")")
all_empty_folders=("${all_empty_folders[@]}" "$(realpath $dir)") all_empty_folders=("${all_empty_folders[@]}" "$(realpath "$dir")")
echo "$(realpath $dir)" >> "$godot_empty_roms_folders" # Godot data transfer temp file echo "$(realpath "$dir")" >> "$godot_empty_roms_folders" # Godot data transfer temp file
fi fi
fi fi
done done
@ -61,5 +61,4 @@ configurator_check_multifile_game_structure() {
else else
configurator_generic_dialog "RetroDECK Configurator - Verify Multi-file Structure" "No incorrect multi-file game folder structures found." configurator_generic_dialog "RetroDECK Configurator - Verify Multi-file Structure" "No incorrect multi-file game folder structures found."
fi fi
configurator_welcome_dialog
} }

View file

@ -92,11 +92,11 @@ configurator_move_folder_dialog() {
if [[ ! "$rd_dir_name" == "rdhome" ]]; then # If a sub-folder is being moved, find it's path without the source_root. So /home/deck/retrodeck/roms becomes retrodeck/roms if [[ ! "$rd_dir_name" == "rdhome" ]]; then # If a sub-folder is being moved, find it's path without the source_root. So /home/deck/retrodeck/roms becomes retrodeck/roms
local rd_dir_path="$(echo "$dir_to_move" | sed "s/.*\(retrodeck\/.*\)/\1/; s/\/$//")" local rd_dir_path="$(echo "$dir_to_move" | sed "s/.*\(retrodeck\/.*\)/\1/; s/\/$//")"
else # Otherwise just set the retrodeck root folder else # Otherwise just set the retrodeck root folder
local rd_dir_path="$(basename $dir_to_move)" local rd_dir_path="$(basename "$dir_to_move")"
fi fi
if [[ -d "$dir_to_move" ]]; then # If the directory selected to move already exists at the expected location pulled from retrodeck.cfg if [[ -d "$dir_to_move" ]]; then # If the directory selected to move already exists at the expected location pulled from retrodeck.cfg
choice=$(configurator_destination_choice_dialog "RetroDECK Data" "Please choose a destination for the $(basename $dir_to_move) folder.") choice=$(configurator_destination_choice_dialog "RetroDECK Data" "Please choose a destination for the $(basename "$dir_to_move") folder.")
case $choice in case $choice in
"Internal Storage" | "SD Card" | "Custom Location" ) # If the user picks a location "Internal Storage" | "SD Card" | "Custom Location" ) # If the user picks a location
@ -105,17 +105,17 @@ configurator_move_folder_dialog() {
elif [[ "$choice" == "SD Card" ]]; then # If the user wants to move the folder to the predefined SD card location, set the target as sdcard from retrodeck.cfg elif [[ "$choice" == "SD Card" ]]; then # If the user wants to move the folder to the predefined SD card location, set the target as sdcard from retrodeck.cfg
local dest_root="$sdcard" local dest_root="$sdcard"
else else
configurator_generic_dialog "RetroDECK Configurator - Move Folder" "Select the parent folder you would like to store the $(basename $dir_to_move) folder in." configurator_generic_dialog "RetroDECK Configurator - Move Folder" "Select the parent folder you would like to store the $(basename "$dir_to_move") folder in."
local dest_root=$(directory_browse "RetroDECK directory location") # Set the destination root as the selected custom location local dest_root=$(directory_browse "RetroDECK directory location") # Set the destination root as the selected custom location
fi fi
if [[ (! -z "$dest_root") && ( -w "$dest_root") ]]; then # If user picked a destination and it is writable if [[ (! -z "$dest_root") && ( -w "$dest_root") ]]; then # If user picked a destination and it is writable
if [[ (-d "$dest_root/$rd_dir_path") && (! -L "$dest_root/$rd_dir_path") && (! $rd_dir_name == "rdhome") ]] || [[ "$(realpath $dir_to_move)" == "$dest_root/$rd_dir_path" ]]; then # If the user is trying to move the folder to where it already is (excluding symlinks that will be unlinked) if [[ (-d "$dest_root/$rd_dir_path") && (! -L "$dest_root/$rd_dir_path") && (! $rd_dir_name == "rdhome") ]] || [[ "$(realpath "$dir_to_move")" == "$dest_root/$rd_dir_path" ]]; then # If the user is trying to move the folder to where it already is (excluding symlinks that will be unlinked)
configurator_generic_dialog "RetroDECK Configurator - Move Folder" "The $(basename $dir_to_move) folder is already at that location, please pick a new one." configurator_generic_dialog "RetroDECK Configurator - Move Folder" "The $(basename "$dir_to_move") folder is already at that location, please pick a new one."
configurator_move_folder_dialog "$rd_dir_name" configurator_move_folder_dialog "$rd_dir_name"
else else
if [[ $(verify_space "$(echo $dir_to_move | sed 's/\/$//')" "$dest_root") ]]; then # Make sure there is enough space at the destination if [[ $(verify_space "$(echo $dir_to_move | sed 's/\/$//')" "$dest_root") ]]; then # Make sure there is enough space at the destination
configurator_generic_dialog "RetroDECK Configurator - Move Folder" "Moving $(basename $dir_to_move) folder to $choice" configurator_generic_dialog "RetroDECK Configurator - Move Folder" "Moving $(basename "$dir_to_move") folder to $choice"
unlink "$dest_root/$rd_dir_path" # In case there is already a symlink at the picked destination unlink "$dest_root/$rd_dir_path" # In case there is already a symlink at the picked destination
move "$dir_to_move" "$dest_root/$rd_dir_path" move "$dir_to_move" "$dest_root/$rd_dir_path"
if [[ -d "$dest_root/$rd_dir_path" ]]; then # If the move succeeded if [[ -d "$dest_root/$rd_dir_path" ]]; then # If the move succeeded
@ -128,7 +128,7 @@ configurator_move_folder_dialog() {
if [[ -z $(ls -1 "$source_root/retrodeck") ]]; then # Cleanup empty old_path/retrodeck folder if it was left behind if [[ -z $(ls -1 "$source_root/retrodeck") ]]; then # Cleanup empty old_path/retrodeck folder if it was left behind
rmdir "$source_root/retrodeck" rmdir "$source_root/retrodeck"
fi fi
configurator_process_complete_dialog "moving the RetroDECK data directory to internal storage" configurator_generic_dialog "RetroDECK Configurator - Move Folder" "moving the RetroDECK data directory to internal storage"
else else
configurator_generic_dialog "RetroDECK Configurator - Move Folder" "The moving process was not completed, please try again." configurator_generic_dialog "RetroDECK Configurator - Move Folder" "The moving process was not completed, please try again."
fi fi
@ -150,12 +150,12 @@ configurator_move_folder_dialog() {
esac esac
else # The folder to move was not found at the path pulled from retrodeck.cfg and it needs to be reconfigured manually. else # The folder to move was not found at the path pulled from retrodeck.cfg and it needs to be reconfigured manually.
configurator_generic_dialog "RetroDECK Configurator - Move Folder" "The $(basename $dir_to_move) folder was not found at the expected location.\n\nThis may have happened if the folder was moved manually.\n\nPlease select the current location of the folder." configurator_generic_dialog "RetroDECK Configurator - Move Folder" "The $(basename "$dir_to_move") folder was not found at the expected location.\n\nThis may have happened if the folder was moved manually.\n\nPlease select the current location of the folder."
dir_to_move=$(directory_browse "RetroDECK $(basename $dir_to_move) directory location") dir_to_move=$(directory_browse "RetroDECK $(basename "$dir_to_move") directory location")
declare -g "$rd_dir_name=$dir_to_move" declare -g "$rd_dir_name=$dir_to_move"
prepare_component "postmove" "all" prepare_component "postmove" "all"
conf_write conf_write
configurator_generic_dialog "RetroDECK Configurator - Move Folder" "RetroDECK $(basename $dir_to_move) folder now configured at\n$dir_to_move." configurator_generic_dialog "RetroDECK Configurator - Move Folder" "RetroDECK $(basename "$dir_to_move") folder now configured at\n$dir_to_move."
configurator_move_folder_dialog "$rd_dir_name" configurator_move_folder_dialog "$rd_dir_name"
fi fi
} }

View file

@ -8,6 +8,11 @@
: "${logging_level:=info}" # Initializing the log level variable if not already valued, this will be actually red later from the config file : "${logging_level:=info}" # Initializing the log level variable if not already valued, this will be actually red later from the config file
rd_logs_folder="/var/config/retrodeck/logs" # Static location to write all RetroDECK-related logs rd_logs_folder="/var/config/retrodeck/logs" # Static location to write all RetroDECK-related logs
if [ -h "$rd_logs_folder" ]; then # Check if internal logging folder is already a symlink
if [ ! -e "$rd_logs_folder" ]; then # Check if internal logging folder symlink is broken
unlink "$rd_logs_folder" # Remove broken symlink so the folder is recreated when sourcing logger.sh
fi
fi
source /app/libexec/logger.sh source /app/libexec/logger.sh
rotate_logs rotate_logs
@ -47,6 +52,7 @@ source /app/libexec/prepare_component.sh
source /app/libexec/presets.sh source /app/libexec/presets.sh
source /app/libexec/configurator_functions.sh source /app/libexec/configurator_functions.sh
source /app/libexec/run_game.sh source /app/libexec/run_game.sh
source /app/libexec/steam_sync.sh
# Static variables # Static variables
rd_conf="/var/config/retrodeck/retrodeck.cfg" # RetroDECK config file path rd_conf="/var/config/retrodeck/retrodeck.cfg" # RetroDECK config file path
@ -236,14 +242,13 @@ else
# Verify rdhome is where it is supposed to be. # Verify rdhome is where it is supposed to be.
if [[ ! -d "$rdhome" ]]; then if [[ ! -d "$rdhome" ]]; then
prev_home_path="$rdhome"
configurator_generic_dialog "RetroDECK Setup" "The RetroDECK data folder was not found in the expected location.\nThis may happen when SteamOS is updated.\n\nPlease browse to the current location of the \"retrodeck\" folder." configurator_generic_dialog "RetroDECK Setup" "The RetroDECK data folder was not found in the expected location.\nThis may happen when SteamOS is updated.\n\nPlease browse to the current location of the \"retrodeck\" folder."
new_home_path=$(directory_browse "RetroDECK folder location") new_home_path=$(directory_browse "RetroDECK folder location")
set_setting_value $rd_conf "rdhome" "$new_home_path" retrodeck "paths" set_setting_value $rd_conf "rdhome" "$new_home_path" retrodeck "paths"
conf_read conf_read
#tmplog_merger # This function is tempry(?) removed #tmplog_merger # This function is tempry(?) removed
prepare_component "retrodeck" "postmove" prepare_component "postmove" "retrodeck"
prepare_component "all" "postmove" prepare_component "postmove" "all"
conf_write conf_write
fi fi
@ -252,9 +257,11 @@ else
multi_user_data_folder="$rdhome/multi-user-data" # The default location of multi-user environment profiles multi_user_data_folder="$rdhome/multi-user-data" # The default location of multi-user environment profiles
fi fi
logs_folder="$rdhome/logs" # The path of the logs folder, here we collect all the logs # Steam ROM Manager user files and paths
steamsync_folder="$rdhome/.sync" # Folder containing all the steam sync launchers for SRM
steamsync_folder_tmp="$rdhome/.sync-tmp" # Temp folder containing all the steam sync launchers for SRM steamsync_folder="$rdhome/.sync" # Folder containing favorites manifest for SRM
backups_folder="$rdhome/backups" # Folder containing all the RetroDECK backups retrodeck_favorites_file="$steamsync_folder/retrodeck_favorites.json" # The current SRM manifest of all games that have been favorited in ES-DE
srm_log="$logs_folder/srm_log.log" # Log file for capturing the output of the most recent SRM run, for debugging purposes
retrodeck_removed_favorites="$steamsync_folder/retrodeck_removed_favorites.json" # Temporary manifest of any games that were unfavorited in ES-DE and should be removed from Steam
export GLOBAL_SOURCED=true export GLOBAL_SOURCED=true

View file

@ -273,8 +273,8 @@ dir_prep() {
# Call me with: # Call me with:
# dir prep "real dir" "symlink location" # dir prep "real dir" "symlink location"
real="$(realpath -s $1)" real="$(realpath -s "$1")"
symlink="$(realpath -s $2)" symlink="$(realpath -s "$2")"
log d "Preparing directory $symlink in $real" log d "Preparing directory $symlink in $real"
@ -354,8 +354,288 @@ update_vita3k_firmware() {
} }
backup_retrodeck_userdata() { backup_retrodeck_userdata() {
# This function can compress one or more RetroDECK userdata folders into a single zip file for backup.
# The function can do a "complete" backup of all userdata including ROMs and ES-DE media, so can end up being very large.
# The function can also do a "core" backup of all the very important userdata files (like saves, states and gamelists) or a "custom" backup of only specified paths
# The function can take both folder names as defined in retrodeck.cfg or full paths as arguments for folders to backup
# It will also validate that all the provided paths exist and that there is enough free space to perform the backup before actually proceeding.
# It will also rotate backups so that there are only 3 maximum of each type (standard or custom)
# USAGE: backup_retrodeck_userdata complete
# backup_retrodeck_userdata core
# backup_retrodeck_userdata custom saves_folder states_folder /some/other/path
create_dir "$backups_folder" create_dir "$backups_folder"
zip -rq9 "$backups_folder/$(date +"%0m%0d")_retrodeck_userdata.zip" "$saves_folder" "$states_folder" "$bios_folder" "$media_folder" "$themes_folder" "$rdhome/ES-DE/collections" "$rdhome/ES-DE/gamelists" "$logs_folder" "$screenshots_folder" "$mods_folder" "$texture_packs_folder" "$borders_folder" > $logs_folder/$(date +"%0m%0d")_backup_log.log
backup_date=$(date +"%0m%0d_%H%M")
backup_log_file="$logs_folder/${backup_date}_${backup_type}_backup_log.log"
# Check if first argument is the type
if [[ "$1" == "complete" || "$1" == "core" || "$1" == "custom" ]]; then
backup_type="$1"
shift # Remove the first argument
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "No valid backup option chosen. Valid options are <standard> and <custom>."
fi
log e "No valid backup option chosen. Valid options are <standard> and <custom>."
exit 1
fi
zip_file="$backups_folder/retrodeck_${backup_date}_${backup_type}.zip"
# Initialize paths arrays
paths_to_backup=()
declare -A config_paths # Requires an associative (dictionary) array to work
# Build array of folder names and real paths from retrodeck.cfg
while read -r config_line; do
local current_setting_name=$(get_setting_name "$config_line" "retrodeck")
if [[ ! $current_setting_name =~ (rdhome|sdcard|backups_folder) ]]; then # Ignore these locations
local current_setting_value=$(get_setting_value "$rd_conf" "$current_setting_name" "retrodeck" "paths")
config_paths["$current_setting_name"]="$current_setting_value"
fi
done < <(grep -v '^\s*$' $rd_conf | awk '/^\[paths\]/{f=1;next} /^\[/{f=0} f')
# Determine which paths to backup
if [[ "$backup_type" == "complete" ]]; then
for folder_name in "${!config_paths[@]}"; do
path_value="${config_paths[$folder_name]}"
if [[ -e "$path_value" ]]; then
paths_to_backup+=("$path_value")
log i "Adding to backup: $folder_name = $path_value"
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The $folder_name was not found at its expected location, $path_value\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: $folder_name = $path_value"
fi
done
# Add static paths not defined in retrodeck.cfg
if [[ -e "$rdhome/ES-DE/collections" ]]; then
paths_to_backup+=("$rdhome/ES-DE/collections")
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The ES-DE collections folder was not found at its expected location, $rdhome/ES-DE/collections\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: ES-DE/collections = $rdhome/ES-DE/collections"
fi
if [[ -e "$rdhome/ES-DE/gamelists" ]]; then
paths_to_backup+=("$rdhome/ES-DE/gamelists")
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The ES-DE gamelists folder was not found at its expected location, $rdhome/ES-DE/gamelists\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: ES-DE/gamelists = $rdhome/ES-DE/gamelists"
fi
if [[ -e "$rdhome/ES-DE/custom_systems" ]]; then
paths_to_backup+=("$rdhome/ES-DE/custom_systems")
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The ES-DE custom_systems folder was not found at its expected location, $rdhome/ES-DE/custom_systems\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: ES-DE/custom_systems = $rdhome/ES-DE/custom_systems"
fi
# Check if we found any valid paths
if [[ ${#paths_to_backup[@]} -eq 0 ]]; then
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "No valid userdata folders were found.\nSomething may be wrong with your RetroDECK installation."
fi
log e "Error: No valid paths found in config file"
return 1
fi
elif [[ "$backup_type" == "core" ]]; then
for folder_name in "${!config_paths[@]}"; do
if [[ $folder_name =~ (saves_folder|states_folder|logs_folder) ]]; then # Only include these paths
path_value="${config_paths[$folder_name]}"
if [[ -e "$path_value" ]]; then
paths_to_backup+=("$path_value")
log i "Adding to backup: $folder_name = $path_value"
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The $folder_name was not found at its expected location, $path_value\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: $folder_name = $path_value"
fi
fi
done
# Add static paths not defined in retrodeck.cfg
if [[ -e "$rdhome/ES-DE/collections" ]]; then
paths_to_backup+=("$rdhome/ES-DE/collections")
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The ES-DE collections folder was not found at its expected location, $rdhome/ES-DE/collections\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: ES-DE/collections = $rdhome/ES-DE/collections"
fi
if [[ -e "$rdhome/ES-DE/gamelists" ]]; then
paths_to_backup+=("$rdhome/ES-DE/gamelists")
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The ES-DE gamelists folder was not found at its expected location, $rdhome/ES-DE/gamelists\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: ES-DE/gamelists = $rdhome/ES-DE/gamelists"
fi
if [[ -e "$rdhome/ES-DE/custom_systems" ]]; then
paths_to_backup+=("$rdhome/ES-DE/custom_systems")
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The ES-DE custom_systems folder was not found at its expected location, $rdhome/ES-DE/custom_systems\nSomething may be wrong with your RetroDECK installation."
fi
log i "Warning: Path does not exist: ES-DE/custom_systems = $rdhome/ES-DE/custom_systems"
fi
# Check if we found any valid paths
if [[ ${#paths_to_backup[@]} -eq 0 ]]; then
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "No valid userdata folders were found.\nSomething may be wrong with your RetroDECK installation."
fi
log e "Error: No valid paths found in config file"
return 1
fi
elif [[ "$backup_type" == "custom" ]]; then
if [[ "$#" -eq 0 ]]; then # Check if any paths were provided in the arguments
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "No valid backup locations were specified. Please try again."
fi
log e "Error: No paths specified for custom backup"
return 1
fi
# Process each argument - it could be a variable name or a direct path
for arg in "$@"; do
# Check if argument is a variable name in the config
if [[ -n "${config_paths[$arg]}" ]]; then
path_value="${config_paths[$arg]}"
if [[ -e "$path_value" ]]; then
paths_to_backup+=("$path_value")
log i "Added to backup: $arg = $path_value"
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The $arg was not found at its expected location, $path_value.\nSomething may be wrong with your RetroDECK installation."
fi
log e "Error: Path from variable '$arg' does not exist: $path_value"
return 1
fi
# Otherwise treat it as a direct path
elif [[ -e "$arg" ]]; then
paths_to_backup+=("$arg")
log i "Added to backup: $arg"
else
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "The path $arg was not found at its expected location.\nPlease check the path and try again."
fi
log e "Error: '$arg' is neither a valid variable name nor an existing path"
return 1
fi
done
fi
# Calculate total size of selected paths
log i "Calculating size of backup data..."
total_size=0
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then # Show progress dialog if running Zenity Configurator
total_size_file=$(mktemp) # Create temp file for Zenity subshell data extraction
(
for path in "${paths_to_backup[@]}"; do
if [[ -e "$path" ]]; then
log d "Checking size of path $path"
path_size=$(du -sk "$path" 2>/dev/null | cut -f1) # Get size in KB
path_size=$((path_size * 1024)) # Convert to bytes for calculation
total_size=$((total_size + path_size))
echo "$total_size" > $total_size_file
fi
done
) |
rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --pulsate --auto-close \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK Configurator Utility - Userdata Backup" \
--text="Verifying there is enough free space for the backup, please wait..."
total_size=$(cat "$total_size_file")
rm "$total_size_file" # Clean up temp file
else # If running in CLI
for path in "${paths_to_backup[@]}"; do
if [[ -e "$path" ]]; then
log d "Checking size of path $path"
path_size=$(du -sk "$path" 2>/dev/null | cut -f1) # Get size in KB
path_size=$((path_size * 1024)) # Convert to bytes for calculation
total_size=$((total_size + path_size))
fi
done
fi
# Get available space at destination
available_space=$(df -B1 "$backups_folder" | awk 'NR==2 {print $4}')
# Log sizes for reference
log i "Total size of backup data: $(numfmt --to=iec-i --suffix=B $total_size)"
log i "Available space at destination: $(numfmt --to=iec-i --suffix=B $available_space)"
# Check if we have enough space (using uncompressed size as a conservative estimate)
if [[ "$available_space" -lt "$total_size" ]]; then
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
configurator_generic_dialog "RetroDECK Userdata Backup" "There is not enough free space to perform this backup.\n\nYou need at least $(numfmt --to=iec-i --suffix=B $total_size),\nplease free up some space and try again."
fi
log e "Error: Not enough space to perform backup. Need at least $(numfmt --to=iec-i --suffix=B $total_size)"
return 1
fi
log i "Starting backup process..."
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then # Show progress dialog if running Zenity Configurator
(
# Create zip with selected paths
if zip -rq9 "$zip_file" "${paths_to_backup[@]}" >> "$backup_log_file" 2>&1; then
# Rotate backups for the specific type
cd "$backups_folder" || return 1
ls -t *_${backup_type}.zip | tail -n +4 | xargs -r rm
final_size=$(du -h "$zip_file" | cut -f1)
configurator_generic_dialog "RetroDECK Userdata Backup" "The backup to $zip_file was successful, final size is $final_size.\n\nThe backups have been rotated, keeping the last 3 of the $backup_type backup type."
log i "Backup completed successfully: $zip_file (Size: $final_size)"
log i "Older backups rotated, keeping latest 3 of type $backup_type"
if [[ ! -s "$backup_log_file" ]]; then # If the backup log file is empty, meaning zip threw no errors
rm -f "$backup_log_file"
fi
else
configurator_generic_dialog "RetroDECK Userdata Backup" "Something went wrong with the backup process. Please check the log $backup_log_file for more information."
log i "Error: Backup failed"
return 1
fi
) |
rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --pulsate --auto-close \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK Configurator Utility - Userdata Backup" \
--text="Compressing files into backup, please wait..."
else
if zip -rq9 "$zip_file" "${paths_to_backup[@]}" >> "$backup_log_file" 2>&1; then
# Rotate backups for the specific type
cd "$backups_folder" || return 1
ls -t *_${backup_type}.zip | tail -n +4 | xargs -r rm
final_size=$(du -h "$zip_file" | cut -f1)
log i "Backup completed successfully: $zip_file (Size: $final_size)"
log i "Older backups rotated, keeping latest 3 of type $backup_type"
if [[ ! -s "$backup_log_file" ]]; then # If the backup log file is empty, meaning zip threw no errors
rm -f "$backup_log_file"
fi
else
log i "Error: Backup failed"
return 1
fi
fi
} }
make_name_pretty() { make_name_pretty() {
@ -962,22 +1242,8 @@ quit_retrodeck() {
pkill -f "es-de" pkill -f "es-de"
# if steam sync is on do the magic # if steam sync is on do the magic
if [[ $(get_setting_value "$rd_conf" "steam_sync" retrodeck "options") == "true" ]]; then if [[ $(get_setting_value "$rd_conf" "steam_sync" "retrodeck" "options") == "true" ]]; then
( steam_sync
source /app/libexec/steam_sync.sh
add_to_steam "$(ls "$rdhome/ES-DE/gamelists/")"
) |
rd_zenity --progress \
--title="Syncing with Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="<span foreground='$purple'><b>\t\t\t\tSyncing favorite games with Steam</b></span>\n\n<b>NOTE: </b>This operation may take some time depending on the size of your library.\nFeel free to leave this in the background and switch to another application.\n\n" \
--percentage=25 \
--pulsate \
--width=500 \
--height=150 \
--auto-close \
--auto-kill \
--no-cancel
fi fi
log i "Shutting down RetroDECK's framework" log i "Shutting down RetroDECK's framework"
pkill -f "retrodeck" pkill -f "retrodeck"
@ -1128,3 +1394,58 @@ add_retrodeck_to_steam(){
log i "RetroDECK has been added to Steam" log i "RetroDECK has been added to Steam"
} }
repair_paths() {
# This function will verify that all folders defined in the [paths] section of retrodeck.cfg exist
# If a folder doesn't exist and is defined outside of rdhome, it will check in rdhome first and have the user browse for them manually if it isn't there either
# USAGE: repair_paths
invalid_path_found="false"
log i "Checking that all RetroDECK paths are valid"
while read -r config_line; do
local current_setting_name=$(get_setting_name "$config_line" "retrodeck")
if [[ ! $current_setting_name =~ (rdhome|sdcard) ]]; then # Ignore these locations
local current_setting_value=$(get_setting_value "$rd_conf" "$current_setting_name" "retrodeck" "paths")
if [[ ! -d "$current_setting_value" ]]; then # If the folder doesn't exist as defined
log i "$current_setting_name does not exist as defined, config is incorrect"
if [[ ! -d "$rdhome/${current_setting_value#*retrodeck/}" ]]; then # If the folder doesn't exist within defined rdhome path
if [[ ! -d "$sdcard/${current_setting_value#*retrodeck/}" ]]; then # If the folder doesn't exist within defined sdcard path
log i "$current_setting_name cannot be found at any expected location, having user locate it manually"
configurator_generic_dialog "RetroDECK Path Repair" "The RetroDECK $current_setting_name was not found in the expected location.\nThis may happen when the folder is moved manually.\n\nPlease browse to the current location of the $current_setting_name."
new_path=$(directory_browse "RetroDECK $current_setting_name location")
set_setting_value "$rd_conf" "$current_setting_name" "$new_path" retrodeck "paths"
invalid_path_found="true"
else # Folder does exist within defined sdcard path, update accordingly
log i "$current_setting_name found in $sdcard/retrodeck, correcting path config"
new_path="$sdcard/retrodeck/${current_setting_value#*retrodeck/}"
set_setting_value "$rd_conf" "$current_setting_name" "$new_path" retrodeck "paths"
invalid_path_found="true"
fi
else # Folder does exist within defined rdhome path, update accordingly
log i "$current_setting_name found in $rdhome, correcting path config"
new_path="$rdhome/${current_setting_value#*retrodeck/}"
set_setting_value "$rd_conf" "$current_setting_name" "$new_path" retrodeck "paths"
invalid_path_found="true"
fi
fi
fi
done < <(grep -v '^\s*$' $rd_conf | awk '/^\[paths\]/{f=1;next} /^\[/{f=0} f')
if [[ $invalid_path_found == "true" ]]; then
log i "One or more invalid paths repaired, fixing internal RetroDECK structures"
conf_read
dir_prep "$logs_folder" "$rd_logs_folder"
prepare_component "postmove" "all"
configurator_generic_dialog "RetroDECK Path Repair" "One or more incorrectly configured paths were repaired."
else
log i "All folders were found at their expected locations"
configurator_generic_dialog "RetroDECK Path Repair" "All RetroDECK folders were found at their expected locations."
fi
}
# Function to sanitize strings for filenames
sanitize() {
# Replace sequences of underscores with a single space
echo "$1" | sed -e 's/_\{2,\}/ /g' -e 's/_/ /g' -e 's/:/ -/g' -e 's/&/and/g' -e 's%/%and%g' -e 's/ / /g'
}

View file

@ -9,6 +9,58 @@ post_update() {
update_rd_conf update_rd_conf
export CONFIGURATOR_GUI="zenity"
# Optional userdata backup prior to update
choice=$(rd_zenity --title "RetroDECK Update - Backup Userdata" --info --no-wrap --ok-label="No Backup" --extra-button"Backup Core Userdata" --extra-button="Backup Some Userdata" --extra-button="Backup All Userdata" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --text="Would you like to backup some or all of the RetroDECK userdata prior to update?\n\nIf you choose \"Backup Core Userdata\" only irreplaceable files (like saves, states and gamelists) will be backed up. If you choose \"Backup Some Userdata\" you will be given a choice of which folders to backup.\n\nIf you choose \"Backup All Userdata\" then ALL data (including ROMs and downloaded media) will be backed up.\nPLEASE NOTE: A full backup may take up a large amount of space, especially if you have a lot of scraped media.")
local rc=$?
if [[ $rc == "0" ]] && [[ -z "$choice" ]]; then # User selected No Backup button
log i "User chose to not backup prior to update."
else
case $choice in
"Backup Core Userdata" )
log i "User chose to backup core userdata prior to update."
backup_retrodeck_userdata "core"
;;
"Backup Some Userdata" )
log i "User chose to backup some userdata prior to update."
while read -r config_line; do
local current_setting_name=$(get_setting_name "$config_line" "retrodeck")
if [[ ! $current_setting_name =~ (rdhome|sdcard|backups_folder) ]]; then # Ignore these locations
log d "Adding $current_setting_name to compressible paths."
local current_setting_value=$(get_setting_value "$rd_conf" "$current_setting_name" "retrodeck" "paths")
compressible_paths=("${compressible_paths[@]}" "false" "$current_setting_name" "$current_setting_value")
fi
done < <(grep -v '^\s*$' $rd_conf | awk '/^\[paths\]/{f=1;next} /^\[/{f=0} f')
choice=$(rd_zenity \
--list --width=1200 --height=720 \
--checklist \
--separator="^" \
--print-column=3 \
--text="Please select folders to compress..." \
--column "Backup?" \
--column "Folder Name" \
--column "Path" \
"${compressible_paths[@]}")
choices=() # Expand choice string into passable array
IFS='^' read -ra choices <<< "$choice"
backup_retrodeck_userdata "custom" "${choices[@]}" # Expand array of choices into individual arguments
;;
"Backup All Userdata" )
log i "User chose to backup all userdata prior to update."
backup_retrodeck_userdata "complete"
;;
esac
fi
# Start of post_update actions
if [[ $(check_version_is_older_than "$version_being_updated" "0.5.0b") == "true" ]]; then # If updating from prior to save sorting change at 0.5.0b if [[ $(check_version_is_older_than "$version_being_updated" "0.5.0b") == "true" ]]; then # If updating from prior to save sorting change at 0.5.0b
log d "Version is older than 0.5.0b, executing save migration" log d "Version is older than 0.5.0b, executing save migration"
save_migration save_migration
@ -674,6 +726,29 @@ post_update() {
fi # end of 0.9.1b fi # end of 0.9.1b
if [[ $(check_version_is_older_than "$version_being_updated" "0.9.2b") == "true" ]]; then
# In version 0.9.2b, the following changes were made that required config file updates/reset or other changes to the filesystem:
# Steam Sync completely rebuilt into new manifest system. Favorites will need to be nuked and, if steam_sync is enabled will be rebuilt.
if [[ -d "$steamsync_folder" ]]; then # If Steam Sync has ever been run
steam-rom-manager nuke
steam_sync
if [[ "$(configurator_generic_question_dialog "RetroDECK 0.9.2b Steam Sync Reset" "In RetroDECK 0.9.2b we upgraded our Steam Sync feature and the shortcuts in Steam need to be rebuilt.\n\nAll of your ES-DE favorites are still unchanged.\nAny games you have favorited now will be recreated.\n\nIf you have added RetroDECK to Steam through our Configurator it will also be removed through this process.\nWould you like to add the RetroDECK shortcut again?")" == "true" ]]; then
(
# Add RetroDECK launcher to Steam
steam-rom-manager enable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager add >> "$srm_log" 2>&1
) |
rd_zenity --progress \
--title="RetroDECK Configurator: Add RetroDECK to Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="Adding RetroDECK launcher to Steam, please wait..." \
--pulsate --width=500 --height=150 --auto-close --no-cancel
fi
fi
fi # end of 0.9.2b
# The following commands are run every time. # The following commands are run every time.
if [[ -d "/var/data/dolphin-emu/Load/DynamicInputTextures" ]]; then # Refresh installed textures if they have been enabled if [[ -d "/var/data/dolphin-emu/Load/DynamicInputTextures" ]]; then # Refresh installed textures if they have been enabled
@ -710,5 +785,7 @@ post_update() {
changelog_dialog "$version" changelog_dialog "$version"
fi fi
unset CONFIGURATOR_GUI
log i "Upgrade process completed successfully." log i "Upgrade process completed successfully."
} }

View file

@ -138,8 +138,6 @@ prepare_component() {
jq '.environmentVariables.romsDirectory = "'$rdhome'/.sync"' "$srm_userdata/userSettings.json" > "$srm_userdata/tmp.json" && mv -f "$srm_userdata/tmp.json" "$srm_userdata/userSettings.json" jq '.environmentVariables.romsDirectory = "'$rdhome'/.sync"' "$srm_userdata/userSettings.json" > "$srm_userdata/tmp.json" && mv -f "$srm_userdata/tmp.json" "$srm_userdata/userSettings.json"
get_steam_user get_steam_user
populate_steamuser_srm
fi fi
if [[ "$component" =~ ^(retroarch|all)$ ]]; then if [[ "$component" =~ ^(retroarch|all)$ ]]; then
@ -561,8 +559,10 @@ prepare_component() {
if [[ "$component" =~ ^(pico8|pico-8|all)$ ]]; then if [[ "$component" =~ ^(pico8|pico-8|all)$ ]]; then
component_found="true" component_found="true"
if [[ ("$action" == "reset") || ("$action" == "postmove") ]]; then if [[ ("$action" == "reset") || ("$action" == "postmove") ]]; then
if [[ -d "$roms_folder/pico8" ]]; then
dir_prep "$roms_folder/pico8" "$bios_folder/pico-8/carts" # Symlink default game location to RD roms for cleanliness (this location is overridden anyway by the --root_path launch argument anyway)
fi
dir_prep "$bios_folder/pico-8" "$HOME/.lexaloffle/pico-8" # Store binary and config files together. The .lexaloffle directory is a hard-coded location for the PICO-8 config file, cannot be changed dir_prep "$bios_folder/pico-8" "$HOME/.lexaloffle/pico-8" # Store binary and config files together. The .lexaloffle directory is a hard-coded location for the PICO-8 config file, cannot be changed
dir_prep "$roms_folder/pico8" "$bios_folder/pico-8/carts" # Symlink default game location to RD roms for cleanliness (this location is overridden anyway by the --root_path launch argument anyway)
dir_prep "$saves_folder/pico-8" "$bios_folder/pico-8/cdata" # PICO-8 saves folder dir_prep "$saves_folder/pico-8" "$bios_folder/pico-8/cdata" # PICO-8 saves folder
cp -fv "$config/pico-8/config.txt" "$bios_folder/pico-8/config.txt" cp -fv "$config/pico-8/config.txt" "$bios_folder/pico-8/config.txt"
cp -fv "$config/pico-8/sdl_controllers.txt" "$bios_folder/pico-8/sdl_controllers.txt" cp -fv "$config/pico-8/sdl_controllers.txt" "$bios_folder/pico-8/sdl_controllers.txt"

View file

@ -1,121 +1,167 @@
#!/bin/bash #!/bin/bash
# Function to sanitize strings for filenames steam_sync() {
sanitize() {
# Replace sequences of underscores with a single space
echo "$1" | sed -e 's/_\{2,\}/ /g' -e 's/_/ /g' -e 's/:/ -/g' -e 's/&/and/g' -e 's%/%and%g' -e 's/ / /g'
}
add_to_steam() { # This function looks for favorited games in all ES-DE gamelists and builds a manifest of any found.
# It then compares the new manifest to the existing one (if it exists) and runs an SRM sync if there are differences
# If all favorites were removed from ES-DE, it will remove all existing entries from Steam and then remove the favorites manifest entirely
# If there is no existing manifest, this is a first time sync and games are synced automatically
# USAGE: steam_sync
log "i" "Starting Steam Sync" log "i" "Starting Steam Sync"
create_dir $steamsync_folder create_dir $steamsync_folder
create_dir $steamsync_folder_tmp
local srm_path="/var/config/steam-rom-manager/userData/userConfigurations.json"
if [ ! -f "$srm_path" ]; then if [ ! -f "$srm_path" ]; then
log "e" "Steam ROM Manager configuration not initialized! Initializing now." log "e" "Steam ROM Manager configuration not initialized! Initializing now."
prepare_component "reset" "steam-rom-manager" prepare_component "reset" "steam-rom-manager"
fi fi
# Iterate through all gamelist.xml files in the folder structure # Prepare fresh log file
echo > "$srm_log"
# Prepare new favorites manifest
echo "[]" > "${retrodeck_favorites_file}.new" # Initialize favorites JSON file
# Static definitions for all JSON objects
target="flatpak"
launch_command="run net.retrodeck.retrodeck"
startIn=""
for system_path in "$rdhome/ES-DE/gamelists/"*/; do for system_path in "$rdhome/ES-DE/gamelists/"*/; do
# Skip the CLEANUP folder # Skip the CLEANUP folder
if [[ "$system_path" == *"/CLEANUP/"* ]]; then if [[ "$system_path" == *"/CLEANUP/"* ]]; then
continue continue
fi fi
# Skip folders with no gamelists
if [[ ! -f "${system_path}gamelist.xml" ]]; then
continue
fi
system=$(basename "$system_path") # Extract the folder name as the system name system=$(basename "$system_path") # Extract the folder name as the system name
gamelist="${system_path}gamelist.xml" gamelist="${system_path}gamelist.xml"
system_favorites=$(xml sel -t -m "//game[favorite='true']" -v "path" -n "$gamelist")
log d "Reading favorites for $system" while read -r game; do
if [[ -n "$game" ]]; then # Avoid empty lines created by xmlstarlet
# Ensure gamelist.xml exists in the current folder local game="${game#./}" # Remove leading ./
if [ -f "$gamelist" ]; then if [[ -f "$roms_folder/$system/$game" ]]; then # Validate file exists and isn't a stale ES-DE entry for a removed file
while IFS= read -r line; do # Construct launch options with the rom path in quotes, to handle spaces
# Detect the start of a <game> block local launchOptions="$launch_command -s $system \"$roms_folder/$system/$game\""
if [[ "$line" =~ \<game\> ]]; then jq --arg title "${game%.*}" --arg target "$target" --arg launchOptions "$launchOptions" \
to_be_added=false # Reset the flag for a new block '. += [{"title": $title, "target": $target, "launchOptions": $launchOptions}]' "${retrodeck_favorites_file}.new" > "${retrodeck_favorites_file}.tmp" \
path="" && mv "${retrodeck_favorites_file}.tmp" "${retrodeck_favorites_file}.new"
name=""
fi fi
fi
# Check for <favorite>true</favorite> done <<< "$system_favorites"
if [[ "$line" =~ \<favorite\>true\<\/favorite\> ]]; then
to_be_added=true
fi
# Extract the <path> and remove leading "./" if present
if [[ "$line" =~ \<path\>(.*)\<\/path\> ]]; then
path="${BASH_REMATCH[1]#./}"
fi
# Extract and sanitize <name>
if [[ "$line" =~ \<name\>(.*)\<\/name\> ]]; then
name=$(sanitize "${BASH_REMATCH[1]}")
fi
# Detect the end of a </game> block
if [[ "$line" =~ \<\/game\> ]]; then
# If the block is meaningful (marked as favorite), generate the launcher
if [ "$to_be_added" = true ] && [ -n "$path" ] && [ -n "$name" ]; then
local launcher="$steamsync_folder/${name}.sh"
local launcher_tmp="$steamsync_folder_tmp/${name}.sh"
# Create the launcher file
# Check if the launcher file does not already exist
if [ ! -e "$launcher_tmp" ]; then
log d "Creating launcher file: $launcher"
command="flatpak run net.retrodeck.retrodeck -s $system '$roms_folder/$system/$path'"
echo '#!/bin/bash' > "$launcher_tmp"
echo "$command" >> "$launcher_tmp"
chmod +x "$launcher_tmp"
else
log d "$(basename $launcher) desktop file already exists"
fi
fi
# Clean up variables for safety
to_be_added=false
path=""
name=""
fi
done < "$gamelist"
else
log "e" "Gamelist file not found for system: $system"
fi
done done
# Remove the old Steam sync folder if [[ -f "$retrodeck_favorites_file" && -f "${retrodeck_favorites_file}.new" ]]; then
rm -rf "$steamsync_folder" # Look for favorites removed between steam_sync runs, if any
removed_items=$(jq -n \
# Move the temporary Steam sync folder to the final location --slurpfile source "$retrodeck_favorites_file" \
log d "Moving the temporary Steam sync folder to the final location" --slurpfile target "${retrodeck_favorites_file}.new" \
mv "$steamsync_folder_tmp" "$steamsync_folder" && log d "\"$steamsync_folder_tmp\" -> \"$steamsync_folder\"" '[$source[0][] | select(. as $item | ($target[0] | map(. == $item) | any | not))]')
fi
# Check if the Steam sync folder is empty # Check if there are any missing objects
if [ -z "$(ls -A $steamsync_folder)" ]; then if [[ "$(echo "$removed_items" | jq 'length')" -gt 0 ]]; then
# if empty, add the remove_from_steam function log d "Some favorites were removed between sync, writing to $retrodeck_removed_favorites"
log d "No games found, cleaning shortcut" echo "$removed_items" > "$retrodeck_removed_favorites"
remove_from_steam fi
else
log d "Updating game list" # Decide if sync needs to happen
steam-rom-manager enable --names "RetroDECK Steam Sync" if [[ -f "$retrodeck_favorites_file" ]]; then # If an existing favorites manifest exists
steam-rom-manager add if [[ ! "$(cat "${retrodeck_favorites_file}.new" | jq 'length')" -gt 0 ]]; then # If all favorites were removed from all gamelists, meaning new manifest is empty
log i "No favorites were found in current ES-DE gamelists, removing old entries"
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
(
# Remove old entries
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager remove >> "$srm_log" 2>&1
) |
rd_zenity --progress \
--title="Syncing with Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="<span foreground='$purple'><b>\t\t\t\tRemoving unfavorited games from Steam</b></span>\n\n<b>NOTE: </b>This operation may take some time depending on the size of your library.\nFeel free to leave this in the background and switch to another application.\n\n" \
--pulsate --width=500 --height=150 --auto-close --no-cancel
else
# Remove old entries
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager remove >> "$srm_log" 2>&1
fi
# Old manifest cleanup
rm "$retrodeck_favorites_file"
rm "${retrodeck_favorites_file}.new"
else # The new favorites manifest is not empty
if cmp -s "$retrodeck_favorites_file" "${retrodeck_favorites_file}.new"; then # See if the favorites manifests are the same, meaning there were no changes
log i "ES-DE favorites have not changed, no need to sync again"
rm "${retrodeck_favorites_file}.new"
else
log d "New and old manifests are different, running sync"
if [[ -f "$retrodeck_removed_favorites" ]]; then # If some favorites were removed between syncs
log d "Some favorites removed between syncs, removing unfavorited games"
# Load removed favorites as manifest and run SRM remove
mv "$retrodeck_removed_favorites" "$retrodeck_favorites_file"
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
(
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager remove >> "$srm_log" 2>&1
) |
rd_zenity --progress \
--title="Syncing with Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="<span foreground='$purple'><b>\t\t\t\tRemoving unfavorited games from Steam</b></span>\n\n<b>NOTE: </b>This operation may take some time depending on the size of your library.\nFeel free to leave this in the background and switch to another application.\n\n" \
--pulsate --width=500 --height=150 --auto-close --no-cancel
else
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager remove >> "$srm_log" 2>&1
fi
fi
# Load new favorites manifest as games to add during sync
mv "${retrodeck_favorites_file}.new" "$retrodeck_favorites_file"
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
(
# Add new favorites manifest
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager add >> "$srm_log" 2>&1
) |
rd_zenity --progress \
--title="Syncing with Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="<span foreground='$purple'><b>\t\t\t\tSyncing favorite games with Steam</b></span>\n\n<b>NOTE: </b>This operation may take some time depending on the size of your library.\nFeel free to leave this in the background and switch to another application.\n\n" \
--pulsate --width=500 --height=150 --auto-close --no-cancel
else
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager add >> "$srm_log" 2>&1
fi
fi
fi
elif [[ "$(cat "${retrodeck_favorites_file}.new" | jq 'length')" -gt 0 ]]; then # No existing favorites manifest was found, so check if new manifest has entries
log d "First time building favorites manifest, running sync"
mv "${retrodeck_favorites_file}.new" "$retrodeck_favorites_file"
if [[ "$CONFIGURATOR_GUI" == "zenity" ]]; then
(
# Add new favorites manifest
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager add >> "$srm_log" 2>&1
) |
rd_zenity --progress \
--title="Syncing with Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="<span foreground='$purple'><b>\t\t\t\tSyncing favorite games with Steam</b></span>\n\n<b>NOTE: </b>This operation may take some time depending on the size of your library.\nFeel free to leave this in the background and switch to another application.\n\n" \
--pulsate --width=500 --height=150 --auto-close --no-cancel
else
# Add new favorites manifest
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager add >> "$srm_log" 2>&1
fi
fi fi
} }
# Function to remove the games from Steam, this is a workaround to make SRM remove the games as it cannot remove the games based on a empty folder
# So a dummy file must be in place to make SRM remove the other games
remove_from_steam() {
log d "Creating dummy game"
cat "" > "$steamsync_folder/CUL0.sh"
log d "Cleaning the shortcut"
steam-rom-manager enable --names "RetroDECK Steam Sync"
steam-rom-manager disable --names "RetroDECK Launcher"
steam-rom-manager remove
log d "Removing dummy game"
rm "$steamsync_folder/CUL0.sh"
steam-rom-manager enable --names "RetroDECK Launcher"
steam-rom-manager disable --names "RetroDECK Steam Sync"
}

View file

@ -86,7 +86,7 @@ modules:
# VERSION INITIALIZATION # VERSION INITIALIZATION
# on main please update this with the version variable, eg: VERSION=0.8.0b # on main please update this with the version variable, eg: VERSION=0.8.0b
# on cooker will be VERSION=cooker-0.9.0b for example # on cooker will be VERSION=cooker-0.9.0b for example
VERSION=cooker-0.9.1b VERSION=cooker-0.9.2b
git checkout ${GITHUB_REF_NAME} git checkout ${GITHUB_REF_NAME}
mkdir -p ${FLATPAK_DEST}/retrodeck/ mkdir -p ${FLATPAK_DEST}/retrodeck/

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View file

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> <svg width="100%" height="100%" viewBox="0 0 800 800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1.88235,0,0,1.86861,-7.52941,-5.60584)"> <g transform="matrix(3.125,0,0,3.125,0,0)">
<path d="M140,37.25C140,18.347 124.765,3 106,3L38,3C19.235,3 4,18.347 4,37.25L4,105.75C4,124.653 19.235,140 38,140L106,140C124.765,140 140,124.653 140,105.75L140,37.25Z" style="fill:rgb(17,17,17);"/> <g transform="matrix(1.88235,0,0,1.86861,-7.52941,-5.60584)">
</g> <path d="M140,37.25C140,18.347 124.765,3 106,3L38,3C19.235,3 4,18.347 4,37.25L4,105.75C4,124.653 19.235,140 38,140L106,140C124.765,140 140,124.653 140,105.75L140,37.25Z" style="fill:rgb(17,17,17);"/>
<g transform="matrix(2.02105,0,0,2.02105,-13.4737,-13.4737)">
<g id="D" transform="matrix(-0.674885,8.26495e-17,-8.26495e-17,-0.674885,223.747,109.037)">
<path d="M172.54,-2.511C175.786,-5.757 179.378,-8.24 183.315,-9.96C187.251,-11.68 191.533,-12.54 196.16,-12.54L271.855,-12.54L271.855,6.901L196.16,6.901C194.44,6.901 192.823,7.222 191.309,7.864C189.795,8.506 188.475,9.39 187.348,10.517C186.222,11.643 185.337,12.964 184.695,14.478C184.053,15.992 183.732,17.609 183.732,19.329L183.732,96.355C183.732,97.954 184.084,99.498 184.786,100.988C185.489,102.478 186.416,103.798 187.566,104.949C188.717,106.1 190.037,107.027 191.527,107.729C193.017,108.432 194.562,108.783 196.16,108.783L271.855,108.783L271.855,128.224L196.16,128.224C193.859,128.224 191.624,127.982 189.456,127.498C187.288,127.013 185.204,126.329 183.206,125.444C181.207,124.56 179.311,123.5 177.518,122.265C175.726,121.029 174.066,119.673 172.54,118.195C169.366,115.118 166.901,111.575 165.145,107.566C163.389,103.556 162.51,99.226 162.51,94.574L162.51,21.11C162.51,16.458 163.37,12.17 165.09,8.246C166.811,4.321 169.294,0.736 172.54,-2.511Z" style="fill:white;fill-rule:nonzero;"/>
</g> </g>
<g id="Engine" transform="matrix(0.494792,-0,-0,0.494792,6.66667,6.66667)"> <g id="Central-Icons" serif:id="Central Icons" transform="matrix(0.32,-0,-0,0.32,0,0)">
<use xlink:href="#_Image1" x="33.993" y="72.667" width="111px" height="111px"/> <use xlink:href="#_Image1" x="135.918" y="251.889" width="296px" height="296px"/>
</g>
<g id="D" transform="matrix(-1.36398,1.67039e-16,-1.67039e-16,-1.36398,438.73,206.895)">
<path d="M172.54,-2.511C175.786,-5.757 179.378,-8.24 183.315,-9.96C187.251,-11.68 191.533,-12.54 196.16,-12.54L271.855,-12.54L271.855,6.901L196.16,6.901C194.44,6.901 192.823,7.222 191.309,7.864C189.795,8.506 188.475,9.39 187.348,10.517C186.222,11.643 185.337,12.964 184.695,14.478C184.053,15.992 183.732,17.609 183.732,19.329L183.732,96.355C183.732,97.954 184.084,99.498 184.786,100.988C185.489,102.478 186.416,103.798 187.566,104.949C188.717,106.1 190.037,107.027 191.527,107.729C193.017,108.432 194.562,108.783 196.16,108.783L271.855,108.783L271.855,128.224L196.16,128.224C193.859,128.224 191.624,127.982 189.456,127.498C187.288,127.013 185.204,126.329 183.206,125.444C181.207,124.56 179.311,123.5 177.518,122.265C175.726,121.029 174.066,119.673 172.54,118.195C169.366,115.118 166.901,111.575 165.145,107.566C163.389,103.556 162.51,99.226 162.51,94.574L162.51,21.11C162.51,16.458 163.37,12.17 165.09,8.246C166.811,4.321 169.294,0.736 172.54,-2.511Z" style="fill:white;fill-rule:nonzero;"/>
</g> </g>
</g> </g>
<defs> <defs>
<image id="_Image1" width="111px" height="111px" xlink:href="data:image/png;base64,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"/> <image id="_Image1" width="296px" height="296px" xlink:href="data:image/png;base64,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"/>
</defs> </defs>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

18
res/icon-ponzu.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -109,6 +109,10 @@ while [[ $# -gt 0 ]]; do
cli_compress_all_games "$2" cli_compress_all_games "$2"
shift 2 shift 2
;; ;;
--repair-paths)
repair_paths
exit 0
;;
--configurator) --configurator)
sh /app/tools/configurator.sh sh /app/tools/configurator.sh
exit 0 exit 0

View file

@ -76,6 +76,7 @@ rd_zenity --progress --no-cancel --pulsate --auto-close \
# - Update Notification # - Update Notification
# - Add RetroDECK to Steam # - Add RetroDECK to Steam
# - M3U Multi-File Validator # - M3U Multi-File Validator
# - Repair RetroDECK paths
# - Ponzu: Remove Yuzu # - Ponzu: Remove Yuzu
# - Ponzu: Remove Citra # - Ponzu: Remove Citra
# - Steam Sync # - Steam Sync
@ -108,7 +109,6 @@ rd_zenity --progress --no-cancel --pulsate --auto-close \
configurator_welcome_dialog() { configurator_welcome_dialog() {
log i "Configurator: opening welcome dialog" log i "Configurator: opening welcome dialog"
export CONFIGURATOR_GUI="zenity"
welcome_menu_options=( welcome_menu_options=(
"Settings" "Customize your RetroDECK experience with various presets and tweaks." "Settings" "Customize your RetroDECK experience with various presets and tweaks."
"Open Component" "Manually launch and configure settings for each emulator or component (for advanced users)." "Open Component" "Manually launch and configure settings for each emulator or component (for advanced users)."
@ -443,6 +443,7 @@ configurator_tools_dialog() {
"Update Notification" "Enable / Disable: Notifications for new RetroDECK versions." "Update Notification" "Enable / Disable: Notifications for new RetroDECK versions."
"Add RetroDECK to Steam" "Add RetroDECK shortcut to Steam. Steam restart required." "Add RetroDECK to Steam" "Add RetroDECK shortcut to Steam. Steam restart required."
"M3U Multi-File Validator" "Verify the proper structure of multi-file or multi-disc games." "M3U Multi-File Validator" "Verify the proper structure of multi-file or multi-disc games."
"Repair RetroDECK Paths" "Repair RetroDECK folder path configs for unexpectedly missing folders."
) )
if [[ $(get_setting_value "$rd_conf" "kiroi_ponzu" "retrodeck" "options") == "true" ]]; then if [[ $(get_setting_value "$rd_conf" "kiroi_ponzu" "retrodeck" "options") == "true" ]]; then
@ -460,26 +461,66 @@ configurator_tools_dialog() {
case $choice in case $choice in
"Backup Userdata" ) "Backup Userdata" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_generic_dialog "RetroDECK Configurator - Backup Userdata" "This tool will compress important RetroDECK userdata (basically everything except the ROMs folder) into a zip file.\n\nThis process can take several minutes, and the resulting zip file can be found in the ~/retrodeck/backups folder." configurator_generic_dialog "RetroDECK Configurator - Backup Userdata" "This tool will compress one or more RetroDECK userdata folders into a single zip file.\n\nThis process can take several minutes, and the resulting zip file can be found in the ~/retrodeck/backups folder."
(
backup_retrodeck_userdata choice=$(rd_zenity --title "RetroDECK Configurator Utility - Backup Userdata" --info --no-wrap --ok-label="Cancel" --extra-button"Backup Core Userdata" --extra-button="Backup Some Userdata" --extra-button="Backup All Userdata" \
) | --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --text="Would you like to compress all RetroDECK userdata folders, or only some of them?\nThe \"Core Userdata\" includes irreplaceable files such as saves, states and gamelists.\n\n A complete \"All Userdata\" backup can take up A LOT of space if you have a large library.")
rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --pulsate --auto-close \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \ local rc=$?
--title "RetroDECK Configurator Utility - Backup in Progress" \ if [[ $rc == "0" ]] && [[ -z "$choice" ]]; then # User selected Cancel button
--text="Backing up RetroDECK userdata, please wait..." configurator_tools_dialog
if [[ -f "$backups_folder/$(date +"%0m%0d")_retrodeck_userdata.zip" ]]; then
configurator_generic_dialog "RetroDECK Configurator - Backup Userdata" "The backup process is now complete."
else else
configurator_generic_dialog "RetroDECK Configurator - Backup Userdata" "The backup process could not be completed,\nplease check the logs folder for more information." case $choice in
"Backup Core Userdata" )
log i "User chose to backup core userdata prior to update."
export CONFIGURATOR_GUI="zenity"
backup_retrodeck_userdata "core"
;;
"Backup Some Userdata" )
log i "User chose to backup custom userdata prior to update."
while read -r config_line; do
local current_setting_name=$(get_setting_name "$config_line" "retrodeck")
if [[ ! $current_setting_name =~ (rdhome|sdcard|backups_folder) ]]; then # Ignore these locations
log d "Adding $current_setting_name to compressible paths."
local current_setting_value=$(get_setting_value "$rd_conf" "$current_setting_name" "retrodeck" "paths")
compressible_paths=("${compressible_paths[@]}" "false" "$current_setting_name" "$current_setting_value")
fi
done < <(grep -v '^\s*$' $rd_conf | awk '/^\[paths\]/{f=1;next} /^\[/{f=0} f')
choice=$(rd_zenity \
--list --width=1200 --height=720 \
--checklist \
--separator="^" \
--print-column=3 \
--text="Please select folders to compress..." \
--column "Backup?" \
--column "Folder Name" \
--column "Path" \
"${compressible_paths[@]}")
choices=() # Expand choice string into passable array
IFS='^' read -ra choices <<< "$choice"
export CONFIGURATOR_GUI="zenity"
backup_retrodeck_userdata "custom" "${choices[@]}" # Expand array of choices into individual arguments
;;
"Backup All Userdata" )
log i "User chose to backup all userdata prior to update."
export CONFIGURATOR_GUI="zenity"
backup_retrodeck_userdata "complete"
;;
esac
configurator_tools_dialog
fi fi
configurator_welcome_dialog
;; ;;
"BIOS Checker" ) "BIOS Checker" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_bios_checker configurator_bios_checker
configurator_tools_dialog
;; ;;
"Games Compressor" ) "Games Compressor" )
@ -542,12 +583,29 @@ configurator_tools_dialog() {
;; ;;
"Add RetroDECK to Steam" ) "Add RetroDECK to Steam" )
add_retrodeck_to_steam (
# Add RetroDECK launcher to Steam
steam-rom-manager enable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager add >> "$srm_log" 2>&1
) |
rd_zenity --progress \
--title="RetroDECK Configurator: Add RetroDECK to Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="Adding RetroDECK launcher to Steam, please wait..." \
--pulsate --width=500 --height=150 --auto-close --no-cancel
configurator_tools_dialog
;; ;;
"M3U Multi-File Validator" ) "M3U Multi-File Validator" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_check_multifile_game_structure configurator_check_multifile_game_structure
configurator_tools_dialog
;;
"Repair RetroDECK Paths" )
log i "Configurator: opening \"$choice\" menu"
repair_paths
configurator_tools_dialog
;; ;;
"Ponzu: Remove Yuzu" ) "Ponzu: Remove Yuzu" )
@ -658,7 +716,7 @@ configurator_data_management_dialog() {
--list --width=1200 --height=720 --title "RetroDECK Configurator - RetroDECK: Clean Empty ROM Folders" \ --list --width=1200 --height=720 --title "RetroDECK Configurator - RetroDECK: Clean Empty ROM Folders" \
--checklist --hide-column=3 --ok-label="Remove Selected" --extra-button="Remove All" \ --checklist --hide-column=3 --ok-label="Remove Selected" --extra-button="Remove All" \
--separator="," --print-column=2 \ --separator="," --print-column=2 \
--text="Choose which ROM folders to remove:" \ --text="Choose which empty ROM folders to remove:" \
--column "Remove?" \ --column "Remove?" \
--column "System" \ --column "System" \
"${empty_rom_folders_list[@]}") "${empty_rom_folders_list[@]}")
@ -715,26 +773,31 @@ configurator_compression_tool_dialog() {
"Compress Multiple Games: CHD" ) "Compress Multiple Games: CHD" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_compress_multiple_games_dialog "chd" configurator_compress_multiple_games_dialog "chd"
configurator_compression_tool_dialog
;; ;;
"Compress Multiple Games: ZIP" ) "Compress Multiple Games: ZIP" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_compress_multiple_games_dialog "zip" configurator_compress_multiple_games_dialog "zip"
configurator_compression_tool_dialog
;; ;;
"Compress Multiple Games: RVZ" ) "Compress Multiple Games: RVZ" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_compress_multiple_games_dialog "rvz" configurator_compress_multiple_games_dialog "rvz"
configurator_compression_tool_dialog
;; ;;
"Compress Multiple Games: All Formats" ) "Compress Multiple Games: All Formats" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_compress_multiple_games_dialog "all" configurator_compress_multiple_games_dialog "all"
configurator_compression_tool_dialog
;; ;;
"Compress All Games" ) "Compress All Games" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_compress_multiple_games_dialog "everything" configurator_compress_multiple_games_dialog "everything"
configurator_compression_tool_dialog
;; ;;
"" ) # No selection made or Back button clicked "" ) # No selection made or Back button clicked
@ -755,7 +818,7 @@ configurator_compress_single_game_dialog() {
( (
echo "# Compressing $(basename "$file") to $compatible_compression_format format" # This updates the Zenity dialog echo "# Compressing $(basename "$file") to $compatible_compression_format format" # This updates the Zenity dialog
log i "Compressing $(basename "$file") to $compatible_compression_format format" log i "Compressing $(basename "$file") to $compatible_compression_format format"
compress_game "$compatible_compression_format" "$file" "$system" compress_game "$compatible_compression_format" "$file" "$post_compression_cleanup" "$system"
) | ) |
rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --pulsate --auto-close \ rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --pulsate --auto-close \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \ --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
@ -775,120 +838,86 @@ configurator_compress_single_game_dialog() {
configurator_compress_multiple_games_dialog() { configurator_compress_multiple_games_dialog() {
log d "Starting to compress \"$1\"" log d "Starting to compress \"$1\""
local output_file="${godot_compression_compatible_games}" local compressible_games_list_file="${godot_compression_compatible_games}"
[ -f "$output_file" ] && rm -f "$output_file" [ -f "$compressible_games_list_file" ] && rm -f "$compressible_games_list_file"
touch "$output_file" touch "$compressible_games_list_file"
## --- SEARCH PHASE WITH LOADING SCREEN ---
local progress_pipe
progress_pipe=$(mktemp -u)
mkfifo "$progress_pipe"
# Launch find_compatible_games in the background (its output goes to the file)
find_compatible_games "$1" > "$output_file" &
local finder_pid=$!
# Launch a background process that writes loading messages until the search completes.
( (
while kill -0 "$finder_pid" 2>/dev/null; do find_compatible_games "$1" > "$compressible_games_list_file"
echo "# Loading: Searching for compatible games..." ) |
sleep 1 rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --auto-close \
done --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
echo "100" --title "RetroDECK Configurator - RetroDECK: Compression Tool" --text "RetroDECK is searching for compress1ble games, please wait..."
) > "$progress_pipe" &
local progress_writer_pid=$!
rd_zenity --progress --pulsate --auto-close \ if [[ -s "$compressible_games_list_file" ]]; then
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \ mapfile -t all_compressible_games < "$compressible_games_list_file"
--title="RetroDECK Configurator Utility - Searching for Compressable Games" \ log d "Found the following games to compress: ${all_compressible_games[*]}"
--text="Searching for compressable games, please wait..." < "$progress_pipe"
wait "$finder_pid"
wait "$progress_writer_pid"
rm "$progress_pipe"
if [[ -s "$output_file" ]]; then
mapfile -t all_compressable_games < "$output_file"
log d "Found the following games to compress: ${all_compressable_games[*]}"
else else
configurator_generic_dialog "RetroDECK Configurator - Compression Tool" "No compressable files were found." configurator_generic_dialog "RetroDECK Configurator - Compression Tool" "No compressible files were found."
return configurator_compression_tool_dialog
fi fi
local games_to_compress=() local games_to_compress=()
if [[ "$1" != "everything" ]]; then if [[ "$1" != "everything" ]]; then
local checklist_entries=() local checklist_entries=()
for line in "${all_compressable_games[@]}"; do for line in "${all_compressible_games[@]}"; do
IFS="^" read -r game comp <<< "$line" IFS="^" read -r game comp <<< "$line"
local short_game="${game#$roms_folder}" local short_game="${game#$roms_folder}"
checklist_entries+=( "TRUE" "$short_game" "$line" ) checklist_entries+=( "TRUE" "$short_game" "$line" )
done done
local choice local choice=$(rd_zenity \
choice=$(rd_zenity \
--list --width=1200 --height=720 --title "RetroDECK Configurator - Compression Tool" \ --list --width=1200 --height=720 --title "RetroDECK Configurator - Compression Tool" \
--checklist --hide-column=3 --ok-label="Compress Selected" --extra-button="Compress All" \ --checklist --hide-column=3 --ok-label="Compress Selected" --extra-button="Compress All" \
--separator="," --print-column=3 \ --separator=$'\0' --print-column=3 \
--text="Choose which games to compress:" \ --text="Choose which games to compress:" \
--column "Compress?" \ --column "Compress?" \
--column "Game" \ --column "Game" \
--column "Game Full Path" \ --column "Game Full Path and Compression Format" \
"${checklist_entries[@]}") "${checklist_entries[@]}")
local rc=$? local rc=$?
log d "User choice: $choice" log d "User choice: $choice"
if [[ $rc == 0 && -n "$choice" ]]; then if [[ $rc == 0 && -n "$choice" ]]; then
IFS="," read -ra games_to_compress <<< "$choice" while IFS="^" read -r game comp; do # Split Zenity choice string into compatible pairs (game^format)
games_to_compress+=("$game"^"$comp")
done <<< "$choice"
elif [[ -n "$choice" ]]; then elif [[ -n "$choice" ]]; then
games_to_compress=("${all_compressable_games[@]}") games_to_compress=("${all_compressible_games[@]}")
else else
return configurator_compression_tool_dialog
fi fi
else else
games_to_compress=("${all_compressable_games[@]}") games_to_compress=("${all_compressible_games[@]}")
fi fi
local post_compression_cleanup=$(configurator_compression_cleanup_dialog)
local total_games=${#games_to_compress[@]} local total_games=${#games_to_compress[@]}
local games_left=$total_games local games_left=$total_games
## --- COMPRESSION PHASE WITH PROGRESS SCREEN ---
local comp_pipe
comp_pipe=$(mktemp -u)
mkfifo "$comp_pipe"
( (
for game_line in "${games_to_compress[@]}"; do for game_line in "${games_to_compress[@]}"; do
IFS="^" read -r game compression_format <<< "$game_line" IFS="^" read -r game compression_format <<< "$game_line"
local system
system=$(echo "$game" | grep -oE "$roms_folder/[^/]+" | grep -oE "[^/]+$")
log i "Compressing $(basename "$game") into $compression_format format"
# Launch the compression in the background. local system
compress_game "$compression_format" "$game" "$system" & system=$(echo "$game" | grep -oE "$roms_folder/[^/]+" | grep -oE "[^/]+$")
local comp_pid=$! log i "Compressing $(basename "$game") into $compression_format format"
# While the compression is in progress, write a status message every second. echo "#Compressing $(basename "$game") into $compression_format format.\n\n$games_left games left to compress." # Update Zenity dialog text
while kill -0 "$comp_pid" 2>/dev/null; do compress_game "$compression_format" "$game" "$post_compression_cleanup" "$system"
echo "# Compressing $(basename "$game") into $compression_format format"
sleep 1
done
# When finished, update the progress percentage.
local progress=$(( 100 - (( 100 / total_games ) * games_left) ))
echo "$progress"
games_left=$(( games_left - 1 ))
done
echo "100"
) > "$comp_pipe" &
local comp_pid_group=$!
games_left=$(( games_left - 1 ))
local progress=$(( 99 - (( 99 / total_games ) * games_left) ))
log d "progress: $progress"
echo "$progress" # Update Zenity dialog progress bar
done
echo "100" # Close Zenity progress dialog when finished
) |
rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --auto-close \ rd_zenity --icon-name=net.retrodeck.retrodeck --progress --no-cancel --auto-close \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck/retrodeck.svg" \ --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck/retrodeck.svg" \
--width="800" \ --width="800" \
--title "RetroDECK Configurator Utility - Compression in Progress" < "$comp_pipe" --title "RetroDECK Configurator Utility - Compression in Progress"
wait "$comp_pid_group"
rm "$comp_pipe"
configurator_generic_dialog "RetroDECK Configurator - Compression Tool" "The compression process is complete!" configurator_generic_dialog "RetroDECK Configurator - Compression Tool" "The compression process is complete!"
configurator_compression_tool_dialog configurator_compression_tool_dialog
@ -1066,8 +1095,6 @@ configurator_bios_checker() {
--title "RetroDECK Configurator Utility - BIOS Check in Progress" \ --title "RetroDECK Configurator Utility - BIOS Check in Progress" \
--text="This check will look for BIOS files that RetroDECK has identified as working.\n\nNot all BIOS files are required for games to work, please check the BIOS description for more information on its purpose.\n\nBIOS files not known to this tool could still function.\n\nSome more advanced emulators such as Ryujinx will have additional methods to verify that the BIOS files are in working order.\n\nRetroDECK is now checking your BIOS files, please wait...\n\n" \ --text="This check will look for BIOS files that RetroDECK has identified as working.\n\nNot all BIOS files are required for games to work, please check the BIOS description for more information on its purpose.\n\nBIOS files not known to this tool could still function.\n\nSome more advanced emulators such as Ryujinx will have additional methods to verify that the BIOS files are in working order.\n\nRetroDECK is now checking your BIOS files, please wait...\n\n" \
--width=400 --height=100 --width=400 --height=100
configurator_welcome_dialog
} }
configurator_reset_dialog() { configurator_reset_dialog() {
@ -1199,7 +1226,7 @@ configurator_steam_sync() {
if [ $? == 0 ] # User clicked "Yes" if [ $? == 0 ] # User clicked "Yes"
then then
disable_steam_sync configurator_disable_steam_sync
else # User clicked "Cancel" else # User clicked "Cancel"
configurator_welcome_dialog configurator_welcome_dialog
fi fi
@ -1211,15 +1238,17 @@ configurator_steam_sync() {
if [ $? == 0 ] if [ $? == 0 ]
then then
enable_steam_sync configurator_enable_steam_sync
else else
configurator_welcome_dialog configurator_welcome_dialog
fi fi
fi fi
} }
enable_steam_sync() { configurator_enable_steam_sync() {
set_setting_value "$rd_conf" "steam_sync" "true" retrodeck "options" set_setting_value "$rd_conf" "steam_sync" "true" retrodeck "options"
export CONFIGURATOR_GUI="zenity"
steam_sync
zenity --icon-name=net.retrodeck.retrodeck --info --no-wrap --ok-label="OK" \ zenity --icon-name=net.retrodeck.retrodeck --info --no-wrap --ok-label="OK" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \ --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK Configurator - RetroDECK Steam Syncronization" \ --title "RetroDECK Configurator - RetroDECK Steam Syncronization" \
@ -1227,10 +1256,22 @@ enable_steam_sync() {
configurator_welcome_dialog configurator_welcome_dialog
} }
disable_steam_sync() { configurator_disable_steam_sync() {
set_setting_value "$rd_conf" "steam_sync" "false" retrodeck "options" set_setting_value "$rd_conf" "steam_sync" "false" retrodeck "options"
source /app/libexec/steam_sync.sh # Remove only synced favorites, leave RetroDECK shortcut if it exists
remove_from_steam (
steam-rom-manager enable --names "RetroDECK Steam Sync" >> "$srm_log" 2>&1
steam-rom-manager disable --names "RetroDECK Launcher" >> "$srm_log" 2>&1
steam-rom-manager remove >> "$srm_log" 2>&1
) |
rd_zenity --progress \
--title="Removing RetroDECK Sync from Steam" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--text="Removing synced entries from Steam, please wait..." \
--pulsate --width=500 --height=150 --auto-close --no-cancel
if [[ -f "$retrodeck_favorites_file" ]]; then
rm -f "$retrodeck_favorites_file"
fi
zenity --icon-name=net.retrodeck.retrodeck --info --no-wrap --ok-label="OK" \ zenity --icon-name=net.retrodeck.retrodeck --info --no-wrap --ok-label="OK" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \ --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK Configurator - RetroDECK Steam Syncronization" \ --title "RetroDECK Configurator - RetroDECK Steam Syncronization" \
@ -1382,7 +1423,6 @@ configurator_usb_import_dialog() {
"Prepare USB device" ) "Prepare USB device" )
log i "Configurator: opening \"$choice\" menu" log i "Configurator: opening \"$choice\" menu"
configurator_generic_dialog "RetroDeck Configurator - USB Import" "If you have an SD card installed that is not currently configured in RetroDECK it may show up in this list, but not be suitable for USB import.\n\nPlease select your desired drive carefully."
external_devices=() external_devices=()
@ -1392,6 +1432,7 @@ configurator_usb_import_dialog() {
done < <(df --output=size,target -h | grep "/run/media/" | grep -v "$sdcard" | awk '{$1=$1;print}') done < <(df --output=size,target -h | grep "/run/media/" | grep -v "$sdcard" | awk '{$1=$1;print}')
if [[ "${#external_devices[@]}" -gt 0 ]]; then if [[ "${#external_devices[@]}" -gt 0 ]]; then
configurator_generic_dialog "RetroDeck Configurator - USB Import" "If you have an SD card installed that is not currently configured in RetroDECK it may show up in this list, but not be suitable for USB import.\n\nPlease select your desired drive carefully."
choice=$(rd_zenity --list --title="RetroDECK Configurator Utility - USB Migration Tool" --cancel-label="Back" \ choice=$(rd_zenity --list --title="RetroDECK Configurator Utility - USB Migration Tool" --cancel-label="Back" \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \ --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \
--hide-column=3 --print-column=3 \ --hide-column=3 --print-column=3 \
@ -1401,9 +1442,10 @@ configurator_usb_import_dialog() {
"${external_devices[@]}") "${external_devices[@]}")
if [[ ! -z "$choice" ]]; then if [[ ! -z "$choice" ]]; then
create_dir "$choice/RetroDECK Import"
es-de --home "$choice/RetroDECK Import" --create-system-dirs es-de --home "$choice/RetroDECK Import" --create-system-dirs
rm -rf "$choice/RetroDECK Import/ES-DE" # Cleanup unnecessary folder rm -rf "$choice/RetroDECK Import/ES-DE" # Cleanup unnecessary folder
create_dir "$choice/RetroDECK Import/BIOS"
# Prepare default BIOS folder subfolders # Prepare default BIOS folder subfolders
create_dir "$choice/RetroDECK Import/BIOS/np2kai" create_dir "$choice/RetroDECK Import/BIOS/np2kai"