ebook2audiobook / ebook2audiobook.sh
drewThomasson's picture
v2.0 will add the voices folder in a sec
fc032f5
#!/usr/bin/env bash
PYTHON_VERSION="3.12"
export TTS_CACHE="./models"
ARGS="$@"
# Declare an associative array
declare -A arguments
# Parse arguments
while [[ "$#" -gt 0 ]]; do
case "$1" in
--*)
key="${1/--/}" # Remove leading '--'
if [[ -n "$2" && ! "$2" =~ ^-- ]]; then
# If the next argument is a value (not another option)
arguments[$key]="$2"
shift # Move past the value
else
# Set to true for flags without values
arguments[$key]=true
fi
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
shift # Move to the next argument
done
NATIVE="native"
DOCKER_UTILS="docker_utils"
FULL_DOCKER="full_docker"
SCRIPT_MODE="$NATIVE"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WGET=$(which wget 2>/dev/null)
REQUIRED_PROGRAMS=("calibre" "ffmpeg")
DOCKER_UTILS_IMG="utils"
PYTHON_ENV="python_env"
CURRENT_ENV=""
if [[ "$OSTYPE" = "darwin"* ]]; then
CONDA_URL="https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh"
else
CONDA_URL="https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh"
fi
CONDA_INSTALLER=/tmp/Miniconda3-latest.sh
CONDA_INSTALL_DIR=$HOME/miniconda3
CONDA_PATH=$HOME/miniconda3/bin
CONDA_ENV=~/miniconda3/etc/profile.d/conda.sh
CONFIG_FILE="$HOME/.bashrc"
PATH="$CONDA_PATH:$PATH"
declare -a programs_missing
# Check if the current script is run inside a docker container
if [[ -n "$container" || -f /.dockerenv ]]; then
SCRIPT_MODE="$FULL_DOCKER"
else
if [[ -n "${arguments['script_mode']+exists}" ]]; then
if [ "${arguments['script_mode']}" = "$NATIVE" ] || [ "${arguments['script_mode']}" = "$DOCKER_UTILS" ]; then
SCRIPT_MODE="${arguments['script_mode']}"
fi
fi
fi
# Check if running in a Conda or Python virtual environment
if [[ -n "$CONDA_DEFAULT_ENV" ]]; then
CURRENT_ENV="$CONDA_PREFIX"
elif [[ -n "$VIRTUAL_ENV" ]]; then
CURRENT_ENV="$VIRTUAL_ENV"
fi
# If neither environment variable is set, check Python path
if [[ -z "$CURRENT_ENV" ]]; then
PYTHON_PATH=$(which python 2>/dev/null)
if [[ ( -n "$CONDA_PREFIX" && "$PYTHON_PATH" == "$CONDA_PREFIX/bin/python" ) || ( -n "$VIRTUAL_ENV" && "$PYTHON_PATH" == "$VIRTUAL_ENV/bin/python" ) ]]; then
CURRENT_ENV="${CONDA_PREFIX:-$VIRTUAL_ENV}"
fi
fi
# Output result if a virtual environment is detected
if [[ -n "$CURRENT_ENV" ]]; then
echo -e "Current python virtual environment detected: $CURRENT_ENV."
echo -e "This script runs with its own virtual env and must be out of any other virtual environment when it's launched."
echo -e "If you are using miniconda then you would type in:"
echo -e "conda deactivate"
exit 1
fi
function required_programs_check {
local programs=("$@")
for program in "${programs[@]}"; do
if ! command -v "$program" >/dev/null 2>&1; then
echo -e "\e[33m$program is not installed.\e[0m"
programs_missing+=($program)
fi
done
local count=${#programs_missing[@]}
if [[ $count -eq 0 ]]; then
return 0
else
return 1
fi
}
function install_programs {
echo -e "\e[33mInstalling required programs. NOTE: you must have 'sudo' priviliges or it will fail.\e[0m"
if [[ "$OSTYPE" = "darwin"* ]]; then
PACK_MGR="brew install"
if ! command -v brew &> /dev/null; then
echo -e "\e[33mHomebrew is not installed. Installing Homebrew...\e[0m"
/usr/bin/env bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
fi
else
if command -v emerge &> /dev/null; then
PACK_MGR="sudo emerge"
elif command -v dnf &> /dev/null; then
PACK_MGR="sudo dnf install"
PACK_MGR_OPTIONS="-y"
elif command -v yum &> /dev/null; then
PACK_MGR="sudo yum install"
PACK_MGR_OPTIONS="-y"
elif command -v zypper &> /dev/null; then
PACK_MGR="sudo zypper install"
PACK_MGR_OPTIONS="-y"
elif command -v pacman &> /dev/null; then
PACK_MGR="sudo pacman -Sy"
elif command -v apt-get &> /dev/null; then
sudo apt-get update
PACK_MGR="sudo apt-get install"
PACK_MGR_OPTIONS="-y"
elif command -v apk &> /dev/null; then
PACK_MGR="sudo apk add"
else
echo "Cannot recognize your applications package manager. Please install the required applications manually."
return 1
fi
fi
if [ -z "$WGET" ]; then
echo -e "\e[33m wget is missing! trying to install it... \e[0m"
result=$(eval "$PACK_MGR wget $PACK_MGR_OPTIONS" 2>&1)
result_code=$?
if [ $result_code -eq 0 ]; then
WGET=$(which wget 2>/dev/null)
else
echo "Cannot 'wget'. Please install 'wget' manually."
return 1
fi
fi
for program in "${programs_missing[@]}"; do
if [ "$program" = "calibre" ];then
# avoid conflict with calibre builtin lxml
pip uninstall lxml -y 2>/dev/null
echo -e "\e[33mInstalling Calibre...\e[0m"
if [[ "$OSTYPE" = "darwin"* ]]; then
eval "$PACK_MGR --cask calibre"
else
$WGET -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin
fi
if command -v calibre >/dev/null 2>&1; then
echo -e "\e[32m===============>>> Calibre is installed! <<===============\e[0m"
else
echo "Calibre installation failed."
fi
else
eval "$PACK_MGR $program $PKG_MGR_OPTIONS"
if command -v $program >/dev/null 2>&1; then
echo -e "\e[32m===============>>> $program is installed! <<===============\e[0m"
else
echo "$program installation failed."
fi
fi
done
if required_programs_check "${REQUIRED_PROGRAMS[@]}"; then
return 0
else
echo -e "\e[33mYou can run 'ebook2audiobook.sh --script_mode docker_utils' to avoid to install $REQUIRED_PROGRAMS natively.\e[0m"
return 1
fi
}
function conda_check {
if ! command -v conda &> /dev/null; then
echo -e "\e[33mconda is not installed!\e[0m"
echo -e "\e[33mDownloading conda installer...\e[0m"
wget -O "$CONDA_INSTALLER" "$CONDA_URL"
if [[ -f "$CONDA_INSTALLER" ]]; then
echo -e "\e[33mInstalling Miniconda...\e[0m"
bash "$CONDA_INSTALLER" -u -b -p "$CONDA_INSTALL_DIR"
rm -f "$CONDA_INSTALLER"
if [[ -f "$CONDA_INSTALL_DIR/bin/conda" ]]; then
conda init
echo -e "\e[32m===============>>> conda is installed! <<===============\e[0m"
else
echo -e "\e[31mconda installation failed.\e[0m"
return 1
fi
else
echo -e "\e[31mFailed to download Miniconda installer.\e[0m"
echo -e "\e[33mI'ts better to use the install.sh to install everything needed.\e[0m"
return 1
fi
fi
if [[ ! -d $SCRIPT_DIR/$PYTHON_ENV ]]; then
# Use this condition to chmod writable folders once
chmod -R 777 ./audiobooks ./tmp ./models
conda create --prefix $SCRIPT_DIR/$PYTHON_ENV python=$PYTHON_VERSION -y
source $CONDA_ENV
conda activate $SCRIPT_DIR/$PYTHON_ENV
python -m pip install --upgrade pip
python -m pip install --upgrade -r requirements.txt --progress-bar=on
conda deactivate
fi
return 0
}
function docker_check {
if ! command -v docker &> /dev/null; then
echo -e "\e[33m docker is missing! trying to install it... \e[0m"
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "Installing Docker using Homebrew..."
$PACK_MGR --cask docker $PACK_MGR_OPTIONS
else
$WGET -qO get-docker.sh https://get.docker.com && \
sudo sh get-docker.sh
sudo systemctl start docker
sudo systemctl enable docker
docker run hello-world
rm -f get-docker.sh
fi
echo -e "\e[32m===============>>> docker is installed! <<===============\e[0m"
docker_build
else
# Check if Docker service is running
if docker info >/dev/null 2>&1; then
if [[ "$(docker images -q $DOCKER_UTILS_IMG 2> /dev/null)" = "" ]]; then
docker_build
fi
else
echo -e "\e[33mDocker is not running\e[0m"
return 1
fi
fi
return 0
}
function docker_build {
# Check if the Docker socket is accessible
if [[ -e /var/run/docker.sock || -e /run/docker.sock ]]; then
echo -e "\e[33mDocker image '$DOCKER_UTILS_IMG' not found. Trying to build it...\e[0m"
docker build -f DockerfileUtils -t utils .
else
echo -e "\e[33mcannot connect to docker socket. Check if the docker socket is running.\e[0m"
fi
}
if [ "$SCRIPT_MODE" = "$FULL_DOCKER" ]; then
echo -e "\e[33mRunning in $FULL_DOCKER mode\e[0m"
python app.py --script_mode $SCRIPT_MODE $ARGS
elif [[ "$SCRIPT_MODE" == "$NATIVE" || "$SCRIPT_MODE" = "$DOCKER_UTILS" ]]; then
pass=true
if [ "$SCRIPT_MODE" == "$NATIVE" ]; then
echo -e "\e[33mRunning in $NATIVE mode\e[0m"
if ! required_programs_check "${REQUIRED_PROGRAMS[@]}"; then
if ! install_programs; then
pass=false
fi
fi
else
echo -e "\e[33mRunning in $DOCKER_UTILS mode\e[0m"
if conda_check; then
if docker_check; then
source $CONDA_ENV
conda activate $SCRIPT_DIR/$PYTHON_ENV
python app.py --script_mode $DOCKER_UTILS $ARGS
conda deactivate
fi
fi
fi
if [ $pass = true ]; then
if conda_check; then
source $CONDA_ENV
conda activate $SCRIPT_DIR/$PYTHON_ENV
python app.py --script_mode $SCRIPT_MODE $ARGS
conda deactivate
fi
fi
else
echo -e "\e[33mebook2audiobook is not correctly installed or run.\e[0m"
fi
exit 0