Archive libre_translate.sh: unused, moved to testsAndMisc-archive

Full history preserved via git filter-repo, including both pre-reorg
root paths (libre_translate.sh and the subtree-imported
Bash/libre_translate.sh) since both were genuine ancestors of the
current file. Live at
github.com/kuhyx/testsAndMisc-archive/tree/main/linux_configuration/scripts/single_use/misc/testsAndMisc-bash.

Asked the dead-code check-in before any split work started this time,
per the lesson from the plagiarism-tools session. NEXT_SESSION_PROMPT.md
now points at diagnose_pacman_hook_stall.sh.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
This commit is contained in:
Krzysztof Rudnicki 2026-08-18 21:00:33 +02:00
parent 080a1664e0
commit 357c9d0032
3 changed files with 92 additions and 527 deletions

View File

@ -1,10 +1,10 @@
# Next session: §3's second restructure — libre_translate.sh
# Next session: §3's next restructure — diagnose_pacman_hook_stall.sh
> **Paste this whole file into a fresh Claude session opened in `~/testsAndMisc`.**
> It is self-contained. Do not go looking for the previous session's context.
Over-cap: **14** (12 shell, 2 kotlin, 1 dart). Working tree clean, `main` in
sync as of commit `071d706`.
Over-cap: **13** (11 shell, 2 kotlin, 1 dart). Working tree clean, `main` in
sync as of the libre_translate.sh archival commit (see §0.5).
Two standing decisions from the user, already made — do **not** re-litigate:
@ -34,45 +34,50 @@ be worth a one-line check-in — "do you still use this?" — for anything that
looks like it could be dead code, especially in `single_use/` directories.
Not a blocking gate, just don't be surprised if the answer changes scope.
## 1. This session's task: `libre_translate.sh` (488 lines, 18 functions)
## 0.5. What just happened (this session) — libre_translate.sh archived, not split
Location: `linux_configuration/scripts/single_use/misc/testsAndMisc-bash/libre_translate.sh`
Asked the same one-line check-in the §0 lesson above recommends, *before*
starting the split (grill-gate questions, before any code was touched this
time). User confirmed `libre_translate.sh` is also unused. Same resolution as
the plagiarism tools: moved to `kuhyx/testsAndMisc-archive` with full git
history via `git filter-repo`, and deleted from this repo. See the evidence
file `docs/superpowers/evidence/archive-libre-translate-2026-08-18.json` for
the exact recipe — this file's history was more tangled than the plagiarism
tools' (two independent pre-reorg root paths, `libre_translate.sh` and
`Bash/libre_translate.sh`, both genuine ancestors via a subtree-import merge)
so both had to be passed to `--path` or history would have been silently
truncated.
**The user already chose the approach** (from the original brief, still
valid): move the whole config-globals cluster into **one lib that owns both
the writes and the reads**. Do not try relocating `parse_args` alone — four
attempts at that failed in an earlier session. Read the file fully before
planning the split; it has real functions already (unlike
`install_plagiarism_tools.sh`, which had almost none), so
`meta/scripts/extract_shell_functions.py` and
`meta/scripts/verify_shell_split.sh` are the right tools here — they were
mostly _inapplicable_ to the plagiarism installer because it lacked function
structure, but this file has 18 functions and should fit their intended use
case.
**Lesson reinforced:** the §0 check-in is now 2 for 2 on `single_use/` files
turning out to be dead code. Keep asking it before every future §3/§4 split,
not just when something "looks like" it could be unused.
## 1. This session's task: `diagnose_pacman_hook_stall.sh`
Location: `linux_configuration/scripts/single_use/fixes/diagnose_pacman_hook_stall.sh`
(493 lines, 15 functions).
**Ask the dead-code check-in first** (see §0.5) — do not assume this one is
live just because the first two candidates weren't.
If it's confirmed live: `run_one` writes `LAST_ELAPSED`, `main` reads it —
that global crosses the split seam deliberately (see the SC2034 rule in §5
below), so it must stay in whichever file both functions land in, or get
passed explicitly. Emits **SC2153** (`PACMAN_BIN` vs `PACMAN_PID`) once
split — a real finding to resolve, never to suppress.
**Before you start**, confirm scope hasn't drifted: `git status --short` and
`wc -l` on the target file, same as the check that caught the plagiarism
tools were unused this time — it's cheap insurance.
## 2. Also outstanding in §3
`diagnose_pacman_hook_stall.sh` (493 lines, 15 functions) —
`linux_configuration/scripts/single_use/fixes/diagnose_pacman_hook_stall.sh`.
`run_one` writes `LAST_ELAPSED`, `main` reads it — that global crosses the
split seam deliberately (see the SC2034 rule in §5 below), so it must stay in
whichever file both functions land in, or get passed explicitly. Emits
**SC2153** (`PACMAN_BIN` vs `PACMAN_PID`) once split — a real finding to
resolve, never to suppress. Do `libre_translate.sh` first; this one waits its
turn.
`wc -l` on the target file, same as the check that caught both prior files
were unused — it's cheap insurance.
## 3. §4 — do not touch this session
`install_leechblock.sh` (485) and `block_compulsive_opening.sh` (705) are
copied to `/usr/local/…`, and `pacman_wrapper.sh:831` prefers the deployed
copy on **every pacman invocation**. Splitting them naively breaks every
`pacman -S` on this machine. Out of scope until `libre_translate.sh` and
`diagnose_pacman_hook_stall.sh` are both done and the user explicitly says to
continue into §4.
`pacman -S` on this machine. Out of scope until `diagnose_pacman_hook_stall.sh`
is done (or archived — see §0.5) and the user explicitly says to continue
into §4.
You cannot run `sudo pacman -S` from the Bash tool — it deadlocks on
`db.lck`. Hand the user a `! sudo pacman -S <pkg>` line plus the expected
@ -166,10 +171,10 @@ new paths too, or it reports a false `DIFFERENCE`.
**`meta/scripts/mutate_shell.py <spec>`** — mutation testing against specs in
`meta/scripts/fixtures/mutations/`. No spec currently exists for
`libre_translate.sh` or anything outside `phone_focus_mode/`; creating one is
optional, not required by the brief — 100% line coverage with real assertions
is the stated bar, mutation testing is what `phone_focus_mode` additionally
did.
`diagnose_pacman_hook_stall.sh` or anything outside `phone_focus_mode/`;
creating one is optional, not required by the brief — 100% line coverage with
real assertions is the stated bar, mutation testing is what `phone_focus_mode`
additionally did.
## 7. Testing pattern to follow
@ -196,6 +201,7 @@ Last session's plagiarism-tools split established a working pattern for
`exit` always terminates the process regardless of `if`/`&&` context. Run
it in a subshell: `if (fn args); then ...`.
Check `libre_translate.sh` for anything that shells out (curl? systemctl?
some translate CLI?) before assuming the same fakes apply — it's a different
domain from the plagiarism installer, so the PATH-shim list will differ.
Check `diagnose_pacman_hook_stall.sh` for anything that shells out (pacman?
systemctl? journalctl?) before assuming the same fakes apply — it's a
different domain from the plagiarism installer, so the PATH-shim list will
differ.

View File

@ -0,0 +1,47 @@
{
"intent": "Move the unused libre_translate.sh (LibreTranslate Docker setup script, next §3 restructure target per NEXT_SESSION_PROMPT.md) out of testsAndMisc into testsAndMisc-archive with full git history, per the user's explicit statement that they no longer use it -- decided before any split work began, avoiding the wasted-split outcome from the prior plagiarism-tools session.",
"scope": [
"linux_configuration/scripts/single_use/misc/testsAndMisc-bash/libre_translate.sh (deleted)",
"kuhyx/testsAndMisc-archive: same file added, with full history including both pre-reorg root paths",
"Not in scope: diagnose_pacman_hook_stall.sh, install_leechblock.sh, block_compulsive_opening.sh, or any other §3/§4 file -- user only confirmed libre_translate.sh is unused"
],
"changes": [
"Cloned testsAndMisc into a throwaway scratchpad location (never a worktree of the real repo, since git filter-repo rewrites refs and a worktree shares the object store).",
"Discovered the file has two independent pre-reorg root paths merged via subtree imports: libre_translate.sh (original, commit abba033) and Bash/libre_translate.sh (subtree-imported from the old Bash/ directory, commit 022f5c6, later moved to kuhyx/linux-configuration and re-imported into this repo's linux_configuration/ subtree at a0a2dc1). Both are genuine ancestors of the current file (verified with git merge-base --is-ancestor), unlike a simple single-path rename.",
"Ran git filter-repo --force with explicit --path for all three paths (current path, libre_translate.sh, Bash/libre_translate.sh) so history from both convergent lineages was preserved rather than only the most recent rename chain.",
"Cloned testsAndMisc-archive separately, added the filtered clone as a remote, and merged it in with --allow-unrelated-histories (required since the two repos share no common root commit).",
"Removed the filtered-clone remote and confirmed no stray remote-tracking branches (copilot-wt, etc.) leaked into the local branch list before pushing.",
"Verified the merge landed the file with git ls-tree and pushed to testsAndMisc-archive, then confirmed live via the GitHub contents API and commit-history API before touching the main repo.",
"Only after the archive push was confirmed live: git rm the file from testsAndMisc and committed the deletion."
],
"verification": [
{
"command": "gh api repos/kuhyx/testsAndMisc-archive/contents/linux_configuration/scripts/single_use/misc/testsAndMisc-bash",
"result": "pass",
"evidence": "Returned libre_translate.sh, sha 916bf1573edf5e797ac52e93403a47ce0391cb40, 13682 bytes -- confirmed live on GitHub before the main-repo deletion commit was made."
},
{
"command": "gh api repos/kuhyx/testsAndMisc-archive/commits?path=linux_configuration/scripts/single_use/misc/testsAndMisc-bash/libre_translate.sh",
"result": "pass",
"evidence": "Most recent commit message matches the single_use/periodic_background reorg commit from testsAndMisc, confirming history was carried forward through the rename, not truncated."
},
{
"command": "git merge-base --is-ancestor 652341c HEAD && git merge-base --is-ancestor c45c17f HEAD (in testsAndMisc, before filtering)",
"result": "pass",
"evidence": "Both pre-reorg commits (root libre_translate.sh and Bash/libre_translate.sh) confirmed as true ancestors, justifying passing both paths to git filter-repo instead of just one."
},
{
"command": "bash meta/scripts/check_file_length.sh --all",
"result": "pass",
"evidence": "13 files over cap after deletion (was 14 immediately before, including libre_translate.sh at 488 lines) -- the removed file was the only one dropped from the list."
}
],
"risks": [
"The archive repo has no pre-commit hooks or CI, so nothing re-verifies the moved script still works there -- it is frozen at exactly the state it left testsAndMisc in.",
"git filter-repo was run with --force on a disposable clone rather than a truly fresh git clone from the remote; verified this clone's origin was the local repo path (harmless) and that no push was made to it."
],
"rollback": [
"In testsAndMisc: git revert the deletion commit to restore the file (content and permissions unchanged from before archival, so a straight revert is safe).",
"The testsAndMisc-archive copy can stay regardless of rollback -- having the file in both places briefly is not harmful, just redundant. If it must be undone: git revert the merge commit there, using -m to pick which parent to keep."
]
}

View File

@ -1,488 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# LibreTranslate full setup script (Docker-based)
# Features:
# - Installs Docker if missing (optional --no-docker-install)
# - Pulls libretranslate image (tag configurable)
# - Creates persistent data + cache directories
# - Optionally pre-downloads language models
# - Generates or accepts an API key; can disable auth
# - (Removed) systemd service setup – now always ephemeral
# - Health check + sample translation
# - Uninstall mode removes container, image, service, and data (optional keep data)
# - Idempotent: safe to re-run for upgrades (will pull newer image)
SCRIPT_NAME=$(basename "$0")
VERSION="1.0.0"
# Defaults
IMAGE="libretranslate/libretranslate"
TAG="latest"
SERVICE_NAME="libretranslate"
DOCKER_INSTALL=1
# Systemd removed – always run ephemeral container
API_KEY=""
GENERATE_API_KEY=1
DISABLE_API_KEY=0
PORT=5000
HOST=0.0.0.0
DATA_DIR="/var/lib/libretranslate"
CACHE_DIR="${DATA_DIR}/cache"
CONFIG_DIR="/etc/libretranslate"
ENV_FILE="${CONFIG_DIR}/libretranslate.env"
PULL_ONLY=0
PRELOAD_LANGS=""
UNINSTALL=0
KEEP_DATA=0
HEALTH_TIMEOUT=15
EXTRA_ENV=()
NO_COLOR=0
KEEP_ALIVE=0
RUN_COMMAND=()
DEBUG=0
# Colors
if [[ -t 1 && ${NO_COLOR} -eq 0 ]]; then
GREEN="\e[32m"
YELLOW="\e[33m"
RED="\e[31m"
BLUE="\e[34m"
BOLD="\e[1m"
RESET="\e[0m"
else
GREEN=""
YELLOW=""
RED=""
BLUE=""
BOLD=""
RESET=""
fi
log() { echo -e "${BLUE}[INFO]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
err() { echo -e "${RED}[ERR ]${RESET} $*" >&2; }
success() { echo -e "${GREEN}[OK ]${RESET} $*"; }
usage() {
cat << EOF
${SCRIPT_NAME} v${VERSION}
Setup or uninstall a self-hosted LibreTranslate instance via Docker.
Usage: ${SCRIPT_NAME} [options]
Primary actions:
--uninstall Remove service, container, image (data kept unless --purge or --no-keep-data)
--pull-only Only pull/update image & exit
Install behavior options:
--image NAME Docker image (default: ${IMAGE})
--tag TAG Docker tag (default: ${TAG})
--port N Host port to expose (default: ${PORT})
--host IP Bind host (default: ${HOST})
--data-dir PATH Persistent data directory (default: ${DATA_DIR})
--cache-dir PATH Models cache dir (default: ${CACHE_DIR})
--no-docker-install Do not attempt to install Docker
(systemd support removed; container is ephemeral)
--keep-alive Keep running (tail logs) until Ctrl-C
-- Treat remaining arguments as a command to run after service is healthy; service stops when command exits
--api-key KEY Use specified API key
--generate-api-key Force generate new random key (default if none provided)
--disable-api-key Disable key requirement (open instance)
--preload-langs CSV Pre-download language models (e.g. en,es,fr,de)
--env K=V Extra environment variable (repeatable)
--health-timeout SEC Wait time for health check (default: ${HEALTH_TIMEOUT})
--debug Verbose output (do not suppress curl errors; follow logs on failure)
--no-color Disable colored output
Uninstall options:
--purge Remove data directory (implies --uninstall)
--keep-data Keep data on uninstall (default)
Misc:
-h, --help Show this help
-v, --version Show version
Examples:
${SCRIPT_NAME} --preload-langs en,es,fr --env LT_LOAD_ONLY=en,es,fr
${SCRIPT_NAME} --api-key mysecret123 --port 8080
${SCRIPT_NAME} --uninstall --purge
EOF
}
gen_api_key() {
# Avoid SIGPIPE issues under set -o pipefail by capturing output first
local key
key=$(head -c 256 /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 40 || true)
if [[ -z $key || ${#key} -lt 40 ]]; then
# Fallback using openssl if available
if command -v openssl > /dev/null 2>&1; then
key=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 40 || true)
fi
fi
if [[ -z $key || ${#key} -lt 20 ]]; then
# Last resort static warning key (should not happen)
key="LT$(date +%s)$$RANDOM"
fi
printf '%s' "$key"
}
need_cmd() {
command -v "$1" > /dev/null 2>&1 || {
err "Required command '$1' not found"
return 1
}
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--image)
IMAGE="$2"
shift 2
;;
--tag)
TAG="$2"
shift 2
;;
--port)
PORT="$2"
shift 2
;;
--host)
HOST="$2"
shift 2
;;
--data-dir)
DATA_DIR="$2"
CACHE_DIR="${DATA_DIR}/cache"
shift 2
;;
--cache-dir)
CACHE_DIR="$2"
shift 2
;;
--no-docker-install)
DOCKER_INSTALL=0
shift
;;
--keep-alive)
KEEP_ALIVE=1
shift
;;
--)
shift
RUN_COMMAND=("$@")
break
;;
--api-key)
API_KEY="$2"
GENERATE_API_KEY=0
shift 2
;;
--generate-api-key)
GENERATE_API_KEY=1
shift
;;
--disable-api-key)
DISABLE_API_KEY=1
shift
;;
--preload-langs)
PRELOAD_LANGS="$2"
shift 2
;;
--env)
EXTRA_ENV+=("$2")
shift 2
;;
--pull-only)
PULL_ONLY=1
shift
;;
--uninstall)
UNINSTALL=1
shift
;;
--purge)
UNINSTALL=1
KEEP_DATA=0
shift
;;
--keep-data)
KEEP_DATA=1
shift
;;
--health-timeout)
HEALTH_TIMEOUT="$2"
shift 2
;;
--no-color)
NO_COLOR=1
shift
;;
--debug)
DEBUG=1
shift
;;
-h | --help)
usage
exit 0
;;
-v | --version)
echo "${VERSION}"
exit 0
;;
*)
err "Unknown argument: $1"
usage
exit 1
;;
esac
done
}
ensure_root() {
if [[ $EUID -ne 0 ]]; then
err "This script must run as root (or via sudo)."
exit 1
fi
}
install_docker() {
if command -v docker > /dev/null 2>&1; then
log "Docker already installed"
return 0
fi
if [[ ${DOCKER_INSTALL} -eq 0 ]]; then
err "Docker is not installed and --no-docker-install specified."
exit 1
fi
log "Installing Docker..."
if command -v apt-get > /dev/null 2>&1; then
apt-get update -y
apt-get install -y ca-certificates curl gnupg
install -d -m 0755 /etc/apt/keyrings
curl -fsSL "https://download.docker.com/linux/$(
. /etc/os-release
echo "$ID"
)/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(
. /etc/os-release
echo "$ID"
) $(
. /etc/os-release
echo "$VERSION_CODENAME"
) stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update -y
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
else
err "Unsupported package manager. Please install Docker manually."
exit 1
fi
# Attempt to start docker daemon if dockerd exists and systemctl available; otherwise rely on user
if command -v systemctl > /dev/null 2>&1; then
(systemctl enable --now docker 2> /dev/null && success "Docker installed and started") || warn "Docker installed; ensure dockerd is running"
else
warn "Docker installed; please ensure docker daemon is running"
fi
}
pull_image() {
log "Pulling image ${IMAGE}:${TAG}"
docker pull "${IMAGE}:${TAG}"
success "Image pulled"
}
detect_container_user() {
# Determine uid/gid of configured user inside image so host dirs can be chowned
if ! command -v docker > /dev/null 2>&1; then
return 0
fi
local uid gid
uid=$(docker run --rm --entrypoint /usr/bin/id "${IMAGE}:${TAG}" -u 2> /dev/null || echo "")
gid=$(docker run --rm --entrypoint /usr/bin/id "${IMAGE}:${TAG}" -g 2> /dev/null || echo "")
if [[ -n $uid && -n $gid ]]; then
CONTAINER_UID=$uid
CONTAINER_GID=$gid
fi
}
write_env_file() {
mkdir -p "${CONFIG_DIR}" "${DATA_DIR}" "${CACHE_DIR}"
detect_container_user
if [[ -n ${CONTAINER_UID:-} && -n ${CONTAINER_GID:-} ]]; then
if command -v stat > /dev/null 2>&1; then
for d in "${DATA_DIR}" "${CACHE_DIR}"; do
if [[ -d $d ]]; then
CUR_UID=$(stat -c %u "$d" 2> /dev/null || echo -1)
if [[ ${CUR_UID} -ne ${CONTAINER_UID} ]]; then
chown "${CONTAINER_UID}":"${CONTAINER_GID}" "$d" 2> /dev/null || warn "Unable to chown $d to ${CONTAINER_UID}:${CONTAINER_GID}"
fi
fi
done
fi
fi
if [[ ${DISABLE_API_KEY} -eq 1 ]]; then
API_KEY_LINE="LT_NO_API_KEY=true"
else
if [[ -z ${API_KEY} && ${GENERATE_API_KEY} -eq 1 ]]; then
API_KEY=$(gen_api_key)
GENERATED=1
else
GENERATED=0
fi
API_KEY_LINE="LT_API_KEYS=${API_KEY}"
fi
{
echo "# LibreTranslate environment file"
echo "# Generated $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "${API_KEY_LINE}"
[[ -n ${PRELOAD_LANGS} ]] && echo "LT_PRELOAD_LANGS=${PRELOAD_LANGS}"
for kv in "${EXTRA_ENV[@]:-}"; do echo "$kv"; done
} > "${ENV_FILE}.tmp"
mv "${ENV_FILE}.tmp" "${ENV_FILE}"
chmod 600 "${ENV_FILE}"
success "Environment file written: ${ENV_FILE}"
}
start_container_ephemeral() {
docker rm -f "${SERVICE_NAME}" > /dev/null 2>&1 || true
docker run -d --name "${SERVICE_NAME}" \
--env-file "${ENV_FILE}" \
-v "${DATA_DIR}:/home/libretranslate/.local/share/argos-translate" \
-v "${CACHE_DIR}:/app/cache" \
-p "${PORT}:${PORT}" \
"${IMAGE}:${TAG}" \
--host 0.0.0.0 --port "${PORT}"
success "Container started (ephemeral)"
echo
echo "Endpoint (pending readiness): http://$(hostname -I | awk '{print $1}'):${PORT}"
echo "Waiting for health..."
}
health_check() {
local start
start=$(date +%s)
local url="http://127.0.0.1:${PORT}/languages"
local attempt=0
while true; do
attempt=$((attempt + 1))
if curl ${DEBUG:+-v} -fsS "$url" > /dev/null 2>&1; then
success "Service healthy (attempt $attempt)"
return 0
else
[[ $DEBUG -eq 1 ]] && log "Health attempt $attempt failed"
fi
if (($(date +%s) - start > HEALTH_TIMEOUT)); then
err "Health check failed after ${HEALTH_TIMEOUT}s (attempts: $attempt)"
docker logs --tail 200 "${SERVICE_NAME}" || true
return 1
fi
sleep 0.5
done
}
sample_request() {
if [[ ${DISABLE_API_KEY} -eq 0 ]]; then
local key="${API_KEY}"
else
local key=""
fi
log "Performing sample translation (en->es)..."
local DATA='{"q":"Hello world","source":"en","target":"es","format":"text"}'
if [[ -n $key ]]; then
curl -fsS -H "Content-Type: application/json" -H "Authorization: ${key}" -d "$DATA" "http://127.0.0.1:${PORT}/translate" || warn "Sample request failed"
else
curl -fsS -H "Content-Type: application/json" -d "$DATA" "http://127.0.0.1:${PORT}/translate" || warn "Sample request failed"
fi
echo
}
uninstall_all() {
log "Uninstalling LibreTranslate (ephemeral mode)..."
docker rm -f "${SERVICE_NAME}" 2> /dev/null || true
docker rmi "${IMAGE}:${TAG}" 2> /dev/null || true
if [[ ${KEEP_DATA} -eq 0 ]]; then
rm -rf "${DATA_DIR}" "${CONFIG_DIR}" || true
success "Data directories removed"
else
log "Data kept in ${DATA_DIR} and ${CONFIG_DIR}"
fi
success "Uninstall complete"
exit 0
}
main() {
parse_args "$@"
ensure_root
if [[ ${UNINSTALL} -eq 1 ]]; then
uninstall_all
fi
install_docker
pull_image
if [[ ${PULL_ONLY} -eq 1 ]]; then
log "Pull-only requested, exiting."
exit 0
fi
write_env_file
# Always ephemeral now
start_container_ephemeral
health_check
sample_request || true
# If a command is provided, run it and then shutdown container
if [[ ${#RUN_COMMAND[@]} -gt 0 ]]; then
log "Running user command: ${RUN_COMMAND[*]}"
set +e
"${RUN_COMMAND[@]}"
CMD_STATUS=$?
set -e
log "Command exited with status ${CMD_STATUS}; stopping container"
docker stop "${SERVICE_NAME}" > /dev/null 2>&1 || true
exit ${CMD_STATUS}
fi
if [[ ${KEEP_ALIVE} -eq 1 ]]; then
log "Tailing logs (Ctrl-C to stop and remove container)"
trap 'log "Stopping container"; docker stop "${SERVICE_NAME}" >/dev/null 2>&1 || true; exit 0' INT TERM
docker logs -f "${SERVICE_NAME}"
log "Logs ended; stopping container"
docker stop "${SERVICE_NAME}" > /dev/null 2>&1 || true
else
log "Ephemeral container left running in background (id: $(docker inspect --format '{{.Id}}' ${SERVICE_NAME} 2> /dev/null || echo unknown))"
log "Stop manually with: docker stop ${SERVICE_NAME}"
fi
echo
echo "${BOLD}LibreTranslate is ready.${RESET}"
echo "Endpoint: http://$(hostname -I | awk '{print $1}'):${PORT}"
if [[ ${DISABLE_API_KEY} -eq 0 ]]; then
if [[ ${GENERATED:-0} -eq 1 ]]; then
echo "Generated API key: ${API_KEY}"
else
echo "API key: ${API_KEY}"
fi
echo "Use header: Authorization: <API_KEY>"
else
echo "API key authentication DISABLED (public instance)."
fi
if [[ -n ${PRELOAD_LANGS} ]]; then
echo "Preloaded languages requested: ${PRELOAD_LANGS}"
fi
echo "Environment file: ${ENV_FILE}"
echo "Manage: docker logs -f ${SERVICE_NAME} | docker stop ${SERVICE_NAME}"
echo "Uninstall: sudo ${SCRIPT_NAME} --uninstall"
echo
}
main "$@"