Last active
November 11, 2025 00:24
-
-
Save BenMcLean/aca52aa406620dc41b604a7fee6fd393 to your computer and use it in GitHub Desktop.
Batch convert RVZ to ISO using Dolphin's command-line tool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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 "" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 atC:\tools\Dolphin\DolphinTool.exe: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.