Files
PSBBN-Definitive-English-Patch/03-Game-Installer.sh
2025-06-18 22:49:19 +01:00

2210 lines
85 KiB
Bash
Executable File

#!/usr/bin/env bash
# Check if the shell is bash
if [ -z "$BASH_VERSION" ]; then
echo "Error: This script must be run using Bash. Try running it with: bash $0" >&2
exit 1
fi
# Set terminal size: 100 columns and 45 rows
echo -e "\e[8;33;100t"
version_check="2.10"
# Set paths
TOOLKIT_PATH="$(pwd)"
ICONS_DIR="${TOOLKIT_PATH}/icons"
ARTWORK_DIR="${ICONS_DIR}/art"
HELPER_DIR="${TOOLKIT_PATH}/helper"
ASSETS_DIR="${TOOLKIT_PATH}/assets"
POPSTARTER="${ASSETS_DIR}/POPStarter/POPSTARTER.ELF"
NEUTRINO_DIR="${ASSETS_DIR}/neutrino"
LOG_FILE="${TOOLKIT_PATH}/game-installer.log"
MISSING_ART=${TOOLKIT_PATH}/missing-art.log
MISSING_APP_ART=${TOOLKIT_PATH}/missing-app-art.log
MISSING_ICON=${TOOLKIT_PATH}/missing-icon.log
GAMES_PATH="${TOOLKIT_PATH}/games"
CONFIG_FILE="${TOOLKIT_PATH}/gamepath.cfg"
OPL="${TOOLKIT_PATH}/OPL"
PS1_LIST="${TOOLKIT_PATH}/ps1.list"
PS2_LIST="${TOOLKIT_PATH}/ps2.list"
ALL_GAMES="${TOOLKIT_PATH}/master.list"
prevent_sleep_start() {
if command -v xdotool >/dev/null; then
(
while true; do
xdotool key shift >/dev/null 2>&1
sleep 50
done
) &
SLEEP_PID=$!
elif command -v dbus-send >/dev/null; then
if dbus-send --session --dest=org.freedesktop.ScreenSaver \
--type=method_call --print-reply \
/ScreenSaver org.freedesktop.DBus.Introspectable.Introspect \
>/dev/null 2>&1; then
(
while true; do
dbus-send --session \
--dest=org.freedesktop.ScreenSaver \
--type=method_call \
/ScreenSaver org.freedesktop.ScreenSaver.SimulateUserActivity \
>/dev/null 2>&1
sleep 50
done
) &
SLEEP_PID=$!
elif dbus-send --session --dest=org.kde.screensaver \
--type=method_call --print-reply \
/ScreenSaver org.freedesktop.DBus.Introspectable.Introspect \
>/dev/null 2>&1; then
(
while true; do
dbus-send --session \
--dest=org.kde.screensaver \
--type=method_call \
/ScreenSaver org.kde.screensaver.simulateUserActivity \
>/dev/null 2>&1
sleep 50
done
) &
SLEEP_PID=$!
fi
fi
}
prevent_sleep_stop() {
if [[ -n "$SLEEP_PID" ]]; then
kill "$SLEEP_PID" 2>/dev/null
wait "$SLEEP_PID" 2>/dev/null
unset SLEEP_PID
fi
}
# Clean up on exit (even if interrupted)
trap prevent_sleep_stop EXIT
UNMOUNT_OPL() {
sync
if ! sudo umount -l "${TOOLKIT_PATH}/OPL" >> "${LOG_FILE}" 2>&1; then
echo "Error: Failed to unmount $DEVICE."
echo
read -n 1 -s -r -p "Press any key to exit..."
echo
exit 1;
fi
}
clean_up() {
# Remove unwanted directories inside $ICONS_DIR except 'art' and 'ico'
for item in "$ICONS_DIR"/*; do
if [ -d "$item" ] && [[ $(basename "$item") != art && $(basename "$item") != ico ]]; then
sudo rm -rf "$item"
fi
done
# Remove all directories inside ${GAMES_PATH}/APPS in reverse sorted order
find "${GAMES_PATH}/APPS" -mindepth 1 -maxdepth 1 -type d | sort -r | while IFS= read -r dir; do
sudo rm -rf -- "$dir"
done
# Remove listed files
sudo rm -f "${PS1_LIST}" "${PS2_LIST}" "${ALL_GAMES}" "${ARTWORK_DIR}/tmp"/* "${ICONS_DIR}/ico/tmp"/* "${TOOLKIT_PATH}/ps1.list.tmp" 2>>"$LOG_FILE" \
|| { echo "Error: Cleanup failed. See ${LOG_FILE} for details."; exit 1; }
}
error_msg() {
type=$1
error_1="$2"
error_2="$3"
error_3="$4"
error_4="$5"
echo
echo "$type: $error_1" | tee -a "${LOG_FILE}"
[ -n "$error_2" ] && echo "$error_2" | tee -a "${LOG_FILE}"
[ -n "$error_3" ] && echo "$error_3" | tee -a "${LOG_FILE}"
[ -n "$error_4" ] && echo "$error_4" | tee -a "${LOG_FILE}"
echo
if [ "$type" = "Error" ]; then
UNMOUNT_OPL
clean_up
read -n 1 -s -r -p "Press any key to exit..."
echo
exit 1;
else
read -n 1 -s -r -p "Press any key to continue..."
echo
fi
}
MOUNT_OPL() {
echo | tee -a "${LOG_FILE}"
echo "Mounting OPL partition..." | tee -a "${LOG_FILE}"
mkdir -p "${OPL}" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create ${OPL}."
sudo mount -o uid=$UID,gid=$(id -g) ${DEVICE}3 "${OPL}" >> "${LOG_FILE}" 2>&1
# Handle possibility host system's `mount` is using Fuse
if [ $? -ne 0 ] && hash mount.exfat-fuse; then
echo "Attempting to use exfat.fuse..." | tee -a "${LOG_FILE}"
sudo mount.exfat-fuse -o uid=$UID,gid=$(id -g) ${DEVICE}3 "${OPL}" >> "${LOG_FILE}" 2>&1
fi
if [ $? -ne 0 ]; then
error_msg "Error" "Failed to mount ${DEVICE}3"
fi
# Create necessary folders if they don't exist
for folder in APPS ART CFG CHT LNG THM VMC CD DVD bbnl; do
dir="${OPL}/${folder}"
[[ -d "$dir" ]] || mkdir -p "$dir" || {
error_msg "Error" "Failed to create $dir."
}
done
}
HDL_TOC() {
rm -f "$hdl_output"
hdl_output=$(mktemp)
if ! sudo "${HELPER_DIR}/HDL Dump.elf" toc "$DEVICE" 2>>"${LOG_FILE}" > "$hdl_output"; then
rm -f "$hdl_output"
error_msg "Error" "Failed to extract list of partitions." " " "APA partition could be broken on ${DEVICE}"
fi
}
PFS_COMMANDS() {
PFS_COMMANDS=$(echo -e "$COMMANDS" | sudo "${HELPER_DIR}/PFS Shell.elf" >> "${LOG_FILE}" 2>&1)
if echo "$PFS_COMMANDS" | grep -q "Exit code is"; then
error_msg "Error" "PFS Shell returned an error. See ${LOG_FILE}"
fi
}
process_psu_files() {
local target_dir="$1"
if find "$target_dir" -maxdepth 1 -type f \( -iname "*.psu" \) | grep -q .; then
echo "Processing PSU files in: $target_dir" | tee -a "${LOG_FILE}"
for file in "$target_dir"/*.psu "$target_dir"/*.PSU; do
[ -e "$file" ] || continue # Skip if no PSU files exist
echo "Extracting $file..."
"${HELPER_DIR}/PSU Extractor.elf" "$file" >> "${LOG_FILE}" 2>&1
done
fi
}
POPS_SIZE_CKECK() {
# Get total size of VCD files only on PC
LOCAL_SIZE=0
while IFS= read -r file; do
if [[ -f "$POPS_FOLDER/$file" ]]; then
size=$(du --block-size=1M "$POPS_FOLDER/$file" | cut -f1)
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
error_msg "Error" "Failed to calclate the size of local .VCD files. See ${LOG_FILE}"
fi
LOCAL_SIZE=$((LOCAL_SIZE + size))
fi
done <<< "$files_only_in_local"
# Get total size of VCD files on PS2 drive
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __.POPS\n"
COMMANDS+="ls -l\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
ps1_size=$(echo -e "$COMMANDS" | sudo "${HELPER_DIR}/PFS Shell.elf" 2>/dev/null)
if echo "$ps1_size" | grep -q "Exit code is"; then
echo "$ps1_size" >> "${LOG_FILE}"
error_msg "Error" "PFS Shell returned an error. See ${LOG_FILE}"
fi
ps1_size=$(echo "$ps1_size" | grep -iE "\.vcd$" | sort)
# Sum the total size in bytes
REMOTE_SIZE=$(echo "$ps1_size" | awk '{sum += $2} END {print sum}')
# Round up to MB and MiB
remote_mb=$(awk -v size="$REMOTE_SIZE" 'BEGIN {printf "%d", (size + 1000000 - 1) / 1000000}')
POPS_SIZE=$((remote_mb + LOCAL_SIZE))
echo | tee -a "${LOG_FILE}"
echo "Total size of PS1 games: $POPS_SIZE MB" | tee -a "${LOG_FILE}"
# Get the POPS partition size in MB
HDL_TOC
POPS_PARTITION=$(grep '__\.POPS' "$hdl_output" | awk '{print $4}' | grep -oE '[0-9]+')
echo "Available space: ${POPS_PARTITION} MB"| tee -a "${LOG_FILE}"
# Check if POPS_SIZE is greater than POPS_PARTITION - 128
THRESHOLD=$((POPS_PARTITION - 128))
if [ "$POPS_SIZE" -gt "$THRESHOLD" ]; then
error_msg "Error" "Total size of PS1 games is ${POPS_SIZE} MB, exceeds available space of ${THRESHOLD} MB." " " "Remove some VCD files from the local POPS folder and try again."
fi
}
POPS_SYNC() {
echo | tee -a "${LOG_FILE}"
echo "Preparing to $INSTALL_TYPE PS1 games..." | tee -a "${LOG_FILE}"
rm -f "$POPS_FOLDER"/*.[eE][lL][fF] 2>> "${LOG_FILE}"
# Generate the local file list directly in a variable
local_files=$( { ls -1 "$POPS_FOLDER" | grep -Ei '\.VCD$' | sort; } 2>> "${LOG_FILE}" )
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
error_msg "Error" "Failed to create list of local .VCD files. See ${LOG_FILE}"
fi
# Build the commands for PFS Shell
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __.POPS\n"
COMMANDS+="ls\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
# Get the PS1 file list directly from PFS Shell output, filtered and sorted
ps1_files=$(echo -e "$COMMANDS" | sudo "${HELPER_DIR}/PFS Shell.elf" 2>/dev/null)
if echo "$ps1_files" | grep -q "Exit code is"; then
echo "$ps1_files" >> "${LOG_FILE}"
error_msg "Error" "PFS Shell returned an error. See ${LOG_FILE}"
fi
ps1_files=$(echo "$ps1_files" | grep -iE "\.vcd$" | sort)
if [ "$INSTALL_TYPE" = "copy" ] && [ -f "${OPL}/ps1.list" ]; then
# Create an array of POPS files for easy comparison
mapfile -t pops_array < <(echo "$ps1_files")
# Initialize a temporary file
temp_list="${TOOLKIT_PATH}/ps1.list.tmp"
# Track whether any POPS file is missing from ps1.list
missing_from_list=false
while IFS= read -r line; do
vcd_file=$(echo "$line" | awk -F '|' '{print $5}')
if printf '%s\n' "${pops_array[@]}" | grep -Fxq "$vcd_file"; then
echo "$line" >> "$temp_list"
fi
done < "${OPL}/ps1.list"
# Check if any file in __.POPS is missing from ps1.list
for pops_file in "${pops_array[@]}"; do
if ! grep -Fq "|$pops_file" "${OPL}/ps1.list"; then
missing_from_list=true
break
fi
done
if $missing_from_list; then
echo "A file in __.POPS is missing from ps1.list — deleting ps1.list"
rm -f "${OPL}/ps1.list"
else
[ -f "$temp_list" ] && ! cp "$temp_list" "${OPL}/ps1.list" 2>>"${LOG_FILE}" && error_msg "Error" "Failed to copy $temp_list to ${OPL}/ps1.list"
fi
fi
# Compute differences and store them in variables
files_only_in_local=$(comm -23 <(echo "$local_files") <(echo "$ps1_files"))
if [ "$INSTALL_TYPE" = "sync" ] || [ ! -f "${OPL}/ps1.list" ]; then
files_only_in_ps2=$(comm -13 <(echo "$local_files") <(echo "$ps1_files"))
if [ "$INSTALL_TYPE" != "sync" ] && [ -n "$files_only_in_ps2" ]; then
error_msg "Warning" "Could not find ps1.list. PS1 games will be synced instead."
fi
fi
cd "$POPS_FOLDER" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to POPS folder."
# Delete PS1 VCDs
if [ -n "$files_only_in_ps2" ]; then
echo | tee -a "${LOG_FILE}"
echo "Deleteing PS1 games:" | tee -a "${LOG_FILE}"
echo "$files_only_in_ps2" | tee -a "${LOG_FILE}"
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __.POPS\n"
# Add delete commands for files_only_in_ps2
if [ -n "$files_only_in_ps2" ]; then
while IFS= read -r file; do
COMMANDS+="rm \"$file\"\n"
done <<< "$files_only_in_ps2"
fi
COMMANDS+="umount\n"
COMMANDS+="exit"
# Execute the combined commands with PFS Shell
PFS_COMMANDS
else
if [ "$INSTALL_TYPE" = "sync" ]; then
echo | tee -a "${LOG_FILE}"
echo "No PS1 games to delete." | tee -a "${LOG_FILE}"
fi
fi
# Copy PS1 VCDs
if [ -z "$files_only_in_local" ]; then
echo | tee -a "${LOG_FILE}"
echo "No PS1 games to copy." | tee -a "${LOG_FILE}"
else
POPS_SIZE_CKECK
echo | tee -a "${LOG_FILE}"
echo "Copying PS1 games:" | tee -a "${LOG_FILE}"
echo "$files_only_in_local" | tee -a "${LOG_FILE}"
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __.POPS\n"
# Add put commands for files_only_in_local
if [ -n "$files_only_in_local" ]; then
while IFS= read -r file; do
COMMANDS+="put \"$file\"\n"
done <<< "$files_only_in_local"
fi
COMMANDS+="umount\n"
COMMANDS+="exit"
# Execute the combined commands with PFS Shell
echo | tee -a "${LOG_FILE}"
echo -n "Copying..."
PFS_COMMANDS
echo | tee -a "${LOG_FILE}"
echo "PS1 games copied successfully." | tee -a "${LOG_FILE}"
fi
cd ${TOOLKIT_PATH} 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to $TOOLKIT_PATH."
}
OPL_SIZE_CKECK() {
if [ "$INSTALL_TYPE" = "sync" ]; then
opl_size=$(df -m --output=size "${OPL}" | tail -n 1 | awk '{$1=$1};1')
available_mb=$((opl_size - 128))
needed_mb=$(ls -l "${GAMES_PATH}/CD" "${GAMES_PATH}/DVD" | awk '{s+=$5} END {print int((s + 1048575) / 1048576)}')
elif [ "$INSTALL_TYPE" = "copy" ]; then
opl_freespace=$(df -m "${OPL}/" | awk 'NR==2 {print $4}')
available_mb=$((opl_freespace - 128))
cd_size=$(rsync -rL --ignore-existing --exclude=".*" --dry-run --out-format="%l" "${GAMES_PATH}/CD/" "${OPL}/CD/" | awk '{s+=$1} END {printf "%.0f\n", s / (1024*1024)}')
dvd_size=$(rsync -rL --ignore-existing --exclude=".*" --dry-run --out-format="%l" "${GAMES_PATH}/DVD/" "${OPL}/DVD/" | awk '{s+=$1} END {printf "%.0f\n", s / (1024*1024)}')
needed_mb=$((cd_size + dvd_size))
fi
if (( available_mb < needed_mb )); then
error_msg "Error" "Total size of PS2 games are ${needed_mb} MB, exceeds available space of ${available_mb} MB." " " "Remove some ISO/ZSO files from the local CD/DVD folders and try again."
fi
}
# Function to find available space
APA_SIZE_CHECK() {
HDL_TOC
# Extract the "used" value, remove "MB" and any commas
used=$(cat "$hdl_output" | awk '/used:/ {print $6}' | sed 's/,//; s/MB//')
capacity=129960
# Calculate available space (capacity - used)
available=$((capacity - used))
pp_max=$(((available / 8) - 1))
}
app_success_check() {
local name="$1"
if [ $exit_code -ne 0 ]; then
error_msg "Error" "Failed to update $name. See "${LOG_FILE}" for details."
else
echo | tee -a "${LOG_FILE}"
echo "Successfully updated $name." | tee -a "${LOG_FILE}"
fi
}
ps2_rsync_check() {
local type="$1"
# Check if PS2 sync/update failed
if [ $cd_status -ne 0 ] || [ $dvd_status -ne 0 ]; then
error_msg "Error" "Failed to $INSTALL_TYPE PS2 games. See ${LOG_FILE} for details."
else
echo | tee -a "${LOG_FILE}"
echo "PS2 games successfully $type." | tee -a "${LOG_FILE}"
fi
}
update_apps() {
local name="$1"
local source="$2"
local destination="$3"
local options="$4"
echo | tee -a "${LOG_FILE}"
echo "Checking for $name updates..." | tee -a "${LOG_FILE}"
local needs_update=false
if [[ "$name" == "NHDDL" || "$name" == "OPL" || "$name" == "POPStarter" ]]; then
if [ -f "$source" ] && [ -f "$destination" ]; then
local src_hash
local dst_hash
src_hash=$(md5sum "$source" | awk '{print $1}')
dst_hash=$(md5sum "$destination" | awk '{print $1}')
if [ "$src_hash" != "$dst_hash" ]; then
needs_update=true
fi
else
needs_update=true
fi
elif [[ "$name" == "Neutrino" ]]; then
if [[ -f "${OPL}/neutrino/version.txt" ]]; then
current_ver=$(<"${OPL}/neutrino/version.txt")
current_ver="${current_ver//v/}" # Remove 'v' from current version
fi
latest_ver=$(<"${NEUTRINO_DIR}/version.txt")
latest_ver="${latest_ver//v/}" # Remove 'v' from latest version
if [[ -n "$current_ver" ]]; then
echo "Current version is $current_ver" | tee -a "${LOG_FILE}"
fi
# Compare versions
if [[ "$(echo -e "$current_ver\n$latest_ver" | sort -V | tail -n 1)" != "$current_ver" ]]; then
needs_update=true
fi
else
local output
output=$(rsync $options --dry-run "$source" "$destination")
if [ $(echo "$output" | wc -l) -ne 1 ]; then
needs_update=true
fi
fi
if [ "$needs_update" = true ]; then
echo "Updating $name..." | tee -a "${LOG_FILE}"
rsync $options "$source" "$destination" >>"${LOG_FILE}" 2>&1
exit_code=${PIPESTATUS[0]}
app_success_check "$name"
else
echo "$name is already up-to-date." | tee -a "${LOG_FILE}"
fi
}
install_pops() {
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __common\n"
COMMANDS+="ls\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
pops_folder=$(echo -e "$COMMANDS" | sudo "${HELPER_DIR}/PFS Shell.elf" 2>/dev/null)
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __common\n"
COMMANDS+="cd POPS\n"
COMMANDS+="ls\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
pops_files=$(echo -e "$COMMANDS" | sudo "${HELPER_DIR}/PFS Shell.elf" 2>/dev/null)
if echo "$pops_folder" | grep -q "POPS/"; then
mkfolder="NO"
else
mkfolder="YES"
fi
if echo "$pops_folder" | grep -q "POPS/" && echo "$pops_files" | grep -q "POPS\.ELF" && echo "$pops_files" | grep -q "IOPRP252\.IMG"; then
echo "POPS-binaries are already installed."| tee -a "${LOG_FILE}"
else
echo "Checking for POPS binaries..." | tee -a "${LOG_FILE}"
# Check POPS files exist
if [[ -f "${ASSETS_DIR}/POPS-binaries-main/POPS.ELF" && -f "${ASSETS_DIR}/POPS-binaries-main/IOPRP252.IMG" ]]; then
echo | tee -a "${LOG_FILE}"
echo "Both POPS.ELF and IOPRP252.IMG exist in ${ASSETS_DIR}." | tee -a "${LOG_FILE}"
echo "Skipping download." | tee -a "${LOG_FILE}"
else
echo "One or both files are missing in ${ASSETS_DIR}." | tee -a "${LOG_FILE}"
# Check if POPS-binaries-main.zip exists
if [[ -f "${ASSETS_DIR}/POPS-binaries-main.zip" && ! -f "${ASSETS_DIR}/POPS-binaries-main.zip.st" ]]; then
echo "POPS-binaries-main.zip found in ${ASSETS_DIR}. Extracting..." | tee -a "${LOG_FILE}"
if ! unzip -o "${ASSETS_DIR}/POPS-binaries-main.zip" -d "${ASSETS_DIR}" >> "${LOG_FILE}" 2>&1; then
error_msg "Warning" "Failed to extract POPS binaries"
fi
else
echo "Downloading POPS binaries..." | tee -a "${LOG_FILE}"
if ! axel -a https://archive.org/download/pops-binaries-PS2/POPS-binaries-main.zip -o "${ASSETS_DIR}"; then
error_msg "Warning" "Failed to download POPS binaries."
fi
if ! unzip -o "${ASSETS_DIR}/POPS-binaries-main.zip" -d "${ASSETS_DIR}" >> "${LOG_FILE}" 2>&1; then
error_msg "Warning" "Failed to extract POPS binaries"
fi
fi
# Check if both POPS.ELF and IOPRP252.IMG exist after extraction
if [[ -f "${ASSETS_DIR}/POPS-binaries-main/POPS.ELF" && -f "${ASSETS_DIR}/POPS-binaries-main/IOPRP252.IMG" ]]; then
echo "POPS binaries successfully extracted." | tee -a "${LOG_FILE}"
else
error_msg "Warning" "One or both files (POPS.ELF, IOPRP252.IMG) are missing after extraction." "Without these files PS1 games will not be playable."
fi
fi
echo "Installing POPS binaries..." | tee -a "${LOG_FILE}"
# Copy POPS files to __common
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __common\n"
if [[ "$mkfolder" == "YES" ]]; then
COMMANDS+="mkdir POPS\n"
fi
COMMANDS+="cd POPS\n"
COMMANDS+="lcd '${TOOLKIT_PATH}/assets/POPS-binaries-main'\n"
COMMANDS+="put POPS.ELF\n"
COMMANDS+="put IOPRP252.IMG\n"
COMMANDS+="cd /\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
PFS_COMMANDS
echo "POPS-binaries successfully installed." | tee -a "${LOG_FILE}"
fi
}
install_elf() {
local dir=$1
# Check if any ELF files exist in the source directory
if ! find "${dir}/APPS" -maxdepth 1 -type f \( -iname "*.elf" \) | grep -q .; then
echo | tee -a "${LOG_FILE}"
echo "No ELF files to install in: ${dir}/APPS" | tee -a "${LOG_FILE}"
else
echo | tee -a "${LOG_FILE}"
echo "Processing ELF files in: ${dir}/APPS/"
for file in "${dir}/APPS/"*.elf "${dir}/APPS/"*.ELF; do
[ -e "$file" ] || continue # Skip if no ELF files exist
# Extract filename without path and extension
elf=$(basename "$file")
elf_no_ext="${elf%.*}"
echo "Installing ${dir}/APPS/$elf..." | tee -a "${LOG_FILE}"
app_name="${elf_no_ext%%(*}" # Remove anything after an open bracket '('
app_name="${app_name%%[Vv][0-9]*}" # Remove versioning (e.g., v12 or V12)
app_name=$(echo "$app_name" | sed -E 's/[cC][oO][mM][pP][rR][eE][sS][sS][eE][dD].*//') # Remove "compressed"
app_name=$(echo "$app_name" | sed -E 's/[pP][aA][cC][kK][eE][dD].*//') # Remove "packed"
app_name=$(echo "$app_name" | sed 's/\.*$//') # Trim trailing full stops
AppDB_check=$(echo "$app_name" | sed 's/[ _-]//g' | tr 'a-z' 'A-Z')
# Check $HELPER_DIR/AppDB.csv for match in first column to $AppDB_check, set $title based on second column from file if found. If no match found, set $title with the remaining code
match=$(awk -F'|' -v key="$AppDB_check" '$1 && index(key, $1) == 1 {print $2; exit}' "$HELPER_DIR/AppDB.csv")
if [[ -n "$match" ]]; then
title="$match"
else
# Use the processed name if no match is found
app_name="${app_name//[_-]/ }" # Replace underscores and hyphens with spaces
app_name="${app_name%"${app_name##*[![:space:]]}"}" # Trim trailing spaces again
app_name=$(echo "$app_name" | sed 's/\.*$//') # Trim trailing full stops again
app_name_before=$(echo "$app_name") # Save the string
app_name=$(echo "$app_name" | sed 's/\([a-z]\)\([A-Z]\)/\1 \2/g') # Add a space before capital letters when preceded by a lowercase letter
# Check if spaces were added by comparing before and after
if [[ "$app_name" != "$app_name_before" ]]; then
space_added=true
else
space_added=false
fi
# Process for title case and exceptions
input_str="$app_name"
# List of terms to ensure spaces before and after
terms=("3d" "3D" "ps2" "PS2" "ps1" "PS1")
# Loop over the terms
for term in "${terms[@]}"; do
input_str="${input_str//${term}/ ${term}}" # Ensure space before the term
input_str="${input_str//${term}/${term} }" # Ensure space after the term
done
# Special case for "hdd" and "HDD" - add spaces only if the string is longer than 5 characters
if [[ ${#input_str} -gt 5 ]]; then
input_str="${input_str//hdd/ hdd }"
input_str="${input_str//HDD/ HDD }"
fi
# Check if the string contains any lowercase letters
if ! echo "$input_str" | grep -q '[a-z]'; then
input_str="${input_str,,}" # Convert the entire string to lowercase
fi
result=""
# Define words to exclude from uppercase conversion (only consonant-only words)
exclude_list="by cry cyst crypt dry fly fry glyph gym gypsy hymn lynx my myth myrrh ply pry rhythm shy sky spy sly sty sync tryst why wry"
# Now process each word
for word in $input_str; do
# Handle words 3 characters or shorter, but only if no space was added by sed
if [[ ${#word} -le 3 ]] && ! $space_added && ! echo "$exclude_list" | grep -wi -q "$word"; then
result+=" ${word^^}" # Convert to uppercase
# Handle consonant-only words (only if not in exclusion list)
elif [[ "$word" =~ ^[b-df-hj-np-tv-z0-9]+$ ]] && ! echo "$exclude_list" | grep -w -q "$word"; then
result+=" ${word^^}" # Uppercase if the word is consonant-only and not in the exclusion list
else
result+=" ${word^}" # Capitalize first letter for all other words
fi
title="${result# }"
done
# Remove leading space and ensure no double spaces are left
result="${result#"${result%%[![:space:]]*}"}" # Remove leading spaces
title=$(echo "$result" | sed 's/ / /g') # Replace double spaces with single spaces
fi
title_id=$(echo "$title" | tr '[:lower:]' '[:upper:]' | tr -cd 'A-Z0-9' | cut -c1-11) # Replace spaces with underscores & capitalize
# Create the new folder in the destination directory
elf_dir="${dir}/APPS/$title_id"
if [[ $title_id == "WLE" ]] || [[ $title_id == "DISC" ]]; then
error_msg "Error" "The filename $elf cannot be used. Please rename $file and try again."
else
mkdir -p "${elf_dir}" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create directory $elf_dir."
fi
if [[ $dir == $GAMES_PATH ]]; then
cp "${dir}/APPS/$elf" "${elf_dir}" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to copy $elf to $elf_dir."
elif [[ $dir == $OPL ]]; then
mv "${dir}/APPS/$elf" "${elf_dir}" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to move $elf to $elf_dir."
fi
if [[ "$title_id" == "LAUNCHDISC" ]]; then
publisher="github.com/cosmicscale"
elif [[ "$title_id" == "HDDOSD" ]]; then
publisher="Sony Computer Entertainment"
elif [[ "$title_id" == "LAUNCHELF" ]]; then
publisher="github.com/ps2homebrew"
fi
cat > "${elf_dir}/title.cfg" <<EOL
title=$title
boot=$elf
Title=$title
CfgVersion=8
Developer=$publisher
Genre=Homebrew
EOL
done
fi
}
activate_python() {
echo >> "${LOG_FILE}"
echo "Activating Python virtual environment..." >> "${LOG_FILE}"
echo
echo -n "Preparing to $INSTALL_TYPE PS2 games..."
sleep 5
echo | tee -a "${LOG_FILE}"
# Try activating the virtual environment twice before failing
if ! source "${TOOLKIT_PATH}/venv/bin/activate" 2>>"${LOG_FILE}"; then
echo -n "Failed to activate the Python virtual environment. Retrying..." | tee -a "${LOG_FILE}"
sleep 2
echo | tee -a "${LOG_FILE}"
if ! source "${TOOLKIT_PATH}/venv/bin/activate" 2>>"${LOG_FILE}"; then
error_msg "Error" "Failed to activate the Python virtual environment."
fi
fi
}
convert_zso() {
if [[ "$LAUNCHER" != "NEUTRINO" ]]; then
return
fi
if [[ "$INSTALL_TYPE" == "sync" ]]; then
search_dirs=("${GAMES_PATH}/CD" "${GAMES_PATH}/DVD")
else
search_dirs=("${GAMES_PATH}/CD" "${GAMES_PATH}/DVD" "${OPL}/CD" "${OPL}/DVD")
fi
# Only run if .zso files exist
if find "${search_dirs[@]}" -type f -iname "*.zso" | grep -q .; then
error_msg "Warning" "Games in the compressed ZSO format have been found." "Neutrino does not support compressed ZSO files." " " "ZSO files will be converted to ISO files before proceeding."
# Convert ZSO to ISO
while IFS= read -r -d '' zso_file; do
iso_file="${zso_file%.*}.iso"
echo "Converting: $zso_file -> $iso_file" | tee -a "${LOG_FILE}"
python3 -u "${HELPER_DIR}/ziso.py" -c 0 "$zso_file" "$iso_file" | tee -a "${LOG_FILE}"
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
rm -f "$iso_file"
error_msg "Error" "Failed to uncompress $zso_file"
fi
rm -f "$zso_file"
done < <(find "${search_dirs[@]}" -type f -iname "*.zso" -print0)
fi
}
PP_NAME() {
# Format game id correctly for partition
title_id=$(echo "$game_id" | sed -E 's/_(...)\./-\1/;s/\.//')
# Sanitize title by keeping only uppercase A-Z, 0-9, and underscores, and removing any trailing underscores
sanitized_title=$(echo "$title" | sed 's/²/2/g; s/³/3/g' | iconv -f UTF-8 -t ASCII//TRANSLIT | tr 'a-z' 'A-Z' | sed 's/[^A-Z0-9]/_/g' | sed 's/^_//; s/_$//; s/__*/_/g')
PARTITION_LABEL=$(printf "PP.%s.%s" "$title_id" "$sanitized_title" | cut -c 1-32 | sed 's/_$//')
}
create_info_sys() {
local title="$1"
local title_id="$2"
local publisher="$3"
local content_type="255"
if [ "$title_id" = "PSBBN" ]; then
content_type="0"
fi
cat > "$info_sys_filename" <<EOL
title = $title
title_id = $title_id
title_sub_id = 0
release_date =
developer_id =
publisher_id = $publisher
note =
content_web =
image_topviewflag = 0
image_type = 0
image_count = 1
image_viewsec = 600
copyright_viewflag = 0
copyright_imgcount = 0
genre =
parental_lock = 1
effective_date = 0
expire_date = 0
violence_flag = 0
content_type = $content_type
content_subtype = 0
EOL
if [ -f "$info_sys_filename" ]; then
echo "Created: $info_sys_filename" | tee -a "${LOG_FILE}"
else
error_msg "Error" "Failed to create $info_sys_filename"
fi
}
create_icon_sys() {
local title="$1"
local publisher="$2"
cat > "$icon_sys_filename" <<EOL
PS2X
title0=$title
title1=$publisher
bgcola=0
bgcol0=0,0,0
bgcol1=0,0,0
bgcol2=0,0,0
bgcol3=0,0,0
lightdir0=1.0,-1.0,1.0
lightdir1=-1.0,1.0,-1.0
lightdir2=0.0,0.0,0.0
lightcolamb=64,64,64
lightcol0=64,64,64
lightcol1=16,16,16
lightcol2=0,0,0
uninstallmes0=
uninstallmes1=
uninstallmes2=
EOL
if [ -f "$icon_sys_filename" ]; then
echo "Created: $icon_sys_filename" | tee -a "${LOG_FILE}"
else
error_msg "Error" "Failed to create $icon_sys_filename"
fi
}
create_bbnl_cfg() {
local file_name="$1"
local title_id="$2"
local arg="$3"
{
echo "file_name=$file_name"
echo "title_id=$title_id"
echo "launcher=ELF"
if [ -n "$arg" ]; then
echo "arg=$arg"
fi
} > "$bbnl_cfg"
if [ -f "$bbnl_cfg" ]; then
echo "Created: $bbnl_cfg" | tee -a "${LOG_FILE}"
else
error_msg "Error" "Failed to create $bbnl_cfg"
fi
}
APP_ART() {
png_file="${ARTWORK_DIR}/${title_id}.png"
# Copy the matching PNG file from ART_DIR, or default to APP.png
if [ -f "$png_file" ]; then
cp "$png_file" "$dir/jkt_001.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/jkt_001.png. See ${LOG_FILE} for details."
echo "Created: $dir/jkt_001.png" | tee -a "${LOG_FILE}"
cp "$png_file" "${GAMES_PATH}/ART/${elf}_COV.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create ${GAMES_PATH}/ART/${elf}_COV.png. See ${LOG_FILE} for details."
echo "Created: ${GAMES_PATH}/ART/${elf}_COV.png" | tee -a "${LOG_FILE}"
else
echo "Artwork not found locally for $title_id. Attempting to download from the PSBBN art database..." | tee -a "${LOG_FILE}"
wget --quiet --timeout=10 --tries=3 --output-document="$png_file" \
"https://raw.githubusercontent.com/CosmicScale/psbbn-art-database/main/apps/${title_id}.png"
if [[ -s "$png_file" ]]; then
echo "Successfully downloaded artwork for $title_id" | tee -a "${LOG_FILE}"
cp "$png_file" "$dir/jkt_001.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/jkt_001.png. See ${LOG_FILE} for details."
echo "Created: $dir/jkt_001.png" | tee -a "${LOG_FILE}"
cp "$png_file" "${GAMES_PATH}/ART/${elf}_COV.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create ${GAMES_PATH}/ART/${elf}_COV.png. See ${LOG_FILE} for details."
echo "Created: ${GAMES_PATH}/ART/${elf}_COV.png" | tee -a "${LOG_FILE}"
else
rm -f "$png_file"
cp "$ARTWORK_DIR/APP.png" "$dir/jkt_001.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/jkt_001.png. See ${LOG_FILE} for details."
echo "Created: $dir/jkt_001.png using default image." | tee -a "${LOG_FILE}"
echo "$title_id,$title,$elf" >> "${MISSING_APP_ART}"
fi
fi
}
SPLASH() {
clear
echo " _____ _____ _ _ _ ";
echo " | __ \ |_ _| | | | | | ";
echo " | | \/ __ _ _ __ ___ ___ | | _ __ ___| |_ __ _| | | ___ ___ ";
echo " | | __ / _\` | '_ \` _ \ / _ \ | || '_ \/ __| __/ _\` | | |/ _ \ __|";
echo " | |_\ \ (_| | | | | | | __/ _| || | | \__ \ || (_| | | | __/ | ";
echo " \____/\__,_|_| |_| |_|\___| \___/_| |_|___/\__\__,_|_|_|\___|_| ";
echo " ";
echo " Written by CosmicScale"
echo
echo
echo
}
SPLASH
if [[ "$(uname -m)" != "x86_64" ]]; then
error_msg "Error" "Unsupported CPU architecture: $(uname -m). This script requires x86-64."
fi
# Check if the helper files exists
if [[ ! -f "${HELPER_DIR}/PFS Shell.elf" || ! -f "${HELPER_DIR}/HDL Dump.elf" ]]; then
error_msg "Error" "Helper files not found. Scripts must be from the 'PSBBN-Definitive-English-Patch' directory."
fi
if ! echo "########################################################################################################" | tee -a "${LOG_FILE}" >/dev/null 2>&1; then
sudo rm -f "${LOG_FILE}"
if ! echo "########################################################################################################" | tee -a "${LOG_FILE}" >/dev/null 2>&1; then
echo
echo "Error: Cannot create log file."
echo
read -n 1 -s -r -p "Press any key to exit..."
echo
exit 1
fi
fi
date >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
clean_up
sudo rm -f "${MISSING_ART}" "${MISSING_APP_ART}" ${MISSING_ICON} 2>>"${LOG_FILE}" || error_msg "Error" "Failed to remove missing artwork files. See ${LOG_FILE} for details."
# Check if the current directory is a Git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "This is not a Git repository. Skipping update check." | tee -a "${LOG_FILE}"
else
# Fetch updates from the remote
git fetch >> "${LOG_FILE}" 2>&1
# Check the current status of the repository
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse @{u})
BASE=$(git merge-base @ @{u})
if [ "$LOCAL" = "$REMOTE" ]; then
echo "The repository is up to date." | tee -a "${LOG_FILE}"
else
echo "Downloading updates..."
# Get a list of files that have changed remotely
UPDATED_FILES=$(git diff --name-only "$LOCAL" "$REMOTE")
if [ -n "$UPDATED_FILES" ]; then
echo "Files updated in the remote repository:" | tee -a "${LOG_FILE}"
echo "$UPDATED_FILES" | tee -a "${LOG_FILE}"
# Reset only the files that were updated remotely (discard local changes to them)
echo "$UPDATED_FILES" | xargs git checkout -- >> "${LOG_FILE}" 2>&1
# Pull the latest changes
if ! git pull --ff-only >> "${LOG_FILE}" 2>&1; then
error_msg "Error" "Update failed. Delete the PSBBN-Definitive-English-Patch directory and run the command:" " " "git clone https://github.com/CosmicScale/PSBBN-Definitive-English-Patch.git" " " "Then try running the script again."
fi
echo
echo "The repository has been successfully updated." | tee -a "${LOG_FILE}"
read -n 1 -s -r -p "Press any key to exit, then run the script again."
echo
exit 0
fi
fi
fi
echo "Tootkit path: $TOOLKIT_PATH" >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
cat /etc/*-release >> "${LOG_FILE}" 2>&1
echo >> "${LOG_FILE}"
DEVICE=$(sudo blkid -t TYPE=exfat | grep OPL | awk -F: '{print $1}' | sed 's/[0-9]*$//')
if [[ -z "$DEVICE" ]]; then
error_msg "Error" "Unable to detect PS2 drive."
fi
echo "OPL partition found on $DEVICE" >> "${LOG_FILE}"
# Find all mounted volumes associated with the device
mounted_volumes=$(lsblk -ln -o MOUNTPOINT "$DEVICE" | grep -v "^$")
# Iterate through each mounted volume and unmount it
echo "Unmounting volumes associated with $DEVICE..." >> "${LOG_FILE}"
for mount_point in $mounted_volumes; do
echo "Unmounting $mount_point..." >> "${LOG_FILE}"
if sudo umount "$mount_point"; then
echo "Successfully unmounted $mount_point." >> "${LOG_FILE}"
else
error_msg "Error" "Failed to unmount $mount_point. Please unmount manually."
fi
done
HDL_TOC
MOUNT_OPL
psbbn_version=$(head -n 1 "$OPL/version.txt" 2>/dev/null)
# Compare using sort -V
if [ "$(printf '%s\n' "$psbbn_version" "$version_check" | sort -V | head -n1)" != "$version_check" ]; then
error_msg "Warning" "PSBBN Definitive Patch version is lower than the recommended version ($version_check)." " " "Update to the latest version by running the 02-PSBBN-Installer.sh script, or press any key to" "proceed with caution."
rm -f "${OPL}/conf_apps.cfg" || error_msg "Error" "Failed to delete ${OPL}/conf_apps.cfg."
fi
# Check if the Python virtual environment exists
if [ -f "./venv/bin/activate" ]; then
echo "The Python virtual environment exists." >> "${LOG_FILE}"
else
error_msg "Error" "The Python virtual environment does not exist. Run 01-Setup.sh and try again."
fi
if [[ -f "$CONFIG_FILE" && -s "$CONFIG_FILE" ]]; then
cfg_path="$(<"$CONFIG_FILE")"
if [[ -d "$cfg_path" ]]; then
GAMES_PATH="$cfg_path"
fi
fi
echo
echo "Games folder: $GAMES_PATH" | tee -a "${LOG_FILE}"
echo
while true; do
read -p "Would you like to change the location of the local games folder? (y/n): " answer
case "$answer" in
[Yy])
echo
read -p "Enter new path for games folder: " new_path
if [[ -d "$new_path" ]]; then
# Remove trailing slash unless it's the root directory
new_path="${new_path%/}"
[[ "$new_path" == "" ]] && new_path="/"
GAMES_PATH="$new_path"
echo "$GAMES_PATH" > "$CONFIG_FILE"
break
else
echo "Invalid path. Please try again." | tee -a "${LOG_FILE}"
echo
fi
;;
[Nn])
break
;;
*)
echo
echo "Please enter y or n."
;;
esac
done
# Create necessary folders if they don't exist
for folder in APPS ART CFG CHT LNG THM VMC POPS CD DVD; do
dir="${GAMES_PATH}/${folder}"
[[ -d "$dir" ]] || mkdir -p "$dir" || {
error_msg "Error" "Failed to create $dir. Make sure you have write permissions to $GAMES_PATH"
}
done
# Check if GAMES_PATH is custom
if [[ "${GAMES_PATH}" != "${TOOLKIT_PATH}/games" ]]; then
echo "Using custom game path." >> "${LOG_FILE}"
cp "${TOOLKIT_PATH}/games/APPS/"{BOOT.ELF,Launch-Disc.elf,HDD-OSD.elf,PSBBN.ELF} "${GAMES_PATH}/APPS" >> "${LOG_FILE}" 2>&1
else
echo "Using default game path." >> "${LOG_FILE}"
fi
POPS_FOLDER="${GAMES_PATH}/POPS"
SPLASH
echo "Choose an install option:"
echo
echo " 1) Synchronize All Games and Apps:"
echo
echo " - Installs all games and apps currently found in the games folder on your PC."
echo " - Deletes any games or apps from the PS2 drive that are not present in the"
echo " games folder, ensuring the PS2 drive matches the contents of your PC."
echo
echo " WARNING: Any games and apps that are not in the games folder on your PC will be"
echo " permanently removed from the PS2 drive during synchronization."
echo
echo " 2) Add Additional Games and Apps:"
echo
echo " - Installs new games and apps found in the games folder on your PC."
echo " - Scans for newly added or removed games and apps, then updates the game list"
echo " in the PSBBN Game Collection and HDD-OSD accordingly."
echo
while true; do
read -p "Enter 1 or 2: " choice
case "$choice" in
1) INSTALL_TYPE="sync" DESC1="Synchronize"; break ;;
2) INSTALL_TYPE="copy" DESC1="Add Games and Apps"; break ;;
*) echo; echo "Invalid choice. Please enter 1 or 2." ;;
esac
done
if [ "$INSTALL_TYPE" = "sync" ] && \
! find "${GAMES_PATH}/POPS" -maxdepth 1 -type f -iname "*.vcd" | grep -q . && \
! find "${GAMES_PATH}/CD" -maxdepth 1 -type f \( -iname "*.iso" -o -iname "*.zso" \) | grep -q . && \
! find "${GAMES_PATH}/DVD" -maxdepth 1 -type f \( -iname "*.iso" -o -iname "*.zso" \) | grep -q .; then
echo
echo "Warning: No games found in the games folder: ${GAMES_PATH}"
echo "All games on the PS2 drive will be deleted."
echo
while true; do
read -p "Are you sure you wish to continue? (y/n): " confirm
case "$confirm" in
[Yy]) break ;;
[Nn]) echo "Operation cancelled."; exit 1 ;;
*) echo; echo "Please enter y or n." ;;
esac
done
fi
SPLASH
echo "Please choose a game launcher:"
echo
echo " 1) Open PS2 Loader (OPL)"
echo
echo " - 100% open-source game and application loader:"
echo " https://github.com/ps2homebrew/Open-PS2-Loader"
echo
echo " 2) Neutrino"
echo
echo " - Small, fast, and modular PS2 device emulator:"
echo " https://github.com/rickgaiser/neutrino"
echo
while true; do
read -p "Enter 1 or 2: " choice
case "$choice" in
1) LAUNCHER="OPL"; DESC2="Open PS2 Loader (OPL)"; break ;;
2) LAUNCHER="NEUTRINO"; DESC2="Neutrino"; break ;;
*) echo; echo "Invalid choice. Please enter 1 or 2." ;;
esac
done
SPLASH
echo "PS2 drive detected: $DEVICE" | tee -a "${LOG_FILE}"
echo "Games folder: $GAMES_PATH" | tee -a "${LOG_FILE}"
echo "Install type: $DESC1" | tee -a "${LOG_FILE}"
echo "Game launcher: $DESC2" | tee -a "${LOG_FILE}"
echo
read -n 1 -s -r -p "Press any key to continue..."
echo
prevent_sleep_start
# Delete existing BBL partitions
HDL_TOC
delete_partition=$(grep -o 'PP\.[^ ]\+' "$hdl_output")
echo >> "${LOG_FILE}"
echo "Existing PP Partitions:" >> "${LOG_FILE}"
echo "$delete_partition" >> "${LOG_FILE}"
if [ -n "$delete_partition" ]; then
COMMANDS="device ${DEVICE}\n"
while IFS= read -r partition; do
COMMANDS+="rmpart ${partition}\n"
done <<< "$delete_partition"
COMMANDS+="exit"
echo | tee -a "${LOG_FILE}"
echo "Deleting PP partitions..." | tee -a "${LOG_FILE}"
PFS_COMMANDS
HDL_TOC
delete_partition=$(grep -o 'PP\.[^ ]\+' "$hdl_output")
if [ -n "$delete_partition" ]; then
echo "Unable to delete the following partitions:"
echo $delete_partition
error_msg "Error" "Failed to delete existing PP partitions."
else
echo "Existing PP partitions sucessfully deleted." | tee -a "${LOG_FILE}"
fi
else
echo "No PP partitions to delete." | tee -a "${LOG_FILE}"
fi
update_apps "POPStarter" "${POPSTARTER}" "${OPL}/bbnl/POPSTARTER.ELF" "-ut --progress"
install_pops
update_apps "OPL" "${ASSETS_DIR}/OPL/OPNPS2LD.ELF" "${OPL}/bbnl/OPNPS2LD.ELF" "-ut --progress"
update_apps "NHDDL" "${ASSETS_DIR}/NHDDL/nhddl.elf" "${OPL}/bbnl/nhddl.elf" "-ut --progress"
update_apps "Neutrino" "${NEUTRINO_DIR}/" "${OPL}/neutrino/" "-rut --progress --delete --exclude='.*'"
################################### Synchronize Games & Apps ###################################
if [ "$INSTALL_TYPE" = "sync" ]; then
echo | tee -a "${LOG_FILE}"
echo "Preparing to sync apps..." | tee -a "${LOG_FILE}"
cd "${GAMES_PATH}/APPS/" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to ${GAMES_PATH}/APPS."
process_psu_files "${GAMES_PATH}/APPS/"
install_elf "${GAMES_PATH}"
rsync -rut --progress --delete --exclude='.*' "${GAMES_PATH}/APPS/" "${OPL}/APPS/" >> "${LOG_FILE}" 2>&1 || error_msg "Error" "Failed sync apps. See $LOG_FILE for details."
find "${OPL}/APPS/" -maxdepth 1 -type f -exec rm -f {} + 2>>"${LOG_FILE}" || error_msg "Error" "Failed to tidy up OPL/APPS/"
POPS_SYNC
activate_python
convert_zso
OPL_SIZE_CKECK
cd=$(rsync -rL --progress --ignore-existing --delete --exclude='.*' --dry-run "${GAMES_PATH}/CD/" "${OPL}/CD/")
dvd=$(rsync -rL --progress --ignore-existing --delete --exclude='.*' --dry-run "${GAMES_PATH}/DVD/" "${OPL}/DVD/")
# Check if either output contains more than one line
if [ $(echo "$cd" | wc -l) -ne 1 ] || [ $(echo "$dvd" | wc -l) -ne 1 ]; then
needs_update=true
fi
if [ "$needs_update" = true ]; then
echo "Total size of PS2 games to be synced: $needed_mb MB" | tee -a "${LOG_FILE}"
echo "Available space: $available_mb MB" | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
echo "Syncing PS2 games..." | tee -a "${LOG_FILE}"
rsync -rL --progress --ignore-existing --delete --exclude='.*' "${GAMES_PATH}/CD/" "${OPL}/CD/" 2>>"${LOG_FILE}" | tee -a "${LOG_FILE}"
cd_status=${PIPESTATUS[0]}
rsync -rL --progress --ignore-existing --delete --exclude='.*' "${GAMES_PATH}/DVD/" "${OPL}/DVD/" 2>>"${LOG_FILE}" | tee -a "${LOG_FILE}"
dvd_status=${PIPESTATUS[0]}
ps2_rsync_check Synced
else
echo "PS2 games are already up-to-date." | tee -a "${LOG_FILE}"
fi
################################### Add Games & Apps ###################################
elif [ "$INSTALL_TYPE" = "copy" ]; then
echo | tee -a "${LOG_FILE}"
echo "Preparing to copy apps..." | tee -a "${LOG_FILE}"
cd "${OPL}/APPS/" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to ${OPL}/APPS."
process_psu_files "${GAMES_PATH}/APPS/"
process_psu_files "${OPL}/APPS/"
install_elf "${GAMES_PATH}"
install_elf "${OPL}"
find "${GAMES_PATH}/APPS/" -mindepth 1 -maxdepth 1 -type d -exec cp -r {} "${OPL}/APPS/" \; || error_msg "Error" "Failed copy apps. See $LOG_FILE for details."
POPS_SYNC
activate_python
convert_zso
OPL_SIZE_CKECK
if (( needed_mb > 0 )); then
echo "Total size of PS2 games to be copied: $needed_mb MB" | tee -a "${LOG_FILE}"
echo "Available space: $available_mb MB" | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
echo "Copying PS2 games..."
# Update PS2 CD games
rsync -rL --progress --ignore-existing --exclude=".*" "${GAMES_PATH}/CD/" "${OPL}/CD/" 2>>"${LOG_FILE}" | tee -a "${LOG_FILE}"
cd_status=${PIPESTATUS[0]}
# Update PS2 DVD games
rsync -rL --progress --ignore-existing --exclude=".*" "${GAMES_PATH}/DVD/" "${OPL}/DVD/" 2>>"${LOG_FILE}" | tee -a "${LOG_FILE}"
dvd_status=${PIPESTATUS[0]}
ps2_rsync_check copied
else
echo "No PS2 games to copy." | tee -a "${LOG_FILE}"
fi
fi
# Sends a list of apps and games synced/copied to the log file
echo >> "${LOG_FILE}"
echo "APPS on PS2 drive:" >> "${LOG_FILE}"
ls -1 "${OPL}/APPS/" >> "${LOG_FILE}" 2>&1
echo >> "${LOG_FILE}"
echo "PS1 games on PS2 drive:" >> "${LOG_FILE}"
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mount __.POPS\n"
COMMANDS+="ls\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
echo -e "$COMMANDS" | sudo "${HELPER_DIR}/PFS Shell.elf" 2>&1 | grep -i '\.vcd$' >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
echo "PS2 games on PS2 drive:" >> "${LOG_FILE}"
ls -1 "${OPL}/CD/" >> "${LOG_FILE}" 2>&1
ls -1 "${OPL}/DVD/" >> "${LOG_FILE}" 2>&1
# Create games list of PS1 and PS2 games to be installed
if find "${GAMES_PATH}/POPS" -maxdepth 1 -type f \( -iname "*.vcd" \) | grep -q .; then
echo | tee -a "${LOG_FILE}"
echo "Creating PS1 games list..." | tee -a "${LOG_FILE}"
python3 -u "${HELPER_DIR}/list-builder.py" "${GAMES_PATH}" "${PS1_LIST}" | tee -a "${LOG_FILE}"
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
error_msg "Error" "Failed to create PS1 games list."
fi
fi
if find "${OPL}/CD" "${OPL}/DVD" -maxdepth 1 -type f \( -iname "*.iso" -o -iname "*.zso" \) | grep -q .; then
echo | tee -a "${LOG_FILE}"
echo "Creating PS2 games list..." | tee -a "${LOG_FILE}"
python3 -u "${HELPER_DIR}/list-builder.py" "${OPL}" "${PS2_LIST}" | tee -a "${LOG_FILE}"
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
error_msg "Error" "Failed to create PS2 games list."
fi
fi
if [[ "$INSTALL_TYPE" = "copy" && -f "${OPL}/ps1.list" ]]; then
cat "${OPL}/ps1.list" >> "${PS1_LIST}"
# Remove duplicate lines
sort -u "${PS1_LIST}" -o "${PS1_LIST}"
fi
if [ -f "${PS1_LIST}" ]; then
python3 "${HELPER_DIR}/list-sorter.py" "${PS1_LIST}" || error_msg "Error" "Failed to sort PS1 games list."
fi
if [ -f "${PS2_LIST}" ]; then
python3 "${HELPER_DIR}/list-sorter.py" "${PS2_LIST}" || error_msg "Error" "Failed to sort PS2 games list."
fi
# Deactivate the virtual environment
deactivate
# Create master list combining PS1 and PS2 games to a single list
if [[ ! -f "${PS1_LIST}" && ! -f "${PS2_LIST}" ]] && find "${GAMES_PATH}/CD" "${GAMES_PATH}/DVD" -maxdepth 1 -type f \( -iname "*.iso" -o -iname "*.zso" \) | grep -q .; then
error_msg "Error" "Failed to create games list."
fi
if [[ -f "${PS1_LIST}" ]] && [[ ! -f "${PS2_LIST}" ]]; then
{ cat "${PS1_LIST}" > "${ALL_GAMES}"; } 2>> "${LOG_FILE}"
elif [[ ! -f "${PS1_LIST}" ]] && [[ -f "${PS2_LIST}" ]]; then
{ cat "${PS2_LIST}" >> "${ALL_GAMES}"; } 2>> "${LOG_FILE}"
elif [[ -f "${PS1_LIST}" ]] && [[ -f "${PS2_LIST}" ]]; then
{ cat "${PS1_LIST}" > "${ALL_GAMES}"; } 2>> "${LOG_FILE}"
{ cat "${PS2_LIST}" >> "${ALL_GAMES}"; } 2>> "${LOG_FILE}"
fi
rm -f "${OPL}/ps1.list"
# Check for master.list
if [[ -s "${ALL_GAMES}" ]]; then
# Count the number of games to be installed
[ -f "$PS1_LIST" ] && ! cp "${PS1_LIST}" "${OPL}" && error_msg "Error" "Failed to copy $PS1_LIST to ${OPL}"
count=$(grep -c '^[^[:space:]]' "${ALL_GAMES}")
echo | tee -a "${LOG_FILE}"
echo "Number of games to install: $count" | tee -a "${LOG_FILE}"
echo
echo "Games list successfully created."| tee -a "${LOG_FILE}"
echo >> "${LOG_FILE}"
echo "master.list:" >> "${LOG_FILE}"
cat "${ALL_GAMES}" >> "${LOG_FILE}"
fi
################################### Creating Assets ###################################
echo
echo -n "Preparing to create assets..."
echo | tee -a "${LOG_FILE}"
mkdir -p "${ICONS_DIR}/bbnl" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create ${ICONS_DIR}/bbnl."
mkdir -p "${ICONS_DIR}/SAS" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create ${ICONS_DIR}/SAS."
mkdir -p "${ICONS_DIR}/APPS" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create ${ICONS_DIR}/APPS."
mkdir -p "${ARTWORK_DIR}/tmp" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create ${ARTWORK_DIR}/tmp."
mkdir -p "${TOOLKIT_PATH}/icons/ico/tmp" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create ${TOOLKIT_PATH}/icons/ico/tmp."
# Set maximum number of items for the Game Channel (799 + 1 for chosen launcher)
pp_cap="799"
################################### Assets for SAS Apps ###################################
SOURCE_DIR="${OPL}/APPS"
APA_SIZE_CHECK
if [ "$pp_max" -gt "$pp_cap" ]; then
pp_max="$pp_cap"
fi
echo "Max Partitions: $pp_max" >> "${LOG_FILE}"
SAS_COUNT="0"
for dir in "${SOURCE_DIR}"/*/; do
[[ -d "$dir" ]] || continue
# Stop if we've reached the limit
if [ "$SAS_COUNT" -ge "$pp_max" ]; then
error_msg "Warning" "Insufficient space to create BBL partitions for remaining SAS apps." " " "The first $pp_max apps will appear in the PSBBN Game Channel." "All apps will appear in OPL."
break
fi
# Check for .elf/.ELF file
if find "$dir" -maxdepth 1 -type f -iname "*.elf" | grep -q . && \
[[ -f "$dir/icon.sys" && -f "$dir/title.cfg" ]]; then
cp -r "$dir" "${ICONS_DIR}/SAS" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to copy $dir. See ${LOG_FILE} for details."
SAS_COUNT=$((SAS_COUNT + 1))
fi
done
if ! find "${ICONS_DIR}/SAS" -mindepth 1 -maxdepth 1 -type d ! -name '.*' | grep -q .; then
echo | tee -a "${LOG_FILE}"
echo "No SAS apps to process." | tee -a "${LOG_FILE}"
else
echo | tee -a "${LOG_FILE}"
echo "Creating Assets for SAS Apps:" | tee -a "${LOG_FILE}"
# Loop through each folder in the 'SAS' directory, sorted in reverse alphabetical order
while IFS= read -r dir; do
title_id=$(basename "$dir")
echo | tee -a "${LOG_FILE}"
if [ -f "$dir/list.icn" ]; then
echo "Processing $title_id..." | tee -a "${LOG_FILE}"
mv "$dir/list.icn" "$dir/list.ico" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to convert $dir/list.icn."
echo "Converted list.icn: $dir/list.ico" | tee -a "${LOG_FILE}"
[ -f "$dir/del.icn" ] && mv "$dir/del.icn" "$dir/del.ico" | echo "Converted del.icn: $dir/del.ico" | tee -a "${LOG_FILE}"
else
echo "list.icn not found in $dir." | tee -a "${LOG_FILE}"
cp "${ICONS_DIR}/ico/app.ico" "$dir/list.ico" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create $dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $dir/list.ico using default icon."
cp "${ICONS_DIR}/ico/app-del.ico" "$dir/del.ico" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create $dir/del.ico. See ${LOG_FILE} for details."
echo "Created: $dir/del.ico using default icon."
fi
# Convert the icon.sys file
icon_sys_filename="$dir/icon.sys"
python3 "${HELPER_DIR}/icon_sys_to_txt.py" "$icon_sys_filename" >> "${LOG_FILE}" 2>&1
mv "$dir/icon.txt" "$icon_sys_filename" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to convert $icon_sys_filename"
echo "Converted icon.sys: $icon_sys_filename" | tee -a "${LOG_FILE}"
while IFS='=' read -r key value; do
key=$(echo "$key" | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
value=$(echo "$value" | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
# Remove non-ASCII and non-printable characters
value=$(printf '%s' "$value" | LC_ALL=C tr -cd '\40-\176')
case "$key" in
title) title="$value" ;;
boot) elf="$value" ;;
Developer) publisher="$value" ;;
esac
done < "$dir/title.cfg"
# Generate the info.sys file
info_sys_filename="$dir/info.sys"
create_info_sys "$title" "$title_id" "$publisher"
APP_ART
# Generate the bbnl cfg file
bbnl_cfg="${ICONS_DIR}/bbnl/$title_id.cfg"
create_bbnl_cfg "/APPS/$title_id/$elf" "$title_id"
cp "${ASSETS_DIR}/BBNL"/{boot.kelf,system.cnf} "$dir" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create boot.kelf or system.cnf. See ${LOG_FILE} for details."
echo "Created: $dir/boot.kelf" | tee -a "${LOG_FILE}"
echo "Created: $dir/system.cnf" | tee -a "${LOG_FILE}"
done < <(find "${ICONS_DIR}/SAS" -mindepth 1 -maxdepth 1 -type d | sort)
fi
################################### Assets for ELF Files ###################################
pp_max=$(( pp_max - SAS_COUNT ))
echo "PP Max after SAS: $pp_max"
APP_COUNT=0
for dir in "${SOURCE_DIR}"/*/; do
[[ -d "$dir" ]] || continue
# Stop if we've reached the max
if [ "$APP_COUNT" -ge "$pp_max" ]; then
error_msg "Warning" "Insufficient space to create BBL partitions for remaining ELF files." " " "The first $pp_max apps will appear in the PSBBN Game Channel." "All apps will appear in OPL."
break
fi
# Check for .elf/.ELF file
if find "$dir" -maxdepth 1 -type f -iname "*.elf" | grep -q . && \
[[ ! -f "$dir/icon.sys" && -f "$dir/title.cfg" ]]; then
cp -r "$dir" "${ICONS_DIR}/APPS" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to copy $dir. See ${LOG_FILE} for details."
APP_COUNT=$((APP_COUNT + 1))
fi
done
if ! find "${ICONS_DIR}/APPS" -mindepth 1 -maxdepth 1 -type d ! -name '.*' | grep -q .; then
echo | tee -a "${LOG_FILE}"
echo "No ELF files to process." | tee -a "${LOG_FILE}"
else
echo | tee -a "${LOG_FILE}"
echo "Creating Assets for ELF files:" | tee -a "${LOG_FILE}"
# Loop through each folder in the 'APPS' directory, sorted in reverse alphabetical order
while IFS= read -r dir; do
title_id=$(basename "$dir")
while IFS='=' read -r key value; do
key=$(echo "$key" | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
value=$(echo "$value" | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
# Remove non-ASCII and non-printable characters
value=$(printf '%s' "$value" | LC_ALL=C tr -cd '\40-\176')
case "$key" in
title) title="$value" ;;
boot) elf="$value" ;;
Developer) publisher="$value" ;;
esac
done < "$dir/title.cfg"
echo | tee -a "${LOG_FILE}"
info_sys_filename="$dir/info.sys"
create_info_sys "$title" "$title_id" "$publisher"
# Generate the icon.sys file
icon_sys_filename="$dir/icon.sys"
create_icon_sys "$title"
if [[ "$title_id" == "LAUNCHELF" ]]; then
cp "${ICONS_DIR}/ico/wle.ico" "$dir/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $dir/list.ico" | tee -a "${LOG_FILE}"
cp "${ICONS_DIR}/ico/wle-del.ico" "$dir/del.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/del.ico. See ${LOG_FILE} for details."
echo "Created: $dir/del.ico" | tee -a "${LOG_FILE}"
elif [[ "$title_id" == "PSBBN" ]]; then
cp "${ICONS_DIR}/ico/psbbn.ico" "$dir/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $dir/list.ico" | tee -a "${LOG_FILE}"
elif [[ "$title_id" == "HDDOSD" ]]; then
cp "${ICONS_DIR}/ico/hdd-osd.ico" "$dir/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $dir/list.ico" | tee -a "${LOG_FILE}"
else
cp "${ICONS_DIR}/ico/app.ico" "$dir/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $dir/list.ico" | tee -a "${LOG_FILE}"
cp "${ICONS_DIR}/ico/app-del.ico" "$dir/del.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $dir/del.ico. See ${LOG_FILE} for details."
echo "Created: $dir/del.ico" | tee -a "${LOG_FILE}"
fi
if [[ "$title_id" != "PSBBN" ]]; then
APP_ART
fi
bbnl_cfg="${ICONS_DIR}/bbnl/$title_id.cfg"
create_bbnl_cfg "/APPS/$(basename "$dir")/$elf" "$title_id"
cp "${ASSETS_DIR}/BBNL"/{boot.kelf,system.cnf} "$dir" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create boot.kelf, or system.cnf. See ${LOG_FILE} for details."
echo "Created: $dir/boot.kelf" | tee -a "${LOG_FILE}"
echo "Created: $dir/system.cnf" | tee -a "${LOG_FILE}"
done < <(find "${ICONS_DIR}/APPS" -mindepth 1 -maxdepth 1 -type d | sort -r)
fi
################################### Assets for Games ###################################
if [ -f "$ALL_GAMES" ]; then
echo | tee -a "${LOG_FILE}"
echo "Downloading OPL artwork for games..." | tee -a "${LOG_FILE}"
# First loop: Run the art downloader script for each game_id if artwork doesn't already exist
exec 3< "$ALL_GAMES"
while IFS='|' read -r title game_id publisher disc_type file_name <&3; do
# Skip downloading if disc_type is "POPS"
if [[ "$disc_type" == "POPS" ]]; then
continue
fi
png_file_cover="${GAMES_PATH}/ART/${game_id}_COV.png"
png_file_disc="${GAMES_PATH}/ART/${game_id}_ICO.png"
if [[ -f "$png_file_cover" ]]; then
echo "OPL Artwork for $game_id already exists. Skipping download." | tee -a "${LOG_FILE}"
else
# Attempt to download artwork using wget
echo -n "OPL Artwork not found locally. Attempting to download from archive.org..." | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
wget --quiet --timeout=10 --tries=3 --output-document="$png_file_cover" \
"https://archive.org/download/OPLM_ART_2024_09/OPLM_ART_2024_09.zip/PS2/${game_id}/${game_id}_COV.png"
#wget --quiet --timeout=10 --tries=3 --output-document="$png_file_disc" \
#"https://archive.org/download/OPLM_ART_2024_09/OPLM_ART_2024_09.zip/PS2/${game_id}/${game_id}_ICO.png"
missing_files=()
if [[ ! -s "$png_file_cover" ]]; then
[[ -f "$png_file_cover" ]] && rm -f "$png_file_cover"
missing_files+=("cover")
fi
if [[ ! -s "$png_file_disc" ]]; then
[[ -f "$png_file_disc" ]] && rm -f "$png_file_disc"
missing_files+=("disc")
fi
if [[ -f "$png_file_cover" || -f "$png_file_disc" ]]; then
if [[ ${#missing_files[@]} -eq 0 ]]; then
echo "Successfully downloaded OPL artwork for $game_id" | tee -a "${LOG_FILE}"
else
echo "Successfully downloaded some OPL artwork for $game_id, but missing: ${missing_files[*]}" | tee -a "${LOG_FILE}"
fi
else
echo "Failed to download OPL artwork for $game_id" | tee -a "${LOG_FILE}"
fi
fi
done
exec 3<&-
else
echo | tee -a "${LOG_FILE}"
echo "No OPL artwork to download." | tee -a "${LOG_FILE}"
fi
GAME_COUNT=$(grep -c '^[^[:space:]]' "${ALL_GAMES}")
pp_max=$(( pp_max - APP_COUNT ))
if [ "$GAME_COUNT" -gt "$pp_max" ]; then
error_msg "Warning" "Insufficient space to create BBL partitions for remaining games." " " "The first $pp_max games will appear in the PSBBN Game Channel." "All PS2 games will appear in OPL/NHDDL."
# Overwrite master.list with the first $pp_max lines
head -n "$pp_max" "$ALL_GAMES" > "${ALL_GAMES}.tmp"
mv "${ALL_GAMES}.tmp" "$ALL_GAMES" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to updated master.list."
echo "Updated master.list:" >> "${LOG_FILE}"
cat "$ALL_GAMES" >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
fi
[ -f "$ALL_GAMES" ] && [ ! -s "$ALL_GAMES" ] && rm -f "$ALL_GAMES"
if [ -f "$ALL_GAMES" ]; then
echo | tee -a "${LOG_FILE}"
echo "Downloading PSBBN artwork for games..." | tee -a "${LOG_FILE}"
# First loop: Run the art downloader script for each game_id if artwork doesn't already exist
exec 3< "$ALL_GAMES"
while IFS='|' read -r title game_id publisher disc_type file_name <&3; do
# Check if the artwork file already exists
png_file="${ARTWORK_DIR}/${game_id}.png"
if [[ -f "$png_file" ]]; then
echo "Artwork for $game_id already exists. Skipping download." | tee -a "${LOG_FILE}"
else
# Attempt to download artwork using wget
echo -n "Artwork not found locally. Attempting to download from the PSBBN art database..." | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
wget --quiet --timeout=10 --tries=3 --output-document="$png_file" \
"https://raw.githubusercontent.com/CosmicScale/psbbn-art-database/main/art/${game_id}.png"
if [[ -s "$png_file" ]]; then
echo "Successfully downloaded artwork for $game_id" | tee -a "${LOG_FILE}"
else
# If wget fails, run the art downloader
[[ -f "$png_file" ]] && rm -f "$png_file"
echo "Trying IGN for $game_id" | tee -a "${LOG_FILE}"
node "${HELPER_DIR}/art_downloader.js" "$game_id" 2>&1 | tee -a "${LOG_FILE}"
fi
fi
done
exec 3<&-
# Define input directory
input_dir="${ARTWORK_DIR}/tmp"
# Check if the directory contains any files
if compgen -G "${input_dir}/*" > /dev/null; then
echo | tee -a "${LOG_FILE}"
echo "Converting artwork..." | tee -a "${LOG_FILE}"
for file in "${input_dir}"/*; do
# Extract the base filename without the path or extension
base_name=$(basename "${file%.*}")
# Define output filename with .png extension
output="${ARTWORK_DIR}/tmp/${base_name}.png"
# Get image dimensions using identify
dimensions=$(identify -format "%w %h" "$file")
width=$(echo "$dimensions" | cut -d' ' -f1)
height=$(echo "$dimensions" | cut -d' ' -f2)
# Check if width >= 256 and height >= width
if [[ $width -ge 256 && $height -ge $width ]]; then
# Determine whether the image is square
if [[ $width -eq $height ]]; then
# Square: Resize without cropping
echo "Resizing square image $file"
convert "$file" -resize 256x256! -depth 8 -alpha off "$output"
else
# Not square: Resize and crop
echo "Resizing and cropping $file"
convert "$file" -resize 256x256^ -crop 256x256+0+44 -depth 8 -alpha off "$output"
fi
rm -f "$file"
else
echo "Skipping $file: does not meet size requirements" | tee -a "${LOG_FILE}"
rm -f "$file"
fi
done
else
echo | tee -a "${LOG_FILE}"
echo "No artwork to convert in ${input_dir}" | tee -a "${LOG_FILE}"
fi
cp ${ARTWORK_DIR}/tmp/* ${ARTWORK_DIR} >> "${LOG_FILE}" 2>&1
echo | tee -a "${LOG_FILE}"
echo "Dowbloading HDD-OSD icons for games:" | tee -a "${LOG_FILE}"
exec 3< "$ALL_GAMES"
while IFS='|' read -r title game_id publisher disc_type file_name <&3; do
ico_file="${ICONS_DIR}/ico/$game_id.ico"
if [[ ! -s "$ico_file" ]]; then
# Attempt to download icon using wget
echo -n "Icon not found locally for $game_id. Attempting to download from the HDD-OSD icon database..." | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
wget --quiet --timeout=10 --tries=3 --output-document="$ico_file" \
"https://raw.githubusercontent.com/CosmicScale/HDD-OSD-Icon-Database/main/ico/${game_id}.ico"
if [[ -s "$ico_file" ]]; then
echo "Successfully downloaded icon for ${game_id}." | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
else
# If wget fails, run the art downloader
[[ -f "$ico_file" ]] && rm -f "$ico_file"
png_file_cov="${TOOLKIT_PATH}/icons/ico/tmp/${game_id}_COV.png"
png_file_cov2="${TOOLKIT_PATH}/icons/ico/tmp/${game_id}_COV2.png"
png_file_lab="${TOOLKIT_PATH}/icons/ico/tmp/${game_id}_LAB.png"
echo -n "Icon not found on database. Downloading icon assets for $game_id..." | tee -a "${LOG_FILE}"
if [[ -s "${GAMES_PATH}/ART/${game_id}_COV.png" ]]; then
cp "${GAMES_PATH}/ART/${game_id}_COV.png" "${png_file_cov}"
else
wget --quiet --timeout=10 --tries=3 --output-document="${png_file_cov}" \
"https://archive.org/download/OPLM_ART_2024_09/OPLM_ART_2024_09.zip/PS1/${game_id}/${game_id}_COV.png"
fi
if [[ -s "$png_file_cov" && "$disc_type" != "POPS" ]]; then
wget --quiet --timeout=10 --tries=3 --output-document="$png_file_cov2" \
"https://archive.org/download/OPLM_ART_2024_09/OPLM_ART_2024_09.zip/PS2/${game_id}/${game_id}_COV2.png"
wget --quiet --timeout=10 --tries=3 --output-document="$png_file_lab" \
"https://archive.org/download/OPLM_ART_2024_09/OPLM_ART_2024_09.zip/PS2/${game_id}/${game_id}_LAB.png"
elif [[ -s "$png_file_cov" && "$disc_type" == "POPS" ]]; then
wget --quiet --timeout=10 --tries=3 --output-document="$png_file_cov2" \
"https://archive.org/download/OPLM_ART_2024_09/OPLM_ART_2024_09.zip/PS1/${game_id}/${game_id}_COV2.png"
wget --quiet --timeout=10 --tries=3 --output-document="$png_file_lab" \
"https://archive.org/download/OPLM_ART_2024_09/OPLM_ART_2024_09.zip/PS1/${game_id}/${game_id}_LAB.png"
fi
echo | tee -a "${LOG_FILE}"
if [[ ! -s "$png_file_lab" ]]; then
if [[ "${game_id:2:1}" == "E" ]]; then
if [[ "$disc_type" != "POPS" ]]; then
cp "${ASSETS_DIR}/Icon-templates/PS2_LAB_PAL.png" "${png_file_lab}"
else
cp "${ASSETS_DIR}/Icon-templates/PS1_LAB_PAL.png" "${png_file_lab}"
fi
elif [[ "${game_id:2:1}" == "U" || "${game_id:0:1}" == "L" ]]; then
if [[ "$disc_type" != "POPS" ]]; then
cp "${ASSETS_DIR}/Icon-templates/PS2_LAB_USA.png" "${png_file_lab}"
else
cp "${ASSETS_DIR}/Icon-templates/PS1_LAB_USA.png" "${png_file_lab}"
fi
else
if [[ "$disc_type" != "POPS" ]]; then
cp "${ASSETS_DIR}/Icon-templates/PS2_LAB_JPN.png" "${png_file_lab}"
else
cp "${ASSETS_DIR}/Icon-templates/PS1_LAB_JPN.png" "${png_file_lab}"
fi
fi
fi
if [[ -s "$png_file_cov" && -s "$png_file_cov2" && -s "$png_file_lab" ]]; then
echo -n "Creating HDD-OSD icon for $game_id..." | tee -a "${LOG_FILE}"
if [[ "$disc_type" != "POPS" ]]; then
if [[ "${game_id:2:1}" == "E" ]]; then
"${HELPER_DIR}/ps2iconmaker.sh" $game_id -t 2
else
"${HELPER_DIR}/ps2iconmaker.sh" $game_id -t 1
fi
else
if [[ "${game_id:2:1}" == "U" || "${game_id:0:1}" == "L" ]]; then
"${HELPER_DIR}/ps2iconmaker.sh" $game_id -t 3
elif [[ "${game_id:2:1}" == "E" ]]; then
"${HELPER_DIR}/ps2iconmaker.sh" $game_id -t 6
else
"${HELPER_DIR}/ps2iconmaker.sh" $game_id -t 5
fi
fi
echo | tee -a "${LOG_FILE}"
else
echo "Insufficient assets to create icon for $game_id." | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
fi
fi
fi
done
exec 3<&-
cp "${ICONS_DIR}/ico/tmp/"*.ico "${ICONS_DIR}/ico/" >/dev/null 2>&1
echo | tee -a "${LOG_FILE}"
echo "Creating Assets for Games:" | tee -a "${LOG_FILE}"
# Read the file line by line
exec 3< "$ALL_GAMES"
while IFS='|' read -r title game_id publisher disc_type file_name <&3; do
echo | tee -a "${LOG_FILE}"
echo "Processing $title..."
title_id=$(echo "$game_id" | sed -E 's/_(...)\./-\1/;s/\.//')
# Create a sub-folder named after the game_id
game_dir="$ICONS_DIR/$game_id"
mkdir -p "$game_dir" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to create $dir."
cp "${ASSETS_DIR}/BBNL"/{boot.kelf,system.cnf} "${game_dir}" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create boot.kelf, or system.cnf. See ${LOG_FILE} for details."
echo "Created: $game_dir/boot.kelf" | tee -a "${LOG_FILE}"
echo "Created: $game_dir/system.cnf" | tee -a "${LOG_FILE}"
# Generate the info.sys file
info_sys_filename="$game_dir/info.sys"
create_info_sys "$title" "$title_id" "$publisher"
if [ ${#title} -gt 48 ]; then
game_title_icon="${title:0:45}..."
else
game_title_icon="$title"
fi
# Generate the icon.sys file
icon_sys_filename="$game_dir/icon.sys"
create_icon_sys "$game_title_icon" "$publisher"
# Copy the matching .png file and rename it to jkt_001.png
png_file="${TOOLKIT_PATH}/icons/art/${game_id}.png"
if [[ -s "$png_file" ]]; then
cp "$png_file" "${game_dir}/jkt_001.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $game_dir/jkt_001.png. See ${LOG_FILE} for details."
echo "Created: $game_dir/jkt_001.png" | tee -a "${LOG_FILE}"
else
echo "$game_id $title" >> "${MISSING_ART}"
if [[ "$disc_type" == "POPS" ]]; then
cp "${TOOLKIT_PATH}/icons/art/ps1.png" "${game_dir}/jkt_001.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $game_dir/jkt_001.png. See ${LOG_FILE} for details."
echo "Created: $game_dir/jkt_001.png using default PS1 image." | tee -a "${LOG_FILE}"
else
cp "${TOOLKIT_PATH}/icons/art/ps2.png" "${game_dir}/jkt_001.png" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $game_dir/jkt_001.png. See ${LOG_FILE} for details."
echo "Created: $game_dir/jkt_001.png using default PS2 image." | tee -a "${LOG_FILE}"
fi
fi
ico_file="${ICONS_DIR}/ico/$game_id.ico"
if [[ -f "$ico_file" ]]; then
cp "${ICONS_DIR}/ico/$game_id.ico" "${game_dir}/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $game_dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $game_dir/list.ico"
else
echo "$game_id $title" >> "${MISSING_ICON}"
case "$disc_type" in
DVD)
cp "${ICONS_DIR}/ico/dvd.ico" "${game_dir}/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $game_dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $game_dir/list.ico using default DVD icon." | tee -a "${LOG_FILE}"
;;
CD)
cp "${ICONS_DIR}/ico/cd.ico" "${game_dir}/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $game_dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $game_dir/list.ico using default CD icon." | tee -a "${LOG_FILE}"
;;
POPS)
cp "${ICONS_DIR}/ico/ps1.ico" "${game_dir}/list.ico" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create $game_dir/list.ico. See ${LOG_FILE} for details."
echo "Created: $game_dir/list.ico using default PS1 icon." | tee -a "${LOG_FILE}"
;;
esac
fi
PP_NAME
# Generate the BBNL cfg file
# Determine the launcher value for this specific game
if [[ "$disc_type" == "POPS" ]]; then
launcher_value="POPS"
else
launcher_value="$LAUNCHER"
fi
bbnl_label="${PARTITION_LABEL:3}"
bbnl_cfg="${ICONS_DIR}/bbnl/$bbnl_label.cfg"
cat > "$bbnl_cfg" <<EOL
file_name=$file_name
title_id=$game_id
disc_type=$disc_type
launcher=$launcher_value
EOL
echo "Created: $bbnl_cfg" | tee -a "${LOG_FILE}"
done
exec 3<&-
else
echo | tee -a "${LOG_FILE}"
echo "No games to process." | tee -a "${LOG_FILE}"
fi
bbnl_cfg="${ICONS_DIR}/bbnl/LAUNCHER.cfg"
echo | tee -a "${LOG_FILE}"
if [ "$LAUNCHER" = "OPL" ]; then
cp "${ASSETS_DIR}/BBNL"/{boot.kelf,system.cnf} "${ASSETS_DIR}/OPL" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create boot.kelf, or system.cnf for OPL. See ${LOG_FILE} for details."
create_bbnl_cfg "/bbnl/OPNPS2LD.ELF" "LAUNCHER"
elif [ "$LAUNCHER" = "NEUTRINO" ]; then
cp "${ASSETS_DIR}/BBNL"/{boot.kelf,system.cnf} "${ASSETS_DIR}/NHDDL" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to create boot.kelf, or system.cnf for NHDDL. See ${LOG_FILE} for details."
create_bbnl_cfg "/bbnl/nhddl.elf" "LAUNCHER" "-mode=ata"
fi
# Copy OPL files
dirs=(
"${GAMES_PATH}/ART"
"${GAMES_PATH}/CFG"
"${GAMES_PATH}/CHT"
"${GAMES_PATH}/LNG"
"${GAMES_PATH}/THM"
"${GAMES_PATH}/VMC"
)
# Flag to track if any files exist
files_exist=false
echo | tee -a "${LOG_FILE}"
# Check each directory and copy files if not empty
for dir in "${dirs[@]}"; do
if [ -d "$dir" ] && [ -n "$(find "$dir" -type f ! -name '.*' -print -quit 2>/dev/null)" ]; then
# Create the subdirectory in the destination path using the directory name
folder_name=$(basename "$dir")
dest_dir="${OPL}/$folder_name"
# Copy non-hidden files to the corresponding destination subdirectory
if [ "$folder_name" == "CFG" ] || [ "$folder_name" == "VMC" ]; then
echo "Copying OPL $folder_name files..." | tee -a "${LOG_FILE}"
find "$dir" -type f ! -name '.*' -exec cp --update=none {} "$dest_dir" \; >> "${LOG_FILE}" 2>&1
else
if [ -n "$(find "$dir" -mindepth 1 ! -name '.*' -print -quit)" ]; then
echo "Copying OPL $folder_name files..." | tee -a "${LOG_FILE}"
cp -r "$dir"/* "$dest_dir" >> "${LOG_FILE}" 2>&1
fi
fi
files_exist=true
fi
done
# Print message based on the check
if ! $files_exist; then
echo "No OPL files to copy." | tee -a "${LOG_FILE}"
fi
echo | tee -a "${LOG_FILE}"
echo "Copying BBNL configs..." | tee -a "${LOG_FILE}"
rm -f "${TOOLKIT_PATH}"/OPL/bbnl/*.cfg >> "${LOG_FILE}" 2>&1
cp "${ICONS_DIR}"/bbnl/*.cfg "${OPL}/bbnl" 2>> "${LOG_FILE}" || error_msg "Error" "Failed to copy BBNL config files. See ${LOG_FILE} for details."
echo | tee -a "${LOG_FILE}"
echo "All assets have been sucessfully created." | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
echo -n "Unmounting OPL partition..." | tee -a "${LOG_FILE}"
UNMOUNT_OPL
echo | tee -a "${LOG_FILE}"
################################### Create BBNL Partitions ###################################
echo | tee -a "${LOG_FILE}"
if find "${ICONS_DIR}/SAS" -mindepth 1 -maxdepth 1 -type d ! -name '.*' | grep -q .; then
echo "Creating BBNL Partitions for SAS Apps:" | tee -a "${LOG_FILE}"
while IFS= read -r dir; do
folder_name=$(basename "$dir")
pp_name="PP.$folder_name"
APA_SIZE_CHECK
# Check the value of available
if [ "$available" -lt 8 ]; then
error_msg "Warning" "Insufficient space for another partition."
break
fi
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mkpart $pp_name 8M PFS\n"
COMMANDS+="mount $pp_name\n"
COMMANDS+="mkdir res\n"
COMMANDS+="cd res\n"
COMMANDS+="lcd '${ICONS_DIR}/SAS/$folder_name'\n"
COMMANDS+="put info.sys\n"
COMMANDS+="put jkt_001.png\n"
COMMANDS+="cd /\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
PFS_COMMANDS
cd "${ICONS_DIR}/SAS/$folder_name" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to ${ICONS_DIR}/SAS/$folder_name."
sudo "${HELPER_DIR}/HDL Dump.elf" modify_header "${DEVICE}" "$pp_name" >> "${LOG_FILE}" 2>&1 || error_msg "Error" "Failed to modify header of $pp_name"
echo "Created $pp_name" | tee -a "${LOG_FILE}"
done < <(find "${ICONS_DIR}/SAS" -mindepth 1 -maxdepth 1 -type d | sort -r)
fi
if find "${ICONS_DIR}/APPS" -mindepth 1 -maxdepth 1 -type d ! -name '.*' | grep -q .; then
echo | tee -a "${LOG_FILE}"
echo "Creating BBNL Partitions for ELF files:" | tee -a "${LOG_FILE}"
while IFS= read -r dir; do
APA_SIZE_CHECK
# Check the value of available
if [ "$available" -lt 8 ]; then
error_msg "Warning" "Insufficient space for another partition."
break
fi
folder_name=$(basename "$dir")
pp_name="PP.$folder_name"
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mkpart $pp_name 8M PFS\n"
COMMANDS+="mount $pp_name\n"
if [ "$pp_name" = "PP.DISC" ]; then
COMMANDS+="lcd '${ASSETS_DIR}/DISC'\n"
COMMANDS+="put PS1VModeNeg.elf\n"
fi
COMMANDS+="mkdir res\n"
COMMANDS+="cd res\n"
COMMANDS+="lcd '${ICONS_DIR}/APPS/$folder_name'\n"
COMMANDS+="put info.sys\n"
if [ "$pp_name" != "PP.PSBBN" ]; then
COMMANDS+="put jkt_001.png\n"
fi
COMMANDS+="cd /\n"
COMMANDS+="umount\n"
COMMANDS+="exit"
PFS_COMMANDS
if [ "$pp_name" = "PP.LAUNCHDISC" ]; then
cd "${ASSETS_DIR}/DISC" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to ${ASSETS_DIR}/DISC."
sudo "${HELPER_DIR}/HDL Dump.elf" modify_header "${DEVICE}" "$pp_name" >> "${LOG_FILE}" 2>&1 || error_msg "Error" "Failed to modify header of $pp_name."
else
cd "${ICONS_DIR}/APPS/$folder_name" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to ${ICONS_DIR}/APPS/$folder_name."
sudo "${HELPER_DIR}/HDL Dump.elf" modify_header "${DEVICE}" "$pp_name" >> "${LOG_FILE}" 2>&1 || error_msg "Error" "Failed to modify header of $pp_name."
fi
echo "Created $pp_name" | tee -a "${LOG_FILE}"
done < <(find "${ICONS_DIR}/APPS" -mindepth 1 -maxdepth 1 -type d | sort -r)
fi
# Create PP.LAUNCHER
APA_SIZE_CHECK
# Check the value of available
if [ "$available" -lt 8 ]; then
error_msg "Warning" "Insufficient space for another partition."
else
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mkpart PP.LAUNCHER 8M PFS\n"
COMMANDS+="mount PP.LAUNCHER\n"
COMMANDS+="mkdir res\n"
COMMANDS+="cd res\n"
if [ "$LAUNCHER" = "OPL" ]; then
cd "${ASSETS_DIR}/OPL"
COMMANDS+="put info.sys\n"
COMMANDS+="lcd '${ARTWORK_DIR}'\n"
COMMANDS+="put OPENPS2LOAD.png\n"
COMMANDS+="rename OPENPS2LOAD.png jkt_001.png\n"
COMMANDS+="cd /\n"
elif [ "$LAUNCHER" = "NEUTRINO" ]; then
cd "${ASSETS_DIR}/NHDDL"
COMMANDS+="put info.sys\n"
COMMANDS+="lcd '${ARTWORK_DIR}'\n"
COMMANDS+="put NHDDL.png\n"
COMMANDS+="rename NHDDL.png jkt_001.png\n"
COMMANDS+="cd /\n"
fi
COMMANDS+="umount\n"
COMMANDS+="exit"
echo >> "${LOG_FILE}"
PFS_COMMANDS
sudo "${HELPER_DIR}/HDL Dump.elf" modify_header "${DEVICE}" PP.LAUNCHER >> "${LOG_FILE}" 2>&1 || error_msg "Error" "Failed to modify header of PP.LAUNCHER."
echo | tee -a "${LOG_FILE}"
echo "Created PP.LAUNCHER" | tee -a "${LOG_FILE}"
fi
if [ -f "$ALL_GAMES" ]; then
# Read all lines in reverse order
mapfile -t reversed_lines < <(tac "$ALL_GAMES")
echo | tee -a "${LOG_FILE}"
echo "Creating BBNL Partitions for Games:" | tee -a "${LOG_FILE}"
i=0
# Reverse the lines of the file using tac and process each line
for line in "${reversed_lines[@]}"; do
IFS='|' read -r title game_id publisher disc_type file_name <<< "$line"
APA_SIZE_CHECK
# Check the value of available
if [ "$available" -lt 8 ]; then
error_msg "Warning" "Insufficient space for another partition."
break
fi
PP_NAME
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mkpart ${PARTITION_LABEL} 8M PFS\n"
COMMANDS+="mount ${PARTITION_LABEL}\n"
COMMANDS+="cd /\n"
# Navigate into the sub-directory named after the gameid
COMMANDS+="lcd '${ICONS_DIR}/${game_id}'\n"
COMMANDS+="mkdir res\n"
COMMANDS+="cd res\n"
COMMANDS+="put info.sys\n"
COMMANDS+="put jkt_001.png\n"
if [[ "$disc_type" == "POPS" ]]; then
COMMANDS+="lcd '${ASSETS_DIR}/POPStarter'\n"
COMMANDS+="put 1.png\n"
COMMANDS+="put 2.png\n"
COMMANDS+="put bg.png\n"
COMMANDS+="put man.xml\n"
fi
COMMANDS+="umount\n"
COMMANDS+="exit\n"
PFS_COMMANDS
cd "${ICONS_DIR}/$game_id" 2>>"${LOG_FILE}" || error_msg "Error" "Failed to navigate to ${ICONS_DIR}/$game_id."
sudo "${HELPER_DIR}/HDL Dump.elf" modify_header "${DEVICE}" "${PARTITION_LABEL}" >> "${LOG_FILE}" 2>&1 || error_msg "Error" "Failed to modify header of ${PARTITION_LABEL}."
echo "Created $PARTITION_LABEL" | tee -a "${LOG_FILE}"
echo >> "${LOG_FILE}"
((i++))
done
fi
################################### Submit missing artwork to the PSBBN Art Database ###################################
cp "${MISSING_ART}" "${ARTWORK_DIR}/tmp" >> "${LOG_FILE}" 2>&1
cp "${MISSING_APP_ART}" "${ARTWORK_DIR}/tmp" >> "${LOG_FILE}" 2>&1
cp "${MISSING_ICON}" "${ICONS_DIR}/ico/tmp" >> "${LOG_FILE}" 2>&1
cd "${ICONS_DIR}/ico/tmp/"
rm *.png >/dev/null 2>&1
zip -r "${ARTWORK_DIR}/tmp/ico.zip" * >/dev/null 2>&1
cd "${ARTWORK_DIR}/tmp/"
zip -r "${ARTWORK_DIR}/tmp/art.zip" * >/dev/null 2>&1
if [ "$(ls -A "${ARTWORK_DIR}/tmp")" ]; then
echo | tee -a "${LOG_FILE}"
echo "Contributing to the PSBBN art & HDD-OSD databases..." | tee -a "${LOG_FILE}"
# Upload the file using transfer.sh
upload_url=$(curl -F "reqtype=fileupload" -F "time=72h" -F "fileToUpload=@art.zip" https://litterbox.catbox.moe/resources/internals/api.php)
if [[ "$upload_url" == https://* ]]; then
echo "File uploaded successfully: $upload_url" | tee -a "${LOG_FILE}"
# Send a POST request to Webhook.site with the uploaded file URL
webhook_url="https://webhook.site/PSBBN"
curl -X POST -H "Content-Type: application/json" \
-d "{\"url\": \"$upload_url\"}" \
"$webhook_url" >/dev/null 2>&1
else
error_msg "Warning" "Failed to upload the file."
fi
else
echo | tee -a "${LOG_FILE}"
echo "No art work or icons to contribute." | tee -a "${LOG_FILE}"
fi
echo | tee -a "${LOG_FILE}"
echo "Cleaning up..." | tee -a "${LOG_FILE}"
clean_up
HDL_TOC
cat "$hdl_output" >> "${LOG_FILE}"
rm -f "$hdl_output"
echo | tee -a "${LOG_FILE}"
echo "Game installer script complete." | tee -a "${LOG_FILE}"
echo
read -n 1 -s -r -p "Press any key to exit..."
echo