mirror of
https://github.com/SillyTavern/SillyTavern-Launcher.git
synced 2026-01-26 17:09:44 +00:00
launcher improvements
# install.sh + Replaced pip with pip3 for python version 3 + Added openSUSE zypper package support # installer.bat + added stream2sentence for xtts # launcher.sh + some menu + text cleanup + edit extras modules improvements
This commit is contained in:
62
install.sh
62
install.sh
@@ -207,6 +207,10 @@ install_git() {
|
||||
# Termux on Android
|
||||
log_message "INFO" "Installing Git using pkg..."
|
||||
pkg install git
|
||||
elif command -v zypper &>/dev/null; then
|
||||
# openSUSE
|
||||
log_message "INFO" "Installing Git using zypper..."
|
||||
sudo zypper install git
|
||||
else
|
||||
log_message "ERROR" "${red_fg_strong}Unsupported Linux distribution.${reset}"
|
||||
exit 1
|
||||
@@ -278,6 +282,10 @@ install_nodejs_npm() {
|
||||
# macOS
|
||||
log_message "INFO" "Installing Node.js and npm using Homebrew..."
|
||||
brew install node
|
||||
elif command -v zypper &>/dev/null; then
|
||||
# openSUSE
|
||||
log_message "INFO" "Installing Node.js and npm using zypper..."
|
||||
sudo zypper --non-interactive install nodejs npm
|
||||
else
|
||||
log_message "ERROR" "${red_fg_strong}Unsupported Linux distribution.${reset}"
|
||||
exit 1
|
||||
@@ -371,11 +379,11 @@ install_st_extras() {
|
||||
log_message "INFO" "Installing Python in the Conda environment..."
|
||||
conda install python=3.10 -y
|
||||
|
||||
# Install pip requirements
|
||||
log_message "INFO" "Installing pip requirements for xtts..."
|
||||
pip install xtts-api-server
|
||||
pip install pydub
|
||||
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
||||
# Install pip3 requirements
|
||||
log_message "INFO" "Installing pip3 requirements for xtts..."
|
||||
pip3 install xtts-api-server
|
||||
pip3 install pydub
|
||||
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
||||
|
||||
# Create folders for xtts
|
||||
log_message "INFO" "Creating xtts folders..."
|
||||
@@ -429,24 +437,24 @@ install_st_extras() {
|
||||
|
||||
# Check the user's response
|
||||
if [ "$gpu_choice" == "1" ]; then
|
||||
# Install pip requirements
|
||||
# Install pip3 requirements
|
||||
log_message "INFO" "Installing modules from requirements.txt in extras..."
|
||||
pip install -r requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
conda install -c conda-forge faiss-gpu -y
|
||||
elif [ "$gpu_choice" == "2" ]; then
|
||||
log_message "INFO" "Installing modules from requirements-rocm.txt in extras..."
|
||||
pip install -r requirements-rocm.txt
|
||||
pip3 install -r requirements-rocm.txt
|
||||
elif [ "$gpu_choice" == "3" ]; then
|
||||
log_message "INFO" "Installing modules from requirements-silicon.txt in extras..."
|
||||
pip install -r requirements-silicon.txt
|
||||
pip3 install -r requirements-silicon.txt
|
||||
else
|
||||
log_message "ERROR" "Invalid GPU choice. Please enter a valid number."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_message "INFO" "Installing pip requirements-rvc in extras environment..."
|
||||
pip install -r requirements-rvc.txt
|
||||
pip install tensorboardX
|
||||
log_message "INFO" "Installing pip3 requirements-rvc in extras environment..."
|
||||
pip3 install -r requirements-rvc.txt
|
||||
pip3 install tensorboardX
|
||||
|
||||
# Cleanup the Downloaded file
|
||||
rm -rf /tmp/$miniconda_installer
|
||||
@@ -605,11 +613,11 @@ install_extras() {
|
||||
log_message "INFO" "Installing Python in the Conda environment..."
|
||||
conda install python=3.10 -y
|
||||
|
||||
# Install pip requirements
|
||||
log_message "INFO" "Installing pip requirements for xtts..."
|
||||
pip install xtts-api-server
|
||||
pip install pydub
|
||||
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
||||
# Install pip3 requirements
|
||||
log_message "INFO" "Installing pip3 requirements for xtts..."
|
||||
pip3 install xtts-api-server
|
||||
pip3 install pydub
|
||||
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
||||
|
||||
# Create folders for xtts
|
||||
log_message "INFO" "Creating xtts folders..."
|
||||
@@ -663,24 +671,24 @@ install_extras() {
|
||||
|
||||
# Check the user's response
|
||||
if [ "$gpu_choice" == "1" ]; then
|
||||
# Install pip requirements
|
||||
# Install pip3 requirements
|
||||
log_message "INFO" "Installing modules from requirements.txt in extras..."
|
||||
pip install -r requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
conda install -c conda-forge faiss-gpu -y
|
||||
elif [ "$gpu_choice" == "2" ]; then
|
||||
log_message "INFO" "Installing modules from requirements-rocm.txt in extras..."
|
||||
pip install -r requirements-rocm.txt
|
||||
pip3 install -r requirements-rocm.txt
|
||||
elif [ "$gpu_choice" == "3" ]; then
|
||||
log_message "INFO" "Installing modules from requirements-silicon.txt in extras..."
|
||||
pip install -r requirements-silicon.txt
|
||||
pip3 install -r requirements-silicon.txt
|
||||
else
|
||||
log_message "ERROR" "Invalid GPU choice. Please enter a valid number."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_message "INFO" "Installing pip requirements-rvc in extras environment..."
|
||||
pip install -r requirements-rvc.txt
|
||||
pip install tensorboardX
|
||||
log_message "INFO" "Installing pip3 requirements-rvc in extras environment..."
|
||||
pip3 install -r requirements-rvc.txt
|
||||
pip3 install tensorboardX
|
||||
|
||||
# Cleanup the Downloaded file
|
||||
rm -rf /tmp/$miniconda_installer
|
||||
@@ -775,6 +783,12 @@ elif command -v pkg &>/dev/null; then
|
||||
install_git
|
||||
install_nodejs_npm
|
||||
installer
|
||||
elif command -v zypper &>/dev/null; then
|
||||
log_message "INFO" "${blue_fg_strong}Detected openSUSE system.${reset}"
|
||||
# openSUSE
|
||||
install_git
|
||||
install_nodejs_npm
|
||||
installer
|
||||
else
|
||||
log_message "ERROR" "${red_fg_strong}Unsupported package manager. Cannot detect Linux distribution.${reset}"
|
||||
exit 1
|
||||
|
||||
@@ -217,6 +217,7 @@ if /i "%install_xtts_requirements%"=="Y" (
|
||||
echo %blue_bg%[%time%]%reset% %blue_fg_strong%[INFO]%reset% Installing pip requirements for xtts...
|
||||
pip install xtts-api-server
|
||||
pip install pydub
|
||||
pip install stream2sentence==0.2.2
|
||||
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
||||
|
||||
REM Create folders for xtts
|
||||
|
||||
192
launcher.sh
192
launcher.sh
@@ -145,7 +145,7 @@ if [[ "$(git rev-list HEAD...origin/$current_branch)" ]]; then
|
||||
update_status="Update Available"
|
||||
fi
|
||||
|
||||
# Function for the home
|
||||
# Home Menu - Frontend
|
||||
home() {
|
||||
echo -e "\033]0;SillyTavern [HOME]\007"
|
||||
clear
|
||||
@@ -158,12 +158,12 @@ home() {
|
||||
echo "4. Backup"
|
||||
echo "5. Switch branch"
|
||||
echo "6. Toolbox"
|
||||
echo "7. Exit"
|
||||
echo "0. Exit"
|
||||
|
||||
echo "======== VERSION STATUS ========"
|
||||
echo -e "SillyTavern branch: ${cyan_fg_strong}$current_branch${reset}"
|
||||
echo -e "Sillytavern: $update_status"
|
||||
echo -e "Launcher: V1.0.1"
|
||||
echo -e "Launcher: V1.0.2"
|
||||
echo "================================"
|
||||
|
||||
read -p "Choose Your Destiny: " home_choice
|
||||
@@ -173,7 +173,7 @@ home() {
|
||||
home_choice=1
|
||||
fi
|
||||
|
||||
# Home menu - Backend
|
||||
# Home Menu - Backend
|
||||
case $home_choice in
|
||||
1) start_st ;;
|
||||
2) start_st_extras ;;
|
||||
@@ -181,7 +181,7 @@ home() {
|
||||
4) backup_menu ;;
|
||||
5) switch_branch_menu ;;
|
||||
6) toolbox ;;
|
||||
7) exit ;;
|
||||
0) exit ;;
|
||||
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
|
||||
read -p "Press Enter to continue..."
|
||||
home ;;
|
||||
@@ -394,7 +394,7 @@ restore_backup() {
|
||||
backup_menu
|
||||
}
|
||||
|
||||
# Function for backup
|
||||
# Backup Menu - Frontend
|
||||
backup_menu() {
|
||||
echo -e "\033]0;SillyTavern [BACKUP]\007"
|
||||
clear
|
||||
@@ -403,15 +403,15 @@ backup_menu() {
|
||||
echo "What would you like to do?"
|
||||
echo "1. Create Backup"
|
||||
echo "2. Restore Backup"
|
||||
echo "3. Back to Home"
|
||||
echo "0. Back to Home"
|
||||
|
||||
read -p "Choose Your Destiny: " backup_choice
|
||||
|
||||
# Backup menu - Backend
|
||||
# Backup Menu - Backend
|
||||
case $backup_choice in
|
||||
1) create_backup ;;
|
||||
2) restore_backup ;;
|
||||
3) home ;;
|
||||
0) home ;;
|
||||
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
|
||||
read -p "Press Enter to continue..."
|
||||
backup_menu ;;
|
||||
@@ -435,7 +435,7 @@ switch_staging_st() {
|
||||
switch_branch_menu
|
||||
}
|
||||
|
||||
# Function for switching branches
|
||||
# Switch Brance Menu - Frontend
|
||||
switch_branch_menu() {
|
||||
echo -e "\033]0;SillyTavern [SWITCH-BRANCE]\007"
|
||||
clear
|
||||
@@ -444,7 +444,7 @@ switch_branch_menu() {
|
||||
echo "What would you like to do?"
|
||||
echo "1. Switch to Release - SillyTavern"
|
||||
echo "2. Switch to Staging - SillyTavern"
|
||||
echo "3. Back to Home"
|
||||
echo "0. Back to Home"
|
||||
|
||||
current_branch=$(git branch --show-current)
|
||||
echo "======== VERSION STATUS ========"
|
||||
@@ -454,11 +454,11 @@ switch_branch_menu() {
|
||||
|
||||
read -p "Choose Your Destiny: " branch_choice
|
||||
|
||||
# switch branch menu - Backend
|
||||
# Switch Branch Menu - Backend
|
||||
case $branch_choice in
|
||||
1) switch_release_st ;;
|
||||
2) switch_staging_st ;;
|
||||
3) home ;;
|
||||
0) home ;;
|
||||
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
|
||||
read -p "Press Enter to continue..."
|
||||
switch_branch_menu ;;
|
||||
@@ -489,125 +489,74 @@ edit_environment() {
|
||||
# Function to print module options with color based on their status
|
||||
printModule() {
|
||||
if [ "$2" == "true" ]; then
|
||||
echo -e "\e[32m$1 [Enabled]\e[0m"
|
||||
echo -e "\e[32;1m$1 [Enabled]\e[0m"
|
||||
else
|
||||
echo -e "\e[31m$1 [Disabled]\e[0m"
|
||||
echo -e "\e[31;1m$1 [Disabled]\e[0m"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to edit extras modules
|
||||
edit_extras_modules() {
|
||||
while true; do
|
||||
echo "SillyTavern [EDIT-MODULES]"
|
||||
clear
|
||||
echo -e "\e[34m/ Home / Toolbox / Edit Extras Modules\e[0m"
|
||||
echo "-------------------------------------"
|
||||
echo "Choose extras modules to enable or disable (e.g., '1 2 4' to enable XTTS, RVC, and Caption)"
|
||||
echo
|
||||
echo -e "\033]0;SillyTavern [EDIT-MODULES]\007"
|
||||
clear
|
||||
echo -e "${blue_fg_strong}/ Home / Toolbox / Edit Extras Modules${reset}"
|
||||
echo "-------------------------------------"
|
||||
echo "Choose extras modules to enable or disable (e.g., \"1 2 4\" to enable Cuda, RVC, and Caption)"
|
||||
|
||||
# Display module options with colors based on their status
|
||||
printModule "1. XTTS (--gpu 0 --cuda-device=0)" "$xtts_trigger"
|
||||
printModule "2. RVC (--enable-modules=rvc --rvc-save-file --max-content-length=1000)" "$rvc_trigger"
|
||||
printModule "3. talkinghead (--enable-modules=talkinghead)" "$talkinghead_trigger"
|
||||
printModule "4. caption (--enable-modules=caption)" "$caption_trigger"
|
||||
printModule "5. summarize (--enable-modules=summarize)" "$summarize_trigger"
|
||||
echo "6. Back to Toolbox"
|
||||
# Display module options with colors based on their status
|
||||
printModule "1. Cuda (--gpu 0 --cuda --cuda-device=0)" "$cuda_trigger"
|
||||
printModule "2. RVC (--enable-modules=rvc --rvc-save-file --max-content-length=1000)" "$rvc_trigger"
|
||||
printModule "3. talkinghead (--enable-modules=talkinghead)" "$talkinghead_trigger"
|
||||
printModule "4. caption (--enable-modules=caption)" "$caption_trigger"
|
||||
printModule "5. summarize (--enable-modules=summarize)" "$summarize_trigger"
|
||||
printModule "6. listen (--listen)" "$listen_trigger"
|
||||
echo "0. Back to Toolbox"
|
||||
|
||||
python_command=""
|
||||
set "python_command="
|
||||
|
||||
read -p "Choose modules to enable/disable (1-5): " module_choices
|
||||
read -p "Choose modules to enable/disable (1-6): " module_choices
|
||||
|
||||
# Handle the user's module choices and construct the Python command
|
||||
for i in $module_choices; do
|
||||
case $i in
|
||||
1)
|
||||
[ "$xtts_trigger" == "true" ] && xtts_trigger="false" || xtts_trigger="true"
|
||||
# python_command="--gpu 0 --cuda-device=0"
|
||||
;;
|
||||
2)
|
||||
[ "$rvc_trigger" == "true" ] && rvc_trigger="false" || rvc_trigger="true"
|
||||
# python_command=" --enable-modules=rvc --rvc-save-file --max-content-length=1000"
|
||||
;;
|
||||
3)
|
||||
[ "$talkinghead_trigger" == "true" ] && talkinghead_trigger="false" || talkinghead_trigger="true"
|
||||
# python_command=" --enable-modules=talkinghead"
|
||||
;;
|
||||
4)
|
||||
[ "$caption_trigger" == "true" ] && caption_trigger="false" || caption_trigger="true"
|
||||
# python_command=" --enable-modules=caption"
|
||||
;;
|
||||
5)
|
||||
[ "$summarize_trigger" == "true" ] && summarize_trigger="false" || summarize_trigger="true"
|
||||
# python_command=" --enable-modules=summarize"
|
||||
;;
|
||||
6)
|
||||
toolbox
|
||||
break # Break out of the loop when user selects Back to Toolbox
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# Handle the user's module choices and construct the Python command
|
||||
for i in $module_choices; do
|
||||
case $i in
|
||||
1) [ "$cuda_trigger" == "true" ] && cuda_trigger=false || cuda_trigger=true ;;
|
||||
2) [ "$rvc_trigger" == "true" ] && rvc_trigger=false || rvc_trigger=true ;;
|
||||
3) [ "$talkinghead_trigger" == "true" ] && talkinghead_trigger=false || talkinghead_trigger=true ;;
|
||||
4) [ "$caption_trigger" == "true" ] && caption_trigger=false || caption_trigger=true ;;
|
||||
5) [ "$summarize_trigger" == "true" ] && summarize_trigger=false || summarize_trigger=true ;;
|
||||
6) [ "$listen_trigger" == "true" ] && listen_trigger=false || listen_trigger=true ;;
|
||||
0) toolbox ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Save the module flags to modules.txt
|
||||
modules_file="$(dirname "$0")/modules.txt"
|
||||
echo "cuda_trigger=$cuda_trigger" > "$modules_file"
|
||||
echo "rvc_trigger=$rvc_trigger" >> "$modules_file"
|
||||
echo "talkinghead_trigger=$talkinghead_trigger" >> "$modules_file"
|
||||
echo "caption_trigger=$caption_trigger" >> "$modules_file"
|
||||
echo "summarize_trigger=$summarize_trigger" >> "$modules_file"
|
||||
echo "listen_trigger=$listen_trigger" >> "$modules_file"
|
||||
|
||||
# Initial module triggers
|
||||
xtts_trigger="false"
|
||||
rvc_trigger="false"
|
||||
talkinghead_trigger="false"
|
||||
caption_trigger="false"
|
||||
summarize_trigger="false"
|
||||
|
||||
# Function to save the module flags to modules.txt
|
||||
saveModuleFlags() {
|
||||
echo "xtts_trigger=$xtts_trigger" > "$PWD/modules.txt"
|
||||
echo "rvc_trigger=$rvc_trigger" >> "$PWD/modules.txt"
|
||||
echo "talkinghead_trigger=$talkinghead_trigger" >> "$PWD/modules.txt"
|
||||
echo "caption_trigger=$caption_trigger" >> "$PWD/modules.txt"
|
||||
echo "summarize_trigger=$summarize_trigger" >> "$PWD/modules.txt"
|
||||
}
|
||||
|
||||
# Function to compile the Python command
|
||||
compilePythonCommand() {
|
||||
# Compile the Python command
|
||||
python_command="python server.py"
|
||||
[ "$listen_trigger" == "true" ] && python_command+=" --listen"
|
||||
[ "$cuda_trigger" == "true" ] && python_command+=" --gpu 0 --cuda --cuda-device=0 "
|
||||
[ "$rvc_trigger" == "true" ] && python_command+=" --rvc-save-file --max-content-length=1000"
|
||||
modules_enable=""
|
||||
python_command="start cmd /k python server.py"
|
||||
[ "$talkinghead_trigger" == "true" ] && modules_enable+="talkinghead,"
|
||||
[ "$caption_trigger" == "true" ] && modules_enable+="caption,"
|
||||
[ "$summarize_trigger" == "true" ] && modules_enable+="summarize,"
|
||||
|
||||
if [ "$xtts_trigger" == "true" ]; then
|
||||
python_command="$python_command --gpu 0 --cuda-device=0"
|
||||
fi
|
||||
|
||||
if [ "$rvc_trigger" == "true" ]; then
|
||||
python_command="$python_command --rvc-save-file --max-content-length=1000"
|
||||
modules_enable="$modules_enable rvc,"
|
||||
fi
|
||||
|
||||
if [ "$talkinghead_trigger" == "true" ]; then
|
||||
modules_enable="$modules_enable talkinghead,"
|
||||
fi
|
||||
|
||||
if [ "$caption_trigger" == "true" ]; then
|
||||
modules_enable="$modules_enable caption,"
|
||||
fi
|
||||
|
||||
if [ "$summarize_trigger" == "true" ]; then
|
||||
modules_enable="$modules_enable summarize,"
|
||||
fi
|
||||
|
||||
# Remove the last comma
|
||||
if [ -n "$modules_enable" ]; then
|
||||
modules_enable="${modules_enable%,}"
|
||||
fi
|
||||
|
||||
# Check if modules_enable is not empty
|
||||
if [ -n "$modules_enable" ]; then
|
||||
python_command="$python_command --enable-modules=$modules_enable"
|
||||
fi
|
||||
# Remove the last comma from modules_enable
|
||||
modules_enable="${modules_enable%,}"
|
||||
|
||||
# Save the constructed Python command to modules.txt for testing
|
||||
echo "$python_command" >> "$PWD/modules.txt"
|
||||
echo "start_command=$python_command --enable-modules=$modules_enable" >> "$modules_file"
|
||||
edit_extras_modules
|
||||
}
|
||||
|
||||
|
||||
# Function to reinstall SillyTavern
|
||||
reinstall_sillytavern() {
|
||||
local script_name=$(basename "$0")
|
||||
@@ -753,7 +702,7 @@ reinstall_extras() {
|
||||
cd SillyTavern-extras
|
||||
|
||||
log_message "INFO" "Installing modules from requirements.txt..."
|
||||
pip install -r requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
log_message "DISCLAIMER" "The installation of Coqui requirements is not recommended unless you have a specific use case. It may conflict with additional dependencies and functionalities to your environment."
|
||||
log_message "INFO" "To learn more about Coqui, visit: https://docs.sillytavern.app/extras/installation/#decide-which-module-to-use"
|
||||
@@ -761,14 +710,14 @@ reinstall_extras() {
|
||||
read -p "Do you want to install Coqui TTS? [Y/N] " install_coqui_requirements
|
||||
|
||||
if [[ "$install_coqui_requirements" == [Yy] ]]; then
|
||||
log_message "INFO" "Installing pip requirements-coqui..."
|
||||
pip install -r requirements-coqui.txt
|
||||
log_message "INFO" "Installing pip3 requirements-coqui..."
|
||||
pip3 install -r requirements-coqui.txt
|
||||
else
|
||||
log_message "INFO" "Coqui requirements installation skipped."
|
||||
fi
|
||||
|
||||
log_message "INFO" "Installing pip requirements-rvc..."
|
||||
pip install -r requirements-rvc.txt
|
||||
log_message "INFO" "Installing pip3 requirements-rvc..."
|
||||
pip3 install -r requirements-rvc.txt
|
||||
|
||||
log_message "INFO" "${green_fg_strong}SillyTavern Extras reinstalled successfully.${reset}"
|
||||
else
|
||||
@@ -780,7 +729,6 @@ reinstall_extras() {
|
||||
|
||||
# Function to uninstall SillyTavern + Extras
|
||||
uninstall_st_extras() {
|
||||
|
||||
echo
|
||||
echo -e "${red_bg}╔════ DANGER ZONE ═══════════════════════════════════════════════════════════════════╗${reset}"
|
||||
echo -e "${red_bg}║ WARNING: This will delete all data in Sillytavern + Extras ║${reset}"
|
||||
@@ -805,6 +753,7 @@ uninstall_st_extras() {
|
||||
toolbox
|
||||
}
|
||||
|
||||
# Toolbox Menu - Frontend
|
||||
toolbox() {
|
||||
echo -e "\033]0;SillyTavern [TOOLBOX]\007"
|
||||
clear
|
||||
@@ -819,10 +768,11 @@ toolbox() {
|
||||
echo "6. Reinstall SillyTavern"
|
||||
echo "7. Reinstall Extras"
|
||||
echo "8. Uninstall SillyTavern + Extras"
|
||||
echo "9. Back to Home"
|
||||
echo "0. Back to Home"
|
||||
|
||||
read -p "Choose Your Destiny: " toolbox_choice
|
||||
|
||||
# Toolbox Menu - Backend
|
||||
case $toolbox_choice in
|
||||
1) install_7zip ;;
|
||||
2) install_ffmpeg ;;
|
||||
@@ -832,7 +782,7 @@ toolbox() {
|
||||
6) reinstall_sillytavern ;;
|
||||
7) reinstall_extras ;;
|
||||
8) uninstall_st_extras ;;
|
||||
9) home ;;
|
||||
0) home ;;
|
||||
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
|
||||
read -p "Press Enter to continue..."
|
||||
toolbox ;;
|
||||
|
||||
Reference in New Issue
Block a user