diff --git a/functions/crc32.py b/functions/crc32.py new file mode 100644 index 00000000..4dc8bf46 --- /dev/null +++ b/functions/crc32.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +import os, sys +import zlib + +def crc32(fileName): + prev = 0 + for eachLine in open(fileName,"rb"): + prev = zlib.crc32(eachLine, prev) + return "%X"%(prev & 0xFFFFFFFF) + +print(crc32(sys.argv[1]).lower()) diff --git a/functions/game_downloader.sh b/functions/game_downloader.sh new file mode 100755 index 00000000..ce137e9a --- /dev/null +++ b/functions/game_downloader.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +hacks_db_setup() { + crc32_cmd="python3 /app/libexec/crc32.py" + + # "hacks" is the general name which includes ROM Hacks, Homebrew and Ports + hacks_db_path="$HOME/.var/app/net.retrodeck.retrodeck/data/hacks_metadata.db" + + # Set up hacks database + declare -g hacks_db_cmd="sqlite3 $hacks_db_path" + $hacks_db_cmd < <(curl -sL "https://raw.githubusercontent.com/Libretto7/best-romhacks/main/db_setup.sql") + $hacks_db_cmd "ALTER TABLE bases ADD COLUMN local_path;" +} + +db_sanitize() { + echo "$(echo "$1" | sed -e "s/'/''/g")" +} + +check_romhacks_compatibility() { + # Add paths of locally available base roms to db + + for rom_path in ${roms_folder}/*/*; do + if [[ "$(basename "$rom_path")" != "systeminfo.txt" ]]; then + + crc32="$($crc32_cmd "$rom_path")" + + $hacks_db_cmd < <(echo "UPDATE bases SET local_path = '""$(db_sanitize "$rom_path")""' WHERE crc32 = '""$crc32""'") + fi + done +} + +install_romhack() { + # $1: name of romhack + + hack_name="$1" + infos=$($hacks_db_cmd "SELECT bases.system,bases.name,bases.local_path \ + FROM bases JOIN rhacks ON bases.crc32 = rhacks.base_crc32 \ + WHERE rhacks.name = '""$(db_sanitize "$1")""'") + + IFS='|' read -r system base_name base_local_path <<< $infos + + # Download patchfile + wget -q "https://github.com/Libretto7/best-romhacks/raw/main/rhacks/$system/$base_name/$hack_name/patch.tar.xz" \ + -O "/tmp/patch.tar.xz" + + # Extract patchfile + patchfile_name=$(tar -xvf "/tmp/patch.tar.xz" --directory="$roms_folder/$system") + + # Create the hack + base_name="$(basename "$base_local_path")" + ext="$(echo "${base_name##*.}")" + flips --apply "$roms_folder/$system/$patchfile_name" "$base_local_path" "$roms_folder/$system/$hack_name.$ext" >/dev/null + + # Cleanup + rm "$roms_folder/$system/$patchfile_name" +} diff --git a/functions/global.sh b/functions/global.sh index cabfb66f..d9d67121 100644 --- a/functions/global.sh +++ b/functions/global.sh @@ -7,6 +7,7 @@ source /app/libexec/checks.sh source /app/libexec/compression.sh source /app/libexec/dialogs.sh source /app/libexec/functions.sh +source /app/libexec/game_downloader.sh source /app/libexec/multi_user.sh source /app/libexec/patching.sh source /app/libexec/post_update.sh diff --git a/net.retrodeck.retrodeck.yml b/net.retrodeck.retrodeck.yml index 5d895820..9d7a8236 100644 --- a/net.retrodeck.retrodeck.yml +++ b/net.retrodeck.retrodeck.yml @@ -1361,4 +1361,4 @@ modules: sources: - type: git url: https://github.com/XargonWan/RetroDECK.git - branch: THISBRANCH \ No newline at end of file + branch: THISBRANCH diff --git a/tools/configurator.sh b/tools/configurator.sh index edd9cf67..88918020 100644 --- a/tools/configurator.sh +++ b/tools/configurator.sh @@ -92,12 +92,14 @@ source /app/libexec/global.sh # - Version-specific changelogs # - RetroDECK Credits # - Add to Steam +# - ROM Hack Downloader # - Developer Options (Hidden) # - Change Multi-user mode # - Change Update channel # - Browse the wiki # - USB Import tool # - Install: RetroDECK Starter Pack +# - Game Downloader # DIALOG TREE FUNCTIONS @@ -109,6 +111,7 @@ configurator_welcome_dialog() { "RetroDECK: Troubleshooting" "Backup data, perform BIOS / multi-disc file checks checks and emulator resets" \ "RetroDECK: About" "Show additional information about RetroDECK" \ "Sync with Steam" "Sync with Steam all the favorites games" \ + "ROM Hack Downloader" "Install ROM Hacks which are compatible with your ROMs" \ "Developer Options" "Welcome to the DANGER ZONE") else welcome_menu_options=("Presets & Settings" "Here you find various presets, tweaks and settings to customize your RetroDECK experience" \ @@ -150,6 +153,11 @@ configurator_welcome_dialog() { configurator_add_steam ;; + "ROM Hack Downloader" ) + configurator_generic_dialog "RetroDECK Configurator - ROM Hack Downloader" "In order to download ROM Hacks you need to have the ROMs the hacks are based on already available. Your base ROMs need to be compatible with the hacks, otherwise those hacks will not be shown.\n\nRight now, your base ROMs need to be uncompressed for this to work.\n\nThe compatible ROM Hacks will now be listed." + configurator_romhack_downloader_dialog + ;; + "Developer Options" ) configurator_generic_dialog "RetroDECK Configurator - Developer Options" "The following features and options are potentially VERY DANGEROUS for your RetroDECK install!\n\nThey should be considered the bleeding-edge of upcoming RetroDECK features, and never used when you have important saves/states/roms that are not backed up!\n\nYOU HAVE BEEN WARNED!" configurator_developer_dialog @@ -1218,7 +1226,8 @@ configurator_developer_dialog() { "Change Update Channel" "Change between normal and cooker builds" \ "Browse the Wiki" "Browse the RetroDECK wiki online" \ "USB Import" "Prepare a USB device for ROMs or import an existing collection" \ - "Install RetroDECK Starter Pack" "Install the optional RetroDECK starter pack" ) + "Install RetroDECK Starter Pack" "Install the optional RetroDECK starter pack" \ + "Game Downloader" "Install ROM Hacks, Homebrew or Ports" ) case $choice in @@ -1246,6 +1255,10 @@ configurator_developer_dialog() { configurator_developer_dialog ;; + "Game Downloader" ) + configurator_game_downloader_dialog + ;; + "" ) # No selection made or Back button clicked configurator_welcome_dialog ;; @@ -1397,6 +1410,88 @@ configurator_usb_import_dialog() { } +configurator_game_downloader_dialog() { + choice=$(zenity --list --title="RetroDECK Configurator Utility - Game Downloader" --cancel-label="Back" \ + --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \ + --column="Choice" --column="Description" \ + "ROM Hack Downloader" "Install ROM Hacks which are compatible with your ROMs" \ + "Homebrew Downloader" "Install Homebrew (Not yet functional)" \ + "Ports Downloader" "Install Ports (Not yet functional)" ) + + case $choice in + + "ROM Hack Downloader" ) + configurator_generic_dialog "RetroDECK Configurator - ROM Hack Downloader" "In order to download ROM Hacks you need to have the ROMs the hacks are based on already available. Your base ROMs need to be compatible with the hacks, otherwise those hacks will not be shown.\n\nRight now, your base ROMs need to be uncompressed for this to work.\n\nThe compatible ROM Hacks will now be listed." + configurator_romhack_downloader_dialog + ;; + + "Homebrew Downloader" ) + configurator_developer_dialog + ;; + + "Ports Downloader" ) + configurator_developer_dialog + ;; + + "" ) # No selection made or Back button clicked + configurator_welcome_dialog + ;; + + esac +} + +configurator_romhack_downloader_dialog() { + hacks_db_setup + check_romhacks_compatibility # add paths of available base roms to db + + available_bases_crc32s="$($hacks_db_cmd "SELECT crc32 FROM bases WHERE local_path NOT NULL;")" + + zenity_columns=() + while IFS= read -r base_crc32; do + + # Get info of the available hacks for this base crc32 + info_of_hacks_compatible_with_base="$($hacks_db_cmd "SELECT rhacks.name,bases.system,rhacks.released,rhacks.retro_achievements,rhacks.description \ + FROM bases JOIN rhacks ON bases.crc32 = rhacks.base_crc32 + WHERE bases.crc32 = '""$base_crc32""'")" + + while IFS= read -r single_hack_info; do + + # Turn db output into array + IFS='|' read -r -a single_hack_info_array <<< "$single_hack_info" + + # Add row of hack info to zenity choices + for info in "${single_hack_info_array[@]}"; do + zenity_columns+=("$info") + done + + done <<< "$info_of_hacks_compatible_with_base" + done <<< "$available_bases_crc32s" + + if [[ ${#zenity_columns[@]} != 0 ]]; then # Compatible base ROMs found + choice=$(zenity --list --title="RetroDECK Configurator Utility - ROM Hack Downloader" --cancel-label="Back" \ + --window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" --width=1200 --height=720 \ + --column="ROM Hack Name" --column="System" --column="Released" --column="RetroAchievements" --column="Description" \ + "${zenity_columns[@]}" ) + + if [[ -z "$choice" ]]; then # no selection or back button + configurator_welcome_dialog + else + install_romhack "$choice" + rc=$? + if [[ $rc == "0" ]]; then + configurator_generic_dialog "RetroDECK Configurator - ROM Hack Downloader" "$choice was installed successfully!" + else + configurator_generic_dialog "RetroDECK Configurator - ROM Hack Downloader" "Something went wrong :(" + fi + + configurator_romhack_downloader_dialog + fi + else # No compatible base ROMs + configurator_generic_dialog "RetroDECK Configurator - ROM Hack Downloader" "You have no uncompressed ROMs which are compatible with the available patches." + configurator_welcome_dialog + fi +} + # START THE CONFIGURATOR configurator_welcome_dialog