Skip to content

Instantly share code, notes, and snippets.

@BenMcLean
Last active November 11, 2025 00:24
Show Gist options
  • Select an option

  • Save BenMcLean/aca52aa406620dc41b604a7fee6fd393 to your computer and use it in GitHub Desktop.

Select an option

Save BenMcLean/aca52aa406620dc41b604a7fee6fd393 to your computer and use it in GitHub Desktop.
Batch convert RVZ to ISO using Dolphin's command-line tool
#!/bin/bash
# Check if source argument provided
if [ $# -eq 0 ]; then
echo "Usage: $0 <source_directory> [destination_directory]"
echo "Example: $0 /path/to/rvz/archive /path/to/sdcard"
echo ""
echo "If destination is not provided, files will be converted to the script's directory"
exit 1
fi
SOURCE_DIR="$1"
# If destination not provided, use script's directory
if [ $# -eq 1 ]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEST_DIR="$SCRIPT_DIR"
echo "No destination specified, using script directory: $DEST_DIR"
echo ""
else
DEST_DIR="$2"
fi
# Check if source directory exists
if [ ! -d "$SOURCE_DIR" ]; then
echo "Error: Source directory does not exist: $SOURCE_DIR"
exit 1
fi
# Check if destination directory exists
if [ ! -d "$DEST_DIR" ]; then
echo "Error: Destination directory does not exist: $DEST_DIR"
exit 1
fi
# Check if DolphinTool is available
if ! command -v dolphin-tool &> /dev/null; then
echo "Error: dolphin-tool not found"
echo "Please install Dolphin Emulator or add it to your PATH"
echo ""
echo "On Linux: sudo apt install dolphin-emu (or your package manager)"
echo "On macOS: brew install --cask dolphin"
echo "On Windows: Download from https://dolphin-emu.org/"
exit 1
fi
# Function to format seconds into human-readable time
format_time() {
local seconds=$1
local hours=$((seconds / 3600))
local minutes=$(((seconds % 3600) / 60))
local secs=$((seconds % 60))
if [ $hours -gt 0 ]; then
printf "%dh %dm %ds" $hours $minutes $secs
elif [ $minutes -gt 0 ]; then
printf "%dm %ds" $minutes $secs
else
printf "%ds" $secs
fi
}
# Function to format bytes into human-readable size
format_size() {
local bytes=$1
if [ $bytes -ge 1073741824 ]; then
echo "$(awk "BEGIN {printf \"%.2f\", $bytes/1073741824}") GB"
elif [ $bytes -ge 1048576 ]; then
echo "$(awk "BEGIN {printf \"%.2f\", $bytes/1048576}") MB"
elif [ $bytes -ge 1024 ]; then
echo "$(awk "BEGIN {printf \"%.2f\", $bytes/1024}") KB"
else
echo "$bytes bytes"
fi
}
echo "Converting RVZ files to ISO"
echo "Source: $SOURCE_DIR"
echo "Destination: $DEST_DIR"
echo "================================================"
echo ""
# Count total RVZ files and store them in an array
echo "Scanning for RVZ files..."
mapfile -t rvz_files < <(find "$SOURCE_DIR" -type f -iname "*.rvz" | sort)
total_files=${#rvz_files[@]}
if [ $total_files -eq 0 ]; then
echo "No RVZ files found in $SOURCE_DIR"
exit 0
fi
echo "Found $total_files RVZ file(s) to convert"
echo ""
# Counter for statistics
current=0
total_converted=0
total_failed=0
total_skipped=0
total_input_size=0
total_output_size=0
# Start time
start_time=$(date +%s)
# Process each file
for rvzfile in "${rvz_files[@]}"; do
((current++))
# Get just the filename without extension
file_basename=$(basename "$rvzfile" .rvz)
# Create ISO in destination directory (flat structure)
isofile="$DEST_DIR/${file_basename}.iso"
# Check if ISO already exists at destination
if [ -f "$isofile" ]; then
echo "[$current/$total_files] Skipping (already exists): $file_basename"
((total_skipped++))
echo ""
continue
fi
# Calculate progress percentage
progress=$((current * 100 / total_files))
# Calculate time estimates
current_time=$(date +%s)
elapsed=$((current_time - start_time))
if [ $current -gt 1 ]; then
avg_time_per_file=$((elapsed / (current - 1)))
remaining_files=$((total_files - current + 1))
eta=$((avg_time_per_file * remaining_files))
eta_formatted=$(format_time $eta)
elapsed_formatted=$(format_time $elapsed)
else
eta_formatted="calculating..."
elapsed_formatted=$(format_time $elapsed)
fi
# Progress bar with standard ASCII characters
bar_width=30
filled=$((progress * bar_width / 100))
empty=$((bar_width - filled))
bar=$(printf "%${filled}s" | tr ' ' '#')
bar+=$(printf "%${empty}s" | tr ' ' '-')
# Get input file size
input_size=$(stat -f%z "$rvzfile" 2>/dev/null || stat -c%s "$rvzfile" 2>/dev/null)
input_size_formatted=$(format_size $input_size)
echo "[$bar] $progress% ($current/$total_files)"
echo "Elapsed: $elapsed_formatted | ETA: $eta_formatted"
echo "Converting: $file_basename ($input_size_formatted)"
echo "---"
# Convert to ISO using dolphin-tool
if dolphin-tool convert -f iso -i "$rvzfile" -o "$isofile" 2>&1; then
# Get output file size
output_size=$(stat -f%z "$isofile" 2>/dev/null || stat -c%s "$isofile" 2>/dev/null)
output_size_formatted=$(format_size $output_size)
# Calculate compression ratio
if [ $input_size -gt 0 ]; then
ratio=$(awk "BEGIN {printf \"%.1f\", ($output_size/$input_size)}")
else
ratio="N/A"
fi
echo "---"
echo "✓ Successfully converted: $file_basename"
echo " Input: $input_size_formatted"
echo " Output: $output_size_formatted (${ratio}x)"
total_input_size=$((total_input_size + input_size))
total_output_size=$((total_output_size + output_size))
((total_converted++))
echo ""
else
echo "---"
echo "✗ Failed to convert: $file_basename"
((total_failed++))
echo ""
fi
done
# Final statistics
end_time=$(date +%s)
total_time=$((end_time - start_time))
total_time_formatted=$(format_time $total_time)
# Format total sizes
total_input_formatted=$(format_size $total_input_size)
total_output_formatted=$(format_size $total_output_size)
# Calculate overall compression ratio
if [ $total_input_size -gt 0 ]; then
overall_ratio=$(awk "BEGIN {printf \"%.1f\", ($total_output_size/$total_input_size)}")
space_saved=$((total_output_size - total_input_size))
if [ $space_saved -lt 0 ]; then
space_saved=$((space_saved * -1))
space_saved_formatted=$(format_size $space_saved)
space_saved_text="(saved $space_saved_formatted)"
else
space_saved_formatted=$(format_size $space_saved)
space_saved_text="(expanded by $space_saved_formatted)"
fi
else
overall_ratio="N/A"
space_saved_text=""
fi
echo "================================================"
echo "Conversion complete!"
echo ""
echo "Total files found: $total_files"
echo "Successfully converted: $total_converted"
echo "Skipped (exist): $total_skipped"
echo "Failed conversions: $total_failed"
echo ""
echo "Total input size: $total_input_formatted"
echo "Total output size: $total_output_formatted $space_saved_text"
echo "Expansion ratio: ${overall_ratio}x"
if [ $total_converted -gt 0 ]; then
avg_time=$((total_time / total_converted))
avg_time_formatted=$(format_time $avg_time)
echo "Average time per file: $avg_time_formatted"
fi
echo ""
echo "Total time: $total_time_formatted"
echo ""
@BenMcLean
Copy link
Author

BenMcLean commented Nov 11, 2025

In order to use this on Windows 11 WSL Ubuntu, I had to create a warpper script with sudo nano /usr/local/bin/dolphin-tool, pointing it at my Windows Dolphin (Chocolatey) installation at C:\tools\Dolphin\DolphinTool.exe:

#!/bin/bash
# Convert Linux paths to Windows paths for arguments
args=()
for arg in "$@"; do
    if [[ "$arg" == /mnt/* ]]; then
        # Convert /mnt/d/path to D:\path
        drive_letter=$(echo "$arg" | sed 's|/mnt/\([a-z]\)/|\U\1:\\|')
        windows_path=$(echo "$drive_letter" | sed 's|/|\\|g')
        args+=("$windows_path")
    else
        args+=("$arg")
    fi
done

"/mnt/c/tools/Dolphin/DolphinTool.exe" "${args[@]}"

This proved to be far easier than installing a Linux version of Dolphin as I had initially planned. Flatpak's sandboxing made it too difficult to use a script like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment