226 lines
5.7 KiB
Bash
Executable File
226 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
clear
|
|
|
|
# Gum theme
|
|
export GUM_THEME="\
|
|
[\"ui\"] = { background = \"#000000\", foreground = \"#FFA500\" }\
|
|
[\"ui.focused\"] = { background = \"#FFA500\", foreground = \"#000000\" }\
|
|
[\"ui.text\"] = { foreground = \"#FFA500\" }\
|
|
[\"box\"] = { background = \"#000000\", foreground = \"#FFA500\", border = \"#FFA500\" }\
|
|
[\"box.border\"] = { foreground = \"#FFA500\" }\
|
|
"
|
|
|
|
# FZF colors (orange highlight)
|
|
export FZF_DEFAULT_OPTS="--color=fg:#FFA500,bg:#000000,hl:#FFA500,fg+:#000000,bg+:#FFA500,hl+:#000000,info:#FFA500,prompt:#FFA500,pointer:#FFA500,marker:#FFA500,spinner:#FFA500"
|
|
|
|
title() {
|
|
gum style \
|
|
--foreground="#FFA500" \
|
|
--background="#000000" \
|
|
--border-foreground="#FFA500" \
|
|
--border="double" \
|
|
--align="center" \
|
|
--width="50" \
|
|
--margin="1" \
|
|
--padding="2 4" \
|
|
"MEGADRIVE CART FLASH"
|
|
}
|
|
|
|
# -------------------------
|
|
# Dependencies
|
|
# -------------------------
|
|
check_dependencies() {
|
|
# Ensure ~/.local/bin is in PATH (for pip installs)
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
|
|
# flashkit
|
|
if ! command -v flashkit &> /dev/null; then
|
|
gum confirm "flashkit is not installed. Install it now?" || exit 1
|
|
|
|
gum spin --spinner="line" --title="Installing flashkit..." -- \
|
|
python3 -m pip install --user flashkit
|
|
|
|
# Re-check after install
|
|
if ! command -v flashkit &> /dev/null; then
|
|
gum style --foreground="#FFA500" "flashkit install failed or not in PATH."
|
|
gum style --foreground="#FFA500" "Try: export PATH=\$HOME/.local/bin:\$PATH"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# pyserial
|
|
if ! python3 -c "import serial" &> /dev/null; then
|
|
gum confirm "pyserial is not installed. Install it now?" || exit 1
|
|
|
|
gum spin --spinner="line" --title="Installing pyserial..." -- \
|
|
python3 -m pip install --user pyserial
|
|
|
|
if ! python3 -c "import serial" &> /dev/null; then
|
|
gum style --foreground="#FFA500" "pyserial install failed."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# fzf
|
|
if ! command -v fzf &> /dev/null; then
|
|
gum confirm "fzf is not installed. Install it now?" || exit 1
|
|
|
|
gum spin --spinner="line" --title="Installing fzf..." -- \
|
|
sudo apt-get update && sudo apt-get install -y fzf
|
|
fi
|
|
|
|
# md5sum (usually present, but just in case)
|
|
if ! command -v md5sum &> /dev/null; then
|
|
gum style --foreground="#FFA500" "md5sum not found. Please install coreutils."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# -------------------------
|
|
# Detect FTDI port
|
|
# -------------------------
|
|
detect_port() {
|
|
gum style --foreground="#FFA500" "Detecting flash cartridge..."
|
|
|
|
if [ -d /dev/serial/by-id ]; then
|
|
matches=($(ls /dev/serial/by-id/*FTDI* 2>/dev/null))
|
|
fi
|
|
|
|
if [ ${#matches[@]} -eq 0 ]; then
|
|
for dev in /dev/ttyUSB*; do
|
|
[ -e "$dev" ] || continue
|
|
if udevadm info --query=property --name="$dev" | grep -q "ID_VENDOR_ID=0403"; then
|
|
matches+=("$dev")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [ ${#matches[@]} -eq 0 ]; then
|
|
gum style --foreground="#FFA500" "No FTDI flash device detected."
|
|
exit 1
|
|
fi
|
|
|
|
selected_port=$(readlink -f "${matches[0]}")
|
|
gum style --foreground="#FFA500" "Using port: $selected_port"
|
|
}
|
|
|
|
# -------------------------
|
|
# Read cart
|
|
# -------------------------
|
|
read_cart() {
|
|
clear
|
|
title
|
|
|
|
gum style --foreground="#FFA500" "Checking current cartridge content..."
|
|
check_output=$(flashkit --port "$selected_port" check 2>&1)
|
|
|
|
gum style \
|
|
--foreground="#FFA500" \
|
|
--border="rounded" \
|
|
--border-foreground="#FFA500" \
|
|
--padding="1 2" \
|
|
"$check_output"
|
|
}
|
|
|
|
# -------------------------
|
|
# FZF file browser
|
|
# -------------------------
|
|
browse_files() {
|
|
search_path="$1"
|
|
|
|
find "$search_path" -type f -name "*.md" -size +256k 2>/dev/null \
|
|
| fzf \
|
|
--height=40% \
|
|
--reverse \
|
|
--border \
|
|
--prompt="Select ROM > " \
|
|
--preview 'echo Size: $(du -h {} | awk "{print \$1}"); echo MD5: $(md5sum {} | awk "{print \$1}")'
|
|
}
|
|
|
|
# -------------------------
|
|
# Write ROM
|
|
# -------------------------
|
|
write_rom() {
|
|
clear
|
|
title
|
|
|
|
# Build menu dynamically
|
|
options=()
|
|
|
|
if [ -d "/mnt/nas/Games/ROMs/megadrive" ]; then
|
|
options+=("NAS (/mnt/nas/Games/ROMs/megadrive)")
|
|
fi
|
|
|
|
options+=("Search Home (~)")
|
|
|
|
source_choice=$(printf "%s\n" "${options[@]}" | gum choose --header="Select ROM source:")
|
|
|
|
case "$source_choice" in
|
|
"NAS (/mnt/nas/Games/ROMs/megadrive)")
|
|
if [ ! -d "/mnt/nas/Games/ROMs/megadrive" ]; then
|
|
gum style --foreground="#FFA500" "NAS path not available."
|
|
return
|
|
fi
|
|
rom_file=$(browse_files "/mnt/nas/Games/ROMs/megadrive")
|
|
;;
|
|
"Search Home (~)")
|
|
rom_file=$(browse_files "$HOME")
|
|
;;
|
|
*)
|
|
return
|
|
;;
|
|
esac
|
|
|
|
[ -z "$rom_file" ] && {
|
|
gum style --foreground="#FFA500" "No file selected."
|
|
return
|
|
}
|
|
|
|
# File info
|
|
rom_size=$(du -h "$rom_file" | awk '{print $1}')
|
|
rom_md5=$(md5sum "$rom_file" | awk '{print $1}')
|
|
|
|
gum style \
|
|
--foreground="#FFA500" \
|
|
--border="rounded" \
|
|
--border-foreground="#FFA500" \
|
|
--padding="1 2" \
|
|
"File: $(basename "$rom_file")
|
|
Size: $rom_size
|
|
MD5: $rom_md5"
|
|
|
|
gum confirm "Write this ROM to $selected_port?" && {
|
|
gum spin --spinner="line" --title="Writing ROM..." -- flashkit --port "$selected_port" write-rom -i "$rom_file"
|
|
gum style --foreground="#FFA500" "Done! ROM written successfully."
|
|
|
|
read_cart
|
|
} || {
|
|
gum style --foreground="#FFA500" "Cancelled."
|
|
}
|
|
}
|
|
|
|
# -------------------------
|
|
# Main
|
|
# -------------------------
|
|
check_dependencies
|
|
detect_port
|
|
read_cart
|
|
|
|
while true; do
|
|
choice=$(gum choose \
|
|
--header="Select an option:" \
|
|
"Read Cart" \
|
|
"Write ROM" \
|
|
"Exit")
|
|
|
|
case "$choice" in
|
|
"Read Cart") read_cart ;;
|
|
"Write ROM") write_rom ;;
|
|
"Exit")
|
|
gum style --foreground="#FFA500" "Goodbye."
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|