remove DOCKER_UTILS

This commit is contained in:
unknown
2025-02-13 08:35:36 -08:00
parent 5dde13af82
commit 7cc3f86f3b
7 changed files with 72 additions and 376 deletions

View File

@@ -1,53 +0,0 @@
# Use a minimal Debian-based image with GNU libc 2.35 or later
FROM debian:bookworm-slim
# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
ENV LANGUAGE=C.UTF-8
ENV QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox"
# Install required dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
wget \
xz-utils \
python3 \
python3-pip \
ffmpeg \
libegl1 \
libopengl0 \
libgl1-mesa-glx \
libxcb-cursor0 \
libxkbcommon0 \
libxkbfile1 \
libnss3 \
libx11-6 \
libxext6 \
libxrender1 \
libxtst6 \
libxrandr2 \
libxcomposite1 \
qtbase5-dev \
libqt5webenginecore5 \
libqt5webenginewidgets5 \
libqt5webchannel5 \
libqt5websockets5 && \
rm -rf /var/lib/apt/lists/*
# Install Calibre (specifically for CLI use like ebook-convert)
RUN wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin
# Add Calibre's CLI tools to PATH
ENV PATH="/opt/calibre:${PATH}"
# Default working directory
WORKDIR /app
# Modified ENTRYPOINT to print the command and its arguments
ENTRYPOINT ["/bin/sh", "-c", "echo 'Running command: $0 $@'; exec \"$0\" \"$@\""]
# CMD to pass arguments dynamically
CMD ["sh", "-c"]

5
app.py
View File

@@ -134,9 +134,8 @@ Linux/Mac:
'--version', '--help'
]
all_group = parser.add_argument_group('**** The following options are for all modes', 'Optional')
all_group.add_argument(options[0], type=str, help='''Mode the script will run. Accepted values are "native", "docker_utils", "full_docker".
Default mode is "native". "docker_utils" use a docker for ffmpeg and calibre.
"full_docker" cannot be used without a docker command.''')
all_group.add_argument(options[0], type=str, help='''Mode the script will run. Accepted values are "native" and "full_docker". Default mode is "native".
"full_docker" cannot be used without a docker command.''')
parser.add_argument(options[1], type=str, help='''Session to resume the conversion in case of interruption, crash,
or reuse of custom models and custom cloning voices.''')
gui_group = parser.add_argument_group('**** The following option are for gradio/gui mode only', 'Optional')

View File

@@ -5,14 +5,12 @@ setlocal enabledelayedexpansion
set "ARGS=%*"
set "NATIVE=native"
set "DOCKER_UTILS=docker_utils"
set "FULL_DOCKER=full_docker"
set "SCRIPT_MODE=%NATIVE%"
set "SCRIPT_DIR=%~dp0"
set "PYTHON_VERSION=3.12"
set "DOCKER_UTILS_IMG=utils"
set "PYTHON_ENV=python_env"
set "CURRENT_ENV="
set "PROGRAMS_LIST=calibre ffmpeg nodejs espeak-ng"
@@ -30,7 +28,6 @@ set "PROGRAMS_CHECK=0"
set "CONDA_CHECK_STATUS=0"
set "CONDA_RUN_INIT=0"
set "DOCKER_CHECK_STATUS=0"
set "DOCKER_BUILD_STATUS=0"
set "HELP_FOUND=%ARGS:--help=%"
@@ -39,13 +36,6 @@ for /f "tokens=2,*" %%A in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Se
set "PATH=%%B;%PATH%"
)
for %%A in (%ARGS%) do (
if "%%A"=="%DOCKER_UTILS%" (
set "SCRIPT_MODE=%DOCKER_UTILS%"
break
)
)
cd /d "%SCRIPT_DIR%"
:: Check if running inside Docker
@@ -93,13 +83,8 @@ if not defined conda_version (
echo This script runs with its own virtual env and must be out of any other virtual environment when it's launched.
goto failed
)
if "%SCRIPT_MODE%"=="%DOCKER_UTILS%" (
goto docker_check
exit /b
) else (
call :programs_check
exit /b
)
call :programs_check
exit /b
)
goto dispatch
exit /b
@@ -133,26 +118,8 @@ if %errorlevel% neq 0 (
if %errorlevel% neq 0 (
set "DOCKER_CHECK_STATUS=1"
) else (
:: Check if the Docker socket is running
set "docker_socket="
if exist \\.\pipe\docker_engine (
set "docker_socket=Windows"
)
if not defined docker_socket (
echo Cannot connect to docker socket. Check if the docker socket is running.
goto failed
exit /b
) else (
:: Check if the Docker image is available
call docker images -q %DOCKER_UTILS_IMG% >nul 2>&1
if %errorlevel% neq 0 (
echo Docker image '%DOCKER_UTILS_IMG%' not found. Installing it now...
set "DOCKER_BUILD_STATUS=1"
) else (
goto dispatch
exit /b
)
)
goto dispatch
exit /b
)
)
goto install_components
@@ -211,17 +178,6 @@ if not "%DOCKER_CHECK_STATUS%"=="0" (
)
)
)
:: Build Docker image if required
if not "%DOCKER_BUILD_STATUS%"=="0" (
call conda activate "%SCRIPT_DIR%\%PYTHON_ENV%"
call python -m pip install -e .
call docker build -f DockerfileUtils -t utils .
call conda deactivate
call docker images -q %DOCKER_UTILS_IMG% >nul 2>&1
if %errorlevel% equ 0 (
set "DOCKER_BUILD_STATUS=0"
)
)
goto dispatch
exit /b
@@ -229,10 +185,8 @@ exit /b
if "%PROGRAMS_CHECK%"=="0" (
if "%CONDA_CHECK_STATUS%"=="0" (
if "%DOCKER_CHECK_STATUS%"=="0" (
if "%DOCKER_BUILD_STATUS%"=="0" (
goto main
exit /b
)
goto main
exit /b
) else (
goto failed
exit /b
@@ -242,7 +196,6 @@ if "%PROGRAMS_CHECK%"=="0" (
echo PROGRAMS_CHECK: %PROGRAMS_CHECK%
echo CONDA_CHECK_STATUS: %CONDA_CHECK_STATUS%
echo DOCKER_CHECK_STATUS: %DOCKER_CHECK_STATUS%
echo DOCKER_BUILD_STATUS: %DOCKER_BUILD_STATUS%
timeout /t 5 /nobreak >nul
goto install_components
exit /b

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
if [[ -z "$SWITCHED_TO_ZSH" && "$SHELL" = */bin/zsh ]]; then
if [[ -z "$SWITCHED_TO_ZSH" && "$SHELL" = */zsh ]]; then
SWITCHED_TO_ZSH=1 exec env zsh "$0" "$@"
fi
@@ -35,7 +35,6 @@ while [[ "$#" -gt 0 ]]; do
done
NATIVE="native"
DOCKER_UTILS="docker_utils"
FULL_DOCKER="full_docker"
SCRIPT_MODE="$NATIVE"
@@ -45,7 +44,6 @@ TMPDIR=./.cache
WGET=$(which wget 2>/dev/null)
REQUIRED_PROGRAMS=("calibre" "ffmpeg" "mecab" "nodejs" "espeak" "espeak-ng" "rustc" "cargo")
DOCKER_UTILS_IMG="utils"
PYTHON_ENV="python_env"
CURRENT_ENV=""
@@ -90,7 +88,7 @@ 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
if [ "${arguments['script_mode']}" = "$NATIVE" ]; then
SCRIPT_MODE="${arguments['script_mode']}"
fi
fi
@@ -244,9 +242,6 @@ else
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
}
@@ -302,35 +297,14 @@ else
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
elif [ "$SCRIPT_MODE" = "$NATIVE" ]; then
pass=true
echo -e "\e[33mRunning in $SCRIPT_MODE mode\e[0m"
if [ "$SCRIPT_MODE" = "$NATIVE" ]; then

View File

@@ -13,19 +13,19 @@ from lib.models import models
class VoiceExtractor:
def __init__(self, session, models_dir, input_file, voice_name):
def __init__(self, session, models_dir, voice_file, voice_name):
self.wav_file = None
self.session = session
self.input_file = input_file
self.voice_file = voice_file
self.voice_name = voice_name
self.models_dir = models_dir
self.voice_track = 'vocals.wav'
self.samplerate = models[session['tts_engine']][session['fine_tuned']]['samplerate']
self.output_dir = self.session['voice_dir']
self.demucs_dir = os.path.join(self.output_dir, 'htdemucs', os.path.splitext(os.path.basename(self.input_file))[0])
self.demucs_dir = os.path.join(self.output_dir, 'htdemucs', os.path.splitext(os.path.basename(self.voice_file))[0])
def _validate_format(self):
file_extension = os.path.splitext(self.input_file)[1].lower()
file_extension = os.path.splitext(self.voice_file)[1].lower()
if file_extension in voice_formats:
msg = 'Input file valid'
return True, msg
@@ -34,18 +34,14 @@ class VoiceExtractor:
def _convert_to_wav(self):
try:
if not self.input_file.lower().endswith(f'_{self.samplerate}.wav'):
self.wav_file = os.path.join(os.path.dirname(self.input_file), os.path.basename(self.input_file).replace(os.path.splitext(self.input_file)[1], '.wav'))
process = (
ffmpeg
.input(self.input_file)
.output(self.wav_file, format='wav', ar=self.samplerate, ac=1)
.run(overwrite_output=True)
)
msg = 'Conversion to .wav format for processing successful'
else:
self.wav_file = self.input_file
msg = 'File is already a .wav format'
self.wav_file = os.path.join(self.session['voice_dir'], os.path.basename(self.voice_file).replace(os.path.splitext(self.voice_file)[1], '.wav'))
process = (
ffmpeg
.input(self.voice_file)
.output(self.wav_file, format='wav', ar=self.samplerate, ac=1)
.run(overwrite_output=True)
)
msg = 'Conversion to .wav format for processing successful'
return True, msg
except ffmpeg.Error as e:
error = f'convert_to_wav fmpeg.Error: {e.stderr.decode()}'

View File

@@ -6,7 +6,6 @@ min_python_version = (3,12)
max_python_version = (3,12)
NATIVE = 'native'
DOCKER_UTILS = 'docker_utils'
FULL_DOCKER = 'full_docker'
debug_mode = True
@@ -16,7 +15,6 @@ default_device = "cuda"
python_env_dir = os.path.abspath(os.path.join('.','python_env'))
requirements_file = os.path.abspath(os.path.join('.','requirements.txt'))
docker_utils_image = 'utils'
interface_host = '0.0.0.0'
interface_port = 7860

View File

@@ -428,72 +428,32 @@ def convert_to_epub(session):
if session['cancellation_requested']:
print('Cancel requested')
return False
if session['script_mode'] == DOCKER_UTILS:
try:
docker_dir = os.path.basename(session['process_dir'])
docker_file_in = os.path.basename(session['ebook'])
docker_file_out = os.path.basename(session['epub_path'])
# Check if the input file is already an EPUB
if docker_file_in.lower().endswith('.epub'):
shutil.copy(session['ebook'], session['epub_path'])
print("File is already in EPUB format. Copying directly.")
return True
# Convert using Docker
print(f"Starting Docker container to convert {docker_file_in} to EPUB.")
container_logs = session['client'].containers.run(
docker_utils_image,
command=f'ebook-convert /files/{docker_dir}/{docker_file_in} /files/{docker_dir}/{docker_file_out} --input-encoding=utf-8 --output-profile=generic_eink --verbose',
volumes={session['process_dir']: {'bind': f'/files/{docker_dir}', 'mode': 'rw'}},
remove=True,
detach=False,
stdout=True,
stderr=True
)
print(container_logs.decode('utf-8'))
return True
except docker.errors.ContainerError as e:
print(f"Docker container error: {e}")
DependencyError(e)
try:
util_app = shutil.which('ebook-convert')
if not util_app:
error = "The 'ebook-convert' utility is not installed or not found."
print(error)
return False
except docker.errors.ImageNotFound as e:
print(f"Docker image not found: {e}")
DependencyError(e)
return False
except docker.errors.APIError as e:
print(f"Docker API error: {e}")
DependencyError(e)
return False
else:
try:
util_app = shutil.which('ebook-convert')
if not util_app:
error = "The 'ebook-convert' utility is not installed or not found."
print(error)
return False
print(f"Running command: {util_app} {session['ebook']} {session['epub_path']} --input-encoding=utf-8 --output-profile=generic_eink --verbose")
result = subprocess.run(
[util_app, session['ebook'], session['epub_path'], '--input-encoding=utf-8', '--output-profile=generic_eink', '--verbose'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
universal_newlines=True,
encoding='utf-8'
)
print(result.stdout)
return True
print(f"Running command: {util_app} {session['ebook']} {session['epub_path']} --input-encoding=utf-8 --output-profile=generic_eink --verbose")
result = subprocess.run(
[util_app, session['ebook'], session['epub_path'], '--input-encoding=utf-8', '--output-profile=generic_eink', '--verbose'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
universal_newlines=True,
encoding='utf-8'
)
print(result.stdout)
return True
except subprocess.CalledProcessError as e:
print(f"Subprocess error: {e.stderr}")
DependencyError(e)
return False
except FileNotFoundError as e:
print(f"Utility not found: {e}")
DependencyError(e)
return False
except subprocess.CalledProcessError as e:
print(f"Subprocess error: {e.stderr}")
DependencyError(e)
return False
except FileNotFoundError as e:
print(f"Utility not found: {e}")
DependencyError(e)
return False
def get_cover(epubBook, session):
try:
@@ -655,101 +615,6 @@ def get_sanitized(str, replacement="_"):
sanitized = sanitized.strip()
return sanitized
def normalize_voice_file(f, session):
if re.search(r'_(16000|24000)\.wav$', f):
return f
else:
final_name = os.path.splitext(os.path.basename(f))[0].replace('&', 'And').replace(' ', '_') + '.wav'
final_name = get_sanitized(final_name)
final_file = os.path.join(session['voice_dir'], final_name)
if session['script_mode'] == DOCKER_UTILS:
docker_dir = os.path.basename(session['voice_dir'])
ffmpeg_input_file = f'/files/{docker_dir}/' + os.path.basename(f)
ffmpeg_final_file = f'/files/{docker_dir}/' + os.path.basename(final_file)
ffmpeg_cmd = ['ffmpeg', '-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda', '-i', ffmpeg_input_file]
else:
ffmpeg_input_file = f
ffmpeg_final_file = final_file
ffmpeg_cmd = [shutil.which('ffmpeg'), '-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda', '-i', ffmpeg_input_file]
ffmpeg_cmd += [
'-strict', 'experimental',
'-filter_complex', '[0:a]'
'agate=threshold=-25dB:ratio=1.4:attack=10:release=250,'
'afftdn=nf=-70,'
'acompressor=threshold=-20dB:ratio=2:attack=80:release=200:makeup=1dB,'
'loudnorm=I=-14:TP=-3:LRA=7:linear=true,'
'equalizer=f=150:t=q:w=2:g=1,'
'equalizer=f=250:t=q:w=2:g=-3,'
'equalizer=f=3000:t=q:w=2:g=2,'
'equalizer=f=5500:t=q:w=2:g=-4,'
'equalizer=f=9000:t=q:w=2:g=-2,'
'highpass=f=63,'
'pan=mono|c0=0.5*FL+0.5*FR[audio]',
'-map', '[audio]',
'-ar', '16000',
'-y', ffmpeg_final_file
]
error = None
for rate in ['16000', '24000']:
ffmpeg_cmd[-3] = str(rate)
ffmpeg_cmd[-1] = final_file.replace('.wav', f'_{rate}.wav')
if session['script_mode'] == DOCKER_UTILS:
try:
container = session['client'].containers.run(
docker_utils_image,
command=ffmpeg_cmd,
volumes={session['voice_dir']: {'bind': f'/files/{docker_dir}', 'mode': 'rw'}},
remove=True,
detach=False,
stdout=True,
stderr=True
)
print(container.decode('utf-8', errors='replace'))
if not shutil.copy(docker_final_file, final_file):
error = f'Could not copy from {docker_final_file} to {final_file}'
except docker.errors.ContainerError as e:
error = f"normalize_voice_file() error: {e}"
pass
break
except docker.errors.ImageNotFound as e:
error = f"normalize_voice_file() error: {e}"
pass
break
except docker.errors.APIError as e:
error = f"normalize_voice_file() error: {e}"
pass
break
else:
try:
process = subprocess.Popen(
ffmpeg_cmd,
env={},
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
universal_newlines=True,
encoding='utf-8'
)
for line in process.stdout:
print(line, end='') # Print each line of stdout
process.wait()
if process.returncode != 0:
error = f'normalize_voice_file(): process.returncode: {process.returncode}'
break
except subprocess.CalledProcessError as e:
error = f"normalize_voice_file() error: {e}"
pass
break
except Exception as e:
error = f"normalize_voice_file() error: {e}"
pass
break
if error is not None:
print(error)
return None
else:
return final_file.replace('.wav','_24000.wav')
def convert_chapters_to_audio(session):
try:
if session['cancellation_requested']:
@@ -940,21 +805,12 @@ def combine_audio_chapters(session):
print('Cancel requested')
return False
ffmpeg_cover = None
if session['script_mode'] == DOCKER_UTILS:
docker_dir = os.path.basename(session['process_dir'])
ffmpeg_combined_audio = f'/files/{docker_dir}/' + os.path.basename(combined_chapters_file)
ffmpeg_metadata_file = f'/files/{docker_dir}/' + os.path.basename(metadata_file)
ffmpeg_final_file = f'/files/{docker_dir}/' + os.path.basename(docker_final_file)
if session['cover'] is not None:
ffmpeg_cover = f'/files/{docker_dir}/' + os.path.basename(session['cover'])
ffmpeg_cmd = ['ffmpeg', '-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda', '-i', ffmpeg_combined_audio, '-i', ffmpeg_metadata_file]
else:
ffmpeg_combined_audio = combined_chapters_file
ffmpeg_metadata_file = metadata_file
ffmpeg_final_file = final_file
if session['cover'] is not None:
ffmpeg_cover = session['cover']
ffmpeg_cmd = [shutil.which('ffmpeg'), '-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda', '-i', ffmpeg_combined_audio, '-i', ffmpeg_metadata_file]
ffmpeg_combined_audio = combined_chapters_file
ffmpeg_metadata_file = metadata_file
ffmpeg_final_file = final_file
if session['cover'] is not None:
ffmpeg_cover = session['cover']
ffmpeg_cmd = [shutil.which('ffmpeg'), '-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda', '-i', ffmpeg_combined_audio, '-i', ffmpeg_metadata_file]
if session['output_format'] == 'wav':
ffmpeg_cmd += ['-map', '0:a']
elif session['output_format'] == 'aac':
@@ -997,51 +853,26 @@ def combine_audio_chapters(session):
ffmpeg_cmd += ['-af', 'afftdn=nf=-70']
ffmpeg_cmd += ['-strict', 'experimental', '-map_metadata', '1']
ffmpeg_cmd += ['-threads', '8', '-y', ffmpeg_final_file]
if session['script_mode'] == DOCKER_UTILS:
try:
container = session['client'].containers.run(
docker_utils_image,
command=ffmpeg_cmd,
volumes={session['process_dir']: {'bind': f'/files/{docker_dir}', 'mode': 'rw'}},
remove=True,
detach=False,
stdout=True,
stderr=True
)
print(container.decode('utf-8', errors='replace'))
if shutil.copy(docker_final_file, final_file):
return True
return False
except docker.errors.ContainerError as e:
DependencyError(e)
return False
except docker.errors.ImageNotFound as e:
DependencyError(e)
return False
except docker.errors.APIError as e:
DependencyError(e)
return False
else:
try:
process = subprocess.Popen(
ffmpeg_cmd,
env={},
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding='utf-8'
)
for line in process.stdout:
print(line, end='') # Print each line of stdout
process.wait()
if process.returncode == 0:
return True
else:
error = process.returncode
print(error, ffmpeg_cmd)
return False
except subprocess.CalledProcessError as e:
DependencyError(e)
try:
process = subprocess.Popen(
ffmpeg_cmd,
env={},
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding='utf-8'
)
for line in process.stdout:
print(line, end='') # Print each line of stdout
process.wait()
if process.returncode == 0:
return True
else:
error = process.returncode
print(error, ffmpeg_cmd)
return False
except subprocess.CalledProcessError as e:
DependencyError(e)
return False
except Exception as e:
DependencyError(e)
@@ -1276,8 +1107,6 @@ def convert_ebook(args):
bool, e = check_programs('FFmpeg', 'ffmpeg', '-version')
if not bool:
error = f'check_programs() FFMPEG failed: {e}'
elif session['script_mode'] == DOCKER_UTILS:
session['client'] = docker.from_env()
if error is None:
session['session_dir'] = os.path.join(tmp_dir, f"ebook-{session['id']}")