From 1ffca72ee84e5b8fd35adfe305dd3f93b8ec3146 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Thu, 6 Nov 2025 19:39:04 +0100 Subject: [PATCH] chore: fix shell check issues --- .github/copilot-instructions.md | 1 + scripts/fixes/fix_controller.sh | 258 ++++--- scripts/meta/shell_check.sh | 20 +- scripts/misc/testsAndMisc-bash/clean_audio.sh | 145 ++-- scripts/misc/testsAndMisc-bash/convert.sh | 22 +- scripts/misc/testsAndMisc-bash/copyFolder.sh | 18 +- scripts/misc/testsAndMisc-bash/download.sh | 50 +- .../testsAndMisc-bash/fix_thorium_unity.sh | 67 +- scripts/misc/testsAndMisc-bash/fix_unity.sh | 92 ++- .../testsAndMisc-bash/generate_subfolders.sh | 93 ++- .../testsAndMisc-bash/get_rnnoise_model.sh | 36 +- .../install_ffmpeg_with_arnndn.sh | 16 +- .../testsAndMisc-bash/install_unity_mcp.sh | 286 +++---- .../misc/testsAndMisc-bash/libre_translate.sh | 571 ++++++++------ .../misc/testsAndMisc-bash/process_table.sh | 77 +- scripts/misc/testsAndMisc-bash/transcribe.sh | 721 ++++++++++-------- 16 files changed, 1374 insertions(+), 1099 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 773f011..8d71c7b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -40,3 +40,4 @@ This repo automates Linux desktop bootstrap, hardening, and i3 setup. It’s pri - Follow the sudo re-exec + idempotent install pattern from `setup_periodic_system.sh` and `hosts/guard/setup_hosts_guard.sh`. - Add new periodic behaviors as templates under `scripts/system-maintenance/bin` and `.../systemd`, then extend `setup_periodic_system.sh` to install/enable them. - Extend package policy by updating `scripts/digital_wellbeing/pacman/pacman_blocked_keywords.txt` or by adding `check_for_` + `prompt_for__challenge` blocks in the wrapper. +- Run `scripts/meta/shell_check.sh` to detect things to fix before committing. diff --git a/scripts/fixes/fix_controller.sh b/scripts/fixes/fix_controller.sh index d2d2511..7c5d1e2 100755 --- a/scripts/fixes/fix_controller.sh +++ b/scripts/fixes/fix_controller.sh @@ -16,169 +16,181 @@ LOG_FILE="/var/log/xbox-controller-fix.log" timestamp() { date '+%Y-%m-%d %H:%M:%S%z'; } log() { - local msg="$1" - echo "[$(timestamp)] $msg" - if [[ -w "$(dirname "$LOG_FILE")" ]] || [[ ! -e "$LOG_FILE" && -w /var/log ]]; then - echo "[$(timestamp)] $msg" >>"$LOG_FILE" || true - fi + local msg="$1" + echo "[$(timestamp)] $msg" + if [[ -w "$(dirname "$LOG_FILE")" ]] || [[ ! -e $LOG_FILE && -w /var/log ]]; then + echo "[$(timestamp)] $msg" >> "$LOG_FILE" || true + fi } require_root() { - if [[ ${EUID:-$(id -u)} -ne 0 ]]; then - echo "$SCRIPT_NAME needs root to load kernel modules and read some diagnostics. Re-executing with sudo..." - exec sudo -E bash "$0" "$@" - fi + if [[ ${EUID:-$(id -u)} -ne 0 ]]; then + echo "$SCRIPT_NAME needs root to load kernel modules and read some diagnostics. Re-executing with sudo..." + exec sudo -E bash "$0" "$@" + fi } print_header() { - echo "=== $1 ===" + echo "=== $1 ===" } detect_distro() { - if command -v pacman >/dev/null 2>&1; then - echo "arch" - else - echo "other" - fi + if command -v pacman > /dev/null 2>&1; then + echo "arch" + else + echo "other" + fi } list_input_nodes() { - print_header "Input device nodes" - ls -l /dev/input/by-id 2>/dev/null | sed -n '1,120p' || true - echo - if compgen -G "/dev/input/*js*" >/dev/null; then - ls -l /dev/input/js* || true - else - echo "No legacy /dev/input/js* nodes (joydev) present. That's okay for most apps using evdev." - fi - echo + print_header "Input device nodes" + if [[ -d /dev/input/by-id ]]; then + # Robust listing with proper handling of special characters + local count=0 + while IFS= read -r -d '' f; do + stat -c '%A %a %U:%G %N' "$f" 2> /dev/null || true + count=$((count + 1)) + [[ $count -ge 120 ]] && break + done < <(find /dev/input/by-id -maxdepth 1 -mindepth 1 -print0 2> /dev/null) + else + echo "/dev/input/by-id not present" + fi + echo + if compgen -G "/dev/input/*js*" > /dev/null; then + ls -l /dev/input/js* || true + else + echo "No legacy /dev/input/js* nodes (joydev) present. That's okay for most apps using evdev." + fi + echo } show_lsusb() { - print_header "USB devices (filtered)" - if command -v lsusb >/dev/null 2>&1; then - lsusb | grep -Ei 'microsoft|xbox|045e:' || { echo "No Microsoft/Xbox device found via lsusb."; true; } - else - echo "lsusb not found (usbutils). Install usbutils for richer diagnostics." - fi - echo + print_header "USB devices (filtered)" + if command -v lsusb > /dev/null 2>&1; then + lsusb | grep -Ei 'microsoft|xbox|045e:' || { + echo "No Microsoft/Xbox device found via lsusb." + true + } + else + echo "lsusb not found (usbutils). Install usbutils for richer diagnostics." + fi + echo } show_modules() { - print_header "Kernel modules state" - lsmod | grep -E '(^|\s)(xpad|joydev|hid_microsoft|hid_generic|hid_xpadneo|xone)(\s|$)' || echo "No matching modules currently loaded." - echo + print_header "Kernel modules state" + lsmod | grep -E '(^|\s)(xpad|joydev|hid_microsoft|hid_generic|hid_xpadneo|xone)(\s|$)' || echo "No matching modules currently loaded." + echo } modprobe_safe() { - local mod="$1" - if ! lsmod | grep -q "^${mod}\b"; then - if modprobe "$mod" 2>/dev/null; then - log "Loaded module: $mod" - else - log "Module $mod not loaded (may be built-in or unavailable)." - fi - fi + local mod="$1" + if ! lsmod | grep -q "^${mod}\b"; then + if modprobe "$mod" 2> /dev/null; then + log "Loaded module: $mod" + else + log "Module $mod not loaded (may be built-in or unavailable)." + fi + fi } show_dmesg_hints() { - print_header "Recent kernel messages (xpad/xbox/hid/input)" - dmesg --color=never | grep -Ei 'xbox|xpad|045e:|Microsoft|input:.*gamepad|event.*joystick|hid.*(xbox|microsoft)' | tail -n 200 || true - echo + print_header "Recent kernel messages (xpad/xbox/hid/input)" + dmesg --color=never | grep -Ei 'xbox|xpad|045e:|Microsoft|input:.*gamepad|event.*joystick|hid.*(xbox|microsoft)' | tail -n 200 || true + echo } check_permissions() { - print_header "Permissions on event/joystick nodes" - local any=0 - for path in /dev/input/by-id/*-event-joystick /dev/input/js*; do - if [[ -e "$path" ]]; then - any=1 - printf '%s -> ' "$path" - local dev - dev=$(readlink -f "$path" 2>/dev/null || echo "$path") - stat -c '%A %a %U:%G %n' "$dev" 2>/dev/null || true - fi - done - if [[ $any -eq 0 ]]; then - echo "No event-joystick or js nodes found to check permissions." - fi - echo - if [[ $(detect_distro) == "arch" ]]; then - echo "On Arch, prefer TAG+\"uaccess\"-based access over adding users to the 'input' group." - echo "If access is denied in apps, install: pacman -S game-devices-udev (provides modern udev rules)." - fi - echo + print_header "Permissions on event/joystick nodes" + local any=0 + for path in /dev/input/by-id/*-event-joystick /dev/input/js*; do + if [[ -e $path ]]; then + any=1 + printf '%s -> ' "$path" + local dev + dev=$(readlink -f "$path" 2> /dev/null || echo "$path") + stat -c '%A %a %U:%G %n' "$dev" 2> /dev/null || true + fi + done + if [[ $any -eq 0 ]]; then + echo "No event-joystick or js nodes found to check permissions." + fi + echo + if [[ $(detect_distro) == "arch" ]]; then + echo "On Arch, prefer TAG+\"uaccess\"-based access over adding users to the 'input' group." + echo "If access is denied in apps, install: pacman -S game-devices-udev (provides modern udev rules)." + fi + echo } suggest_tests() { - print_header "Next steps / tests" - echo "- Test evdev: install 'evtest' and run: evtest /dev/input/by-id/*-event-joystick" - echo "- Test joystick API: install 'joystick' (jstest) and run: jstest /dev/input/js0 (if present)" - echo "- For force feedback test (rumble): install 'linuxconsole' (fftest): fftest /dev/input/by-id/*-event-joystick" - echo - echo "Steam users: Ensure Steam Input settings match your use case. If rumble fails in SDL titles, try: SDL_JOYSTICK_HIDAPI=0" - echo - echo "If you are actually using Bluetooth: consider xpadneo (AUR: xpadneo-dkms)." - echo "If you are using the official wireless USB adapter: consider xone (AUR: xone-dkms and xone-dongle-firmware)." - echo + print_header "Next steps / tests" + echo "- Test evdev: install 'evtest' and run: evtest /dev/input/by-id/*-event-joystick" + echo "- Test joystick API: install 'joystick' (jstest) and run: jstest /dev/input/js0 (if present)" + echo "- For force feedback test (rumble): install 'linuxconsole' (fftest): fftest /dev/input/by-id/*-event-joystick" + echo + echo "Steam users: Ensure Steam Input settings match your use case. If rumble fails in SDL titles, try: SDL_JOYSTICK_HIDAPI=0" + echo + echo "If you are actually using Bluetooth: consider xpadneo (AUR: xpadneo-dkms)." + echo "If you are using the official wireless USB adapter: consider xone (AUR: xone-dkms and xone-dongle-firmware)." + echo } main() { - require_root "$@" - print_header "${SCRIPT_NAME} starting" - log "Kernel: $(uname -r) | Distro: $(detect_distro)" + require_root "$@" + print_header "${SCRIPT_NAME} starting" + log "Kernel: $(uname -r) | Distro: $(detect_distro)" - show_lsusb - show_modules + show_lsusb + show_modules - # Load common modules safely (idempotent) - modprobe_safe usbhid - modprobe_safe xpad - modprobe_safe joydev + # Load common modules safely (idempotent) + modprobe_safe usbhid + modprobe_safe xpad + modprobe_safe joydev - # If xpad failed to load and kernel says it's a module, but it's not present, hint about out-of-sync modules - if ! lsmod | grep -q '^xpad\b'; then - if command -v zcat >/dev/null 2>&1 && [[ -r /proc/config.gz ]] && zcat /proc/config.gz 2>/dev/null | grep -q '^CONFIG_JOYSTICK_XPAD=m'; then - if ! find "/lib/modules/$(uname -r)" -type f -name 'xpad*.ko*' 2>/dev/null | grep -q .; then - log "xpad is configured as a module but missing under /lib/modules/$(uname -r). Your kernel modules may be out-of-sync or incomplete." - if [[ $(detect_distro) == "arch" ]]; then - echo "Arch hint: reinstall the matching kernel package (e.g. 'sudo pacman -S linux' or your variant like linux-zen) and reboot." - else - echo "Hint: reinstall your running kernel's modules then reboot." - fi - echo - fi - fi - fi + # If xpad failed to load and kernel says it's a module, but it's not present, hint about out-of-sync modules + if ! lsmod | grep -q '^xpad\b'; then + if command -v zcat > /dev/null 2>&1 && [[ -r /proc/config.gz ]] && zcat /proc/config.gz 2> /dev/null | grep -q '^CONFIG_JOYSTICK_XPAD=m'; then + if ! find "/lib/modules/$(uname -r)" -type f -name 'xpad*.ko*' 2> /dev/null | grep -q .; then + log "xpad is configured as a module but missing under /lib/modules/$(uname -r). Your kernel modules may be out-of-sync or incomplete." + if [[ $(detect_distro) == "arch" ]]; then + echo "Arch hint: reinstall the matching kernel package (e.g. 'sudo pacman -S linux' or your variant like linux-zen) and reboot." + else + echo "Hint: reinstall your running kernel's modules then reboot." + fi + echo + fi + fi + fi - list_input_nodes - check_permissions - show_dmesg_hints + list_input_nodes + check_permissions + show_dmesg_hints - # Simple heuristic: do we see an Xbox/Microsoft event-joystick? - if compgen -G "/dev/input/by-id/*-event-joystick" >/dev/null; then - local found_label=0 - for f in /dev/input/by-id/*-event-joystick; do - [[ -e "$f" ]] || continue - if printf '%s' "$(basename "$f")" | grep -Eqi 'xbox|microsoft|controller|wireless'; then - found_label=1 - break - fi - done - if (( found_label == 1 )); then - log "Controller event device detected." - else - log "Event-joystick device(s) exist but not obviously Xbox-labelled. Still likely usable." - fi - else - log "No -event-joystick device found. If the controller vibrated but no input node exists, check the cable and try another USB port/cable." - log "Also check dmesg for descriptor errors; for Xbox 360 Play&Charge cable: note it only charges and does not carry input." - fi + # Simple heuristic: do we see an Xbox/Microsoft event-joystick? + if compgen -G "/dev/input/by-id/*-event-joystick" > /dev/null; then + local found_label=0 + for f in /dev/input/by-id/*-event-joystick; do + [[ -e $f ]] || continue + if printf '%s' "$(basename "$f")" | grep -Eqi 'xbox|microsoft|controller|wireless'; then + found_label=1 + break + fi + done + if ((found_label == 1)); then + log "Controller event device detected." + else + log "Event-joystick device(s) exist but not obviously Xbox-labelled. Still likely usable." + fi + else + log "No -event-joystick device found. If the controller vibrated but no input node exists, check the cable and try another USB port/cable." + log "Also check dmesg for descriptor errors; for Xbox 360 Play&Charge cable: note it only charges and does not carry input." + fi - suggest_tests + suggest_tests - print_header "Done" + print_header "Done" } main "$@" - diff --git a/scripts/meta/shell_check.sh b/scripts/meta/shell_check.sh index 6fd4be7..22ab289 100755 --- a/scripts/meta/shell_check.sh +++ b/scripts/meta/shell_check.sh @@ -285,8 +285,24 @@ run_linters() { local cbi_out="$TMPDIR/checkbashisms.txt" local cbi_status=0 if is_cmd checkbashisms; then - # checkbashisms exits 0 if OK, 1 if issues, other codes for tool warnings - checkbashisms "${FILES[@]}" > "$cbi_out" 2>&1 + # Only run checkbashisms on scripts that are intended for /bin/sh (or unspecified), + # skip explicit bash/zsh scripts to avoid false positives. + local -a CBI_FILES + CBI_FILES=() + for f in "${FILES[@]}"; do + local first + first=$(head -n 1 -- "$f" 2> /dev/null || true) + if [[ $first =~ bash || $first =~ zsh ]]; then + continue + fi + CBI_FILES+=("$f") + done + if [[ ${#CBI_FILES[@]} -gt 0 ]]; then + # checkbashisms exits 0 if OK, 1 if issues, other codes for tool warnings + checkbashisms "${CBI_FILES[@]}" > "$cbi_out" 2>&1 + else + : > "$cbi_out" + fi cbi_status=$? if [[ $cbi_status -eq 1 ]]; then issues=$((issues + 1)) diff --git a/scripts/misc/testsAndMisc-bash/clean_audio.sh b/scripts/misc/testsAndMisc-bash/clean_audio.sh index 023b038..aa5d1d3 100755 --- a/scripts/misc/testsAndMisc-bash/clean_audio.sh +++ b/scripts/misc/testsAndMisc-bash/clean_audio.sh @@ -22,10 +22,10 @@ set -euo pipefail # Bash/clean_audio.sh input.wav --preset podcast # -> add dynamics leveler # -SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) print_usage() { - cat < [options] Options: @@ -49,7 +49,7 @@ EOF } require_cmd() { - command -v "$1" >/dev/null 2>&1 || { + command -v "$1" > /dev/null 2>&1 || { echo "Error: Required command '$1' not found in PATH" >&2 exit 1 } @@ -60,7 +60,7 @@ OUT_DIR="" OUT_EXT="wav" RN_MODEL="" NO_ML=false -REQUIRE_ML=true # default: require RNNoise; install/guide if missing; fail fast if unavailable +REQUIRE_ML=true # default: require RNNoise; install/guide if missing; fail fast if unavailable PRESET="asr" JOBS=1 FORCE=false @@ -68,9 +68,9 @@ QUIET=false LOWPASS="" SUFFIX="_clean" HIGHPASS="80" -AFFTDN_NF="-25" # noise floor in dB for afftdn -AFFTDN_MD="8" # mode for afftdn (higher can be more aggressive); requires builds that support 'md' -NO_ADVANCED=false # when true, avoid advanced options that some ffmpeg builds lack +AFFTDN_NF="-25" # noise floor in dB for afftdn +AFFTDN_MD="8" # mode for afftdn (higher can be more aggressive); requires builds that support 'md' +NO_ADVANCED=false # when true, avoid advanced options that some ffmpeg builds lack # Parse args if [[ $# -lt 1 ]]; then @@ -78,40 +78,68 @@ if [[ $# -lt 1 ]]; then exit 1 fi -INPUT_PATH="$1"; shift || true +INPUT_PATH="$1" +shift || true while [[ $# -gt 0 ]]; do case "$1" in - -O|--out-dir) - OUT_DIR="$2"; shift 2;; - -e|--ext) - OUT_EXT="$2"; shift 2;; - -m|--model) - RN_MODEL="$2"; shift 2;; + -O | --out-dir) + OUT_DIR="$2" + shift 2 + ;; + -e | --ext) + OUT_EXT="$2" + shift 2 + ;; + -m | --model) + RN_MODEL="$2" + shift 2 + ;; --no-ml) - NO_ML=true; shift;; + NO_ML=true + shift + ;; --preset) - PRESET="$2"; shift 2;; - -j|--jobs) - JOBS="$2"; shift 2;; - -f|--force) - FORCE=true; shift;; - -q|--quiet) - QUIET=true; shift;; + PRESET="$2" + shift 2 + ;; + -j | --jobs) + JOBS="$2" + shift 2 + ;; + -f | --force) + FORCE=true + shift + ;; + -q | --quiet) + QUIET=true + shift + ;; --lowpass) - LOWPASS="$2"; shift 2;; + LOWPASS="$2" + shift 2 + ;; --suffix) - SUFFIX="$2"; shift 2;; - --no-advanced|--compat) - NO_ADVANCED=true; shift;; + SUFFIX="$2" + shift 2 + ;; + --no-advanced | --compat) + NO_ADVANCED=true + shift + ;; --allow-fallback) - REQUIRE_ML=false; shift;; - -h|--help) - print_usage; exit 0;; + REQUIRE_ML=false + shift + ;; + -h | --help) + print_usage + exit 0 + ;; *) echo "Unknown option: $1" >&2 print_usage - exit 1;; + exit 1 + ;; esac done @@ -119,7 +147,7 @@ require_cmd ffmpeg # Resolve FFmpeg binary (env override -> local build -> system) FFMPEG_BIN=${FFMPEG_BIN:-} -if [[ -z "${FFMPEG_BIN}" ]]; then +if [[ -z ${FFMPEG_BIN} ]]; then if [[ -x "$SCRIPT_DIR/ffmpeg-build/FFmpeg/ffmpeg" ]]; then FFMPEG_BIN="$SCRIPT_DIR/ffmpeg-build/FFmpeg/ffmpeg" else @@ -127,7 +155,7 @@ if [[ -z "${FFMPEG_BIN}" ]]; then fi fi -if ! command -v "$FFMPEG_BIN" >/dev/null 2>&1 && [[ ! -x "$FFMPEG_BIN" ]]; then +if ! command -v "$FFMPEG_BIN" > /dev/null 2>&1 && [[ ! -x $FFMPEG_BIN ]]; then echo "Error: FFmpeg binary not found: $FFMPEG_BIN" >&2 exit 1 fi @@ -137,9 +165,9 @@ fi FFMPEG_LOG=(-hide_banner) if $QUIET; then - FFMPEG_LOG+=( -loglevel error ) + FFMPEG_LOG+=(-loglevel error) else - FFMPEG_LOG+=( -loglevel info ) + FFMPEG_LOG+=(-loglevel info) fi FFMPEG_OVERWRITE=(-n) @@ -148,10 +176,10 @@ if $FORCE; then fi arnndn_available=false -if "$FFMPEG_BIN" -hide_banner -h filter=arnndn >/dev/null 2>&1; then +if "$FFMPEG_BIN" -hide_banner -h filter=arnndn > /dev/null 2>&1; then arnndn_available=true else - if "$FFMPEG_BIN" -hide_banner -filters 2>/dev/null | grep -Eq '(^|[[:space:]])arnndn([[:space:]]|$)'; then + if "$FFMPEG_BIN" -hide_banner -filters 2> /dev/null | grep -Eq '(^|[[:space:]])arnndn([[:space:]]|$)'; then arnndn_available=true fi fi @@ -161,15 +189,15 @@ fi # Check if afftdn supports 'md' option afftdn_supports_md=false -if "$FFMPEG_BIN" -hide_banner -h filter=afftdn 2>/dev/null | grep -q " md="; then +if "$FFMPEG_BIN" -hide_banner -h filter=afftdn 2> /dev/null | grep -q " md="; then afftdn_supports_md=true fi # Try to auto-discover an RNNoise model if none provided find_default_rn_model() { - local candidate="" + # local candidate reserved for future selection logic # Allow env variable override - if [[ -n "${RNNOISE_MODEL:-}" && -f "${RNNOISE_MODEL}" ]]; then + if [[ -n ${RNNOISE_MODEL:-} && -f ${RNNOISE_MODEL} ]]; then echo "${RNNOISE_MODEL}" return 0 fi @@ -184,11 +212,11 @@ find_default_rn_model() { # Prefer '.rnnn' models (rnnoise-nu style) over legacy '.nn' local exts=("rnnn" "nn" "model") for d in "${dirs[@]}"; do - if [[ -d "$d" ]]; then + if [[ -d $d ]]; then for ext in "${exts[@]}"; do # Pick the first matching model file for f in "$d"/*."$ext"; do - if [[ -f "$f" ]]; then + if [[ -f $f ]]; then echo "$f" return 0 fi @@ -208,7 +236,7 @@ if [[ $NO_ML == false ]]; then fi else # arnndn available; require an external model - if [[ -n "$RN_MODEL" && -f "$RN_MODEL" ]]; then + if [[ -n $RN_MODEL && -f $RN_MODEL ]]; then : else if model_path=$(find_default_rn_model); then @@ -222,7 +250,7 @@ if [[ $NO_ML == false ]]; then fi fi fi - if [[ -z "$RN_MODEL" ]]; then + if [[ -z $RN_MODEL ]]; then echo "Error: RNNoise model required but not found. Automatic download failed." >&2 echo "Hint: Set RN_URL to a reachable model URL and run Bash/get_rnnoise_model.sh, or supply -m /path/to/model.nn." >&2 exit 10 @@ -263,7 +291,7 @@ build_filters() { fi # Optional low-pass to shave hiss; keep disabled unless requested - if [[ -n "$LOWPASS" ]]; then + if [[ -n $LOWPASS ]]; then filters+=("lowpass=f=${LOWPASS}") fi @@ -291,7 +319,8 @@ build_filters() { filters+=("aresample=16000") filters+=("aformat=channel_layouts=mono:sample_fmts=s16") - local IFS=","; echo "${filters[*]}" + local IFS="," + echo "${filters[*]}" } make_out_path_for_file() { @@ -300,7 +329,7 @@ make_out_path_for_file() { base=$(basename -- "$in_file") base="${base%.*}" local out_base="${base}${SUFFIX}.${OUT_EXT}" - if [[ -n "$OUT_DIR" ]]; then + if [[ -n $OUT_DIR ]]; then mkdir -p -- "$OUT_DIR" echo "$OUT_DIR/$out_base" else @@ -316,15 +345,15 @@ process_one() { out_file=$(make_out_path_for_file "$in_file") # Choose codec based on extension - local codec=( -c:a pcm_s16le ) - if [[ "$OUT_EXT" == "flac" ]]; then - codec=( -c:a flac ) + local codec=(-c:a pcm_s16le) + if [[ $OUT_EXT == "flac" ]]; then + codec=(-c:a flac) fi local af af=$(build_filters) - if [[ -f "$out_file" && $FORCE == false ]]; then + if [[ -f $out_file && $FORCE == false ]]; then echo "Skip (exists): $out_file" return 0 fi @@ -335,7 +364,7 @@ process_one() { # Concurrency helpers (bash >= 5 supports wait -n; fallback to sequential if not) supports_wait_n=false -if [[ -n "${BASH_VERSINFO:-}" && ${BASH_VERSINFO[0]} -ge 5 ]]; then +if [[ -n ${BASH_VERSINFO:-} && ${BASH_VERSINFO[0]} -ge 5 ]]; then supports_wait_n=true fi @@ -344,7 +373,7 @@ run_dir() { # Common audio extensions (case-insensitive) mapfile -d '' files < <(find "$dir" -type f \ \( -iname "*.wav" -o -iname "*.mp3" -o -iname "*.m4a" -o -iname "*.aac" -o -iname "*.flac" \ - -o -iname "*.ogg" -o -iname "*.opus" -o -iname "*.wma" -o -iname "*.webm" \) -print0) + -o -iname "*.ogg" -o -iname "*.opus" -o -iname "*.wma" -o -iname "*.webm" \) -print0) if [[ ${#files[@]} -eq 0 ]]; then echo "No audio files found in: $dir" @@ -353,12 +382,12 @@ run_dir() { local running=0 for f in "${files[@]}"; do - if [[ "$JOBS" -le 1 || $supports_wait_n == false ]]; then + if [[ $JOBS -le 1 || $supports_wait_n == false ]]; then process_one "$f" else process_one "$f" & ((running++)) - if (( running >= JOBS )); then + if ((running >= JOBS)); then wait -n || true ((running--)) fi @@ -366,20 +395,20 @@ run_dir() { done # Wait for any remaining background jobs - if (( JOBS > 1 )) && $supports_wait_n; then + if ((JOBS > 1)) && $supports_wait_n; then wait || true fi } main() { # Sanity checks and notices - if [[ -n "$RN_MODEL" && $use_arnndn == false && $NO_ML == false ]]; then + if [[ -n $RN_MODEL && $use_arnndn == false && $NO_ML == false ]]; then echo "Note: arnndn filter not available in your ffmpeg or model missing — using afftdn." >&2 fi - if [[ -f "$INPUT_PATH" ]]; then + if [[ -f $INPUT_PATH ]]; then process_one "$INPUT_PATH" - elif [[ -d "$INPUT_PATH" ]]; then + elif [[ -d $INPUT_PATH ]]; then run_dir "$INPUT_PATH" else echo "Error: Input path not found: $INPUT_PATH" >&2 diff --git a/scripts/misc/testsAndMisc-bash/convert.sh b/scripts/misc/testsAndMisc-bash/convert.sh index 7c02225..7d12209 100755 --- a/scripts/misc/testsAndMisc-bash/convert.sh +++ b/scripts/misc/testsAndMisc-bash/convert.sh @@ -27,29 +27,29 @@ mkdir -p "$OUTPUT_DIR" convert_video() { local input_file="$1" local output_file="$OUTPUT_DIR/${input_file%.*}.$TARGET_EXT" - + # Get video duration in seconds DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$input_file") echo "Duration: $DURATION seconds" - + # Convert target size to bytes TARGET_SIZE_BYTES=$(numfmt --from=iec "$TARGET_SIZE") - + # Calculate target bitrate in kilobits per second TARGET_BITRATE=$(echo "($TARGET_SIZE_BYTES * 8) / $DURATION / 2000" | bc) - + # Convert video ffmpeg -i "$input_file" -vcodec libx264 -b:v "${TARGET_BITRATE}k" -preset veryslow -acodec aac -c:a copy "$output_file" - + # Get original and converted video sizes ORIGINAL_SIZE=$(stat -c%s "$input_file") CONVERTED_SIZE=$(stat -c%s "$output_file") - + # Print out details - echo "Original size: $(numfmt --to=iec $ORIGINAL_SIZE)" + echo "Original size: $(numfmt --to=iec "$ORIGINAL_SIZE")" echo "Video length: $DURATION seconds" echo "Target size: $TARGET_SIZE" - echo "Converted size: $(numfmt --to=iec $CONVERTED_SIZE)" + echo "Converted size: $(numfmt --to=iec "$CONVERTED_SIZE")" echo "Target bitrate: ${TARGET_BITRATE}kbps" } @@ -57,12 +57,12 @@ convert_video() { move_video() { local input_file="$1" local output_file="$OUTPUT_DIR/${input_file##*/}" - + # Get original video size ORIGINAL_SIZE=$(stat -c%s "$input_file") - + # Check if video is below target size and in desired format - if [[ "$ORIGINAL_SIZE" -le "$TARGET_SIZE_BYTES" && "${input_file##*.}" == "$TARGET_EXT" ]]; then + if [[ $ORIGINAL_SIZE -le $TARGET_SIZE_BYTES && ${input_file##*.} == "$TARGET_EXT" ]]; then mv "$input_file" "$output_file" echo "Moved $input_file to $output_file" else diff --git a/scripts/misc/testsAndMisc-bash/copyFolder.sh b/scripts/misc/testsAndMisc-bash/copyFolder.sh index d6bc845..0bf5a2f 100755 --- a/scripts/misc/testsAndMisc-bash/copyFolder.sh +++ b/scripts/misc/testsAndMisc-bash/copyFolder.sh @@ -1,7 +1,7 @@ #!/bin/bash # Get the list of directories in the current script directory -directories=($(find . -maxdepth 1 -type d ! -name .)) +mapfile -t directories < <(find . -maxdepth 1 -type d ! -name . -printf '%f\n') # Check if there is exactly one directory if [ ${#directories[@]} -ne 1 ]; then @@ -13,16 +13,16 @@ fi folder_name=${directories[0]} random_string() { - local length=$1 - tr -dc 'a-zA-Z0-9!@#$%^&*()_+{}|:<>?~' < /dev/urandom | head -c $length + local length="$1" + tr -dc 'a-zA-Z0-9!@#$%^&*()_+{}|:<>?~' < /dev/urandom | head -c "$length" } # Number of copies to create (default 100) -num_copies=${1:-100} +num_copies="${1:-100}" # Create the specified number of copies -for ((i=1; i<=num_copies; i++)); do - new_folder_name="$(random_string 255)" - cp -r "$folder_name" "$new_folder_name" - echo "Folder copied and renamed to '$new_folder_name'" -done \ No newline at end of file +for ((i = 1; i <= num_copies; i++)); do + new_folder_name="$(random_string 255)" + cp -r "$folder_name" "$new_folder_name" + echo "Folder copied and renamed to '$new_folder_name'" +done diff --git a/scripts/misc/testsAndMisc-bash/download.sh b/scripts/misc/testsAndMisc-bash/download.sh index 8543cb6..aba4bff 100755 --- a/scripts/misc/testsAndMisc-bash/download.sh +++ b/scripts/misc/testsAndMisc-bash/download.sh @@ -3,8 +3,8 @@ # Check if there are any .txt files in the current directory txt_files=(*.txt) if [ ${#txt_files[@]} -eq 0 ]; then - echo "No .txt files found in the current directory!" - exit 1 + echo "No .txt files found in the current directory!" + exit 1 fi total_files=0 @@ -14,33 +14,33 @@ downloaded_size=0 # Calculate total number of files and total size to download for file in *.txt; do - while IFS= read -r url; do - if [[ -n "$url" ]]; then - total_files=$((total_files + 1)) - size=$(wget --spider "$url" 2>&1 | grep Length | awk '{print $2}') - total_size=$((total_size + size)) - fi - done < "$file" + while IFS= read -r url; do + if [[ -n $url ]]; then + total_files=$((total_files + 1)) + size=$(wget --spider "$url" 2>&1 | awk '/Length/ {print $2}') + total_size=$((total_size + size)) + fi + done < "$file" done # Loop through each .txt file and download each URL in parallel for file in *.txt; do - echo "Processing $file..." - while IFS= read -r url; do - if [[ -n "$url" ]]; then - { - wget -q --show-progress "$url" - downloaded_files=$((downloaded_files + 1)) - size=$(wget --spider "$url" 2>&1 | grep Length | awk '{print $2}') - downloaded_size=$((downloaded_size + size)) - remaining_files=$((total_files - downloaded_files)) - remaining_size=$((total_size - downloaded_size)) - echo "Downloaded: $downloaded_files/$total_files files, $downloaded_size/$total_size bytes" - echo "Remaining: $remaining_files files, $remaining_size bytes" - } & - fi - done < "$file" + echo "Processing $file..." + while IFS= read -r url; do + if [[ -n $url ]]; then + { + wget -q --show-progress "$url" + downloaded_files=$((downloaded_files + 1)) + size=$(wget --spider "$url" 2>&1 | awk '/Length/ {print $2}') + downloaded_size=$((downloaded_size + size)) + remaining_files=$((total_files - downloaded_files)) + remaining_size=$((total_size - downloaded_size)) + echo "Downloaded: $downloaded_files/$total_files files, $downloaded_size/$total_size bytes" + echo "Remaining: $remaining_files files, $remaining_size bytes" + } & + fi + done < "$file" done # Wait for all background jobs to complete -wait \ No newline at end of file +wait diff --git a/scripts/misc/testsAndMisc-bash/fix_thorium_unity.sh b/scripts/misc/testsAndMisc-bash/fix_thorium_unity.sh index 8a2a5f0..5c50bc9 100644 --- a/scripts/misc/testsAndMisc-bash/fix_thorium_unity.sh +++ b/scripts/misc/testsAndMisc-bash/fix_thorium_unity.sh @@ -18,10 +18,14 @@ set -euo pipefail IFS=$'\n\t' -GREEN="\033[1;32m"; YELLOW="\033[1;33m"; RED="\033[1;31m"; BLUE="\033[1;34m"; NC="\033[0m" -log_info() { echo -e "${BLUE}[INFO]${NC} $*"; } -log_ok() { echo -e "${GREEN}[ OK ]${NC} $*"; } -log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +GREEN="\033[1;32m" +YELLOW="\033[1;33m" +RED="\033[1;31m" +BLUE="\033[1;34m" +NC="\033[0m" +log_info() { echo -e "${BLUE}[INFO]${NC} $*"; } +log_ok() { echo -e "${GREEN}[ OK ]${NC} $*"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } log_error() { echo -e "${RED}[ERR ]${NC} $*" 1>&2; } DO_POLICY=false @@ -29,7 +33,7 @@ SET_DEFAULT=false DO_RESTART=false usage() { - cat </dev/null 2>&1; then + if ! command -v sudo > /dev/null 2>&1; then log_error "sudo not found; cannot install system policy. Use --set-default or run from root." exit 1 fi @@ -65,16 +85,16 @@ install_policy() { ensure_sudo # Candidate policy directories (most common for Chromium forks) local candidates=( - "/etc/thorium-browser/policies/managed" # Thorium - "/etc/chromium/policies/managed" # Chromium - "/etc/opt/chrome/policies/managed" # Google Chrome + "/etc/thorium-browser/policies/managed" # Thorium + "/etc/chromium/policies/managed" # Chromium + "/etc/opt/chrome/policies/managed" # Google Chrome ) local wrote_any=false for target in "${candidates[@]}"; do log_info "Installing policy into: $target" sudo mkdir -p "$target" local policy_file="$target/unityhub-policy.json" - sudo tee "$policy_file" >/dev/null <<'JSON' + sudo tee "$policy_file" > /dev/null << 'JSON' { "AutoLaunchProtocolsFromOrigins": [ { "protocol": "unityhub", "origin": "https://id.unity.com", "allow": true }, @@ -90,13 +110,13 @@ JSON log_ok "Policy written: $policy_file" wrote_any=true done - if [[ "$wrote_any" != true ]]; then + if [[ $wrote_any != true ]]; then log_warn "Policy may not have been written. No candidate directories processed." fi } set_default_browser() { - if command -v xdg-settings >/dev/null 2>&1; then + if command -v xdg-settings > /dev/null 2>&1; then # Prefer the upstream desktop id if it exists local desktop="thorium-browser.desktop" if [[ ! -f "/usr/share/applications/$desktop" && -f "$HOME/.local/share/applications/$desktop" ]]; then @@ -107,7 +127,7 @@ set_default_browser() { fi log_info "Setting default browser to $desktop" xdg-settings set default-web-browser "$desktop" || log_warn "Failed to set default browser via xdg-settings" - log_ok "Default browser set to: $(xdg-settings get default-web-browser 2>/dev/null || echo "$desktop")" + log_ok "Default browser set to: $(xdg-settings get default-web-browser 2> /dev/null || echo "$desktop")" else log_warn "xdg-settings not found; cannot set default browser automatically." fi @@ -116,12 +136,13 @@ set_default_browser() { restart_thorium() { # Kill Thorium processes and start fresh log_info "Restarting Thorium..." - pkill -9 -f 'thorium-browser' 2>/dev/null || true + pkill -9 -f 'thorium-browser' 2> /dev/null || true # Also kill unityhub-bin's embedded Chromium if any leftover (harmless) - pkill -9 -f 'unityhub-bin' 2>/dev/null || true + pkill -9 -f 'unityhub-bin' 2> /dev/null || true # Start Thorium detached if available - if command -v thorium-browser >/dev/null 2>&1; then - nohup thorium-browser >/dev/null 2>&1 & disown || true + if command -v thorium-browser > /dev/null 2>&1; then + nohup thorium-browser > /dev/null 2>&1 & + disown || true fi log_ok "Thorium restart attempted." } @@ -131,7 +152,7 @@ main() { $SET_DEFAULT && set_default_browser $DO_RESTART && restart_thorium - cat <<'NEXT' + cat << 'NEXT' --- Next steps: - Open Unity Hub, click Sign in, complete in Thorium; when prompted, allow the unityhub link to open the app. diff --git a/scripts/misc/testsAndMisc-bash/fix_unity.sh b/scripts/misc/testsAndMisc-bash/fix_unity.sh index ddd19d1..3165ab7 100755 --- a/scripts/misc/testsAndMisc-bash/fix_unity.sh +++ b/scripts/misc/testsAndMisc-bash/fix_unity.sh @@ -23,15 +23,19 @@ set -euo pipefail IFS=$'\n\t' SCRIPT_NAME="$(basename "$0")" -GREEN="\033[1;32m"; YELLOW="\033[1;33m"; RED="\033[1;31m"; BLUE="\033[1;34m"; NC="\033[0m" +GREEN="\033[1;32m" +YELLOW="\033[1;33m" +RED="\033[1;31m" +BLUE="\033[1;34m" +NC="\033[0m" -log_info() { echo -e "${BLUE}[INFO]${NC} $*"; } -log_ok() { echo -e "${GREEN}[ OK ]${NC} $*"; } -log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +log_info() { echo -e "${BLUE}[INFO]${NC} $*"; } +log_ok() { echo -e "${GREEN}[ OK ]${NC} $*"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } log_error() { echo -e "${RED}[ERR ]${NC} $*" 1>&2; } usage() { - cat </dev/null 2>&1; then + if ! command -v "$1" > /dev/null 2>&1; then return 1 fi } ensure_deps_arch() { # Best-effort install for Arch-based systems - if [[ "$AUTO_INSTALL" != true ]]; then + if [[ $AUTO_INSTALL != true ]]; then log_warn "Skipping package installation (use -y to auto-install)." return 0 fi @@ -100,8 +117,8 @@ detect_unityhub() { local install_type="UNKNOWN" exec_cmd="" # 1) Flatpak - if command -v flatpak >/dev/null 2>&1; then - if flatpak info com.unity.UnityHub >/dev/null 2>&1; then + if command -v flatpak > /dev/null 2>&1; then + if flatpak info com.unity.UnityHub > /dev/null 2>&1; then install_type="FLATPAK" exec_cmd="flatpak run com.unity.UnityHub %U" echo "$install_type|$exec_cmd" @@ -110,7 +127,7 @@ detect_unityhub() { fi # 2) Native binary in PATH - if command -v unityhub >/dev/null 2>&1; then + if command -v unityhub > /dev/null 2>&1; then local path path="$(command -v unityhub)" install_type="NATIVE" @@ -128,16 +145,16 @@ detect_unityhub() { ) local found_exec="" for d in "${search_dirs[@]}"; do - [[ -d "$d" ]] || continue + [[ -d $d ]] || continue # prefer official naming when present local f for f in "$d"/*.desktop; do - [[ -e "$f" ]] || continue - if grep -qiE '^(Name|Comment)=.*Unity Hub' "$f" 2>/dev/null || \ - grep -qiE 'Exec=.*unityhub' "$f" 2>/dev/null; then + [[ -e $f ]] || continue + if grep -qiE '^(Name|Comment)=.*Unity Hub' "$f" 2> /dev/null || + grep -qiE 'Exec=.*unityhub' "$f" 2> /dev/null; then local exec_line exec_line="$(grep -iE '^Exec=' "$f" | head -n1 | sed 's/^Exec=//')" - if [[ -n "$exec_line" ]]; then + if [[ -n $exec_line ]]; then found_exec="$exec_line" break 2 fi @@ -145,14 +162,14 @@ detect_unityhub() { done done - if [[ -n "$found_exec" ]]; then + if [[ -n $found_exec ]]; then # Normalize: ensure %U present - if [[ "$found_exec" != *"%U"* && "$found_exec" != *"%u"* ]]; then + if [[ $found_exec != *"%U"* && $found_exec != *"%u"* ]]; then found_exec+=" %U" fi - if [[ "$found_exec" == flatpak* ]]; then + if [[ $found_exec == flatpak* ]]; then install_type="FLATPAK" - elif [[ "$found_exec" == *AppImage* || "$found_exec" == *appimage* ]]; then + elif [[ $found_exec == *AppImage* || $found_exec == *appimage* ]]; then install_type="APPIMAGE" else install_type="NATIVE" @@ -170,7 +187,7 @@ detect_unityhub() { local ai for ai in "${ai_candidates[@]}"; do for p in $ai; do - if [[ -f "$p" && -x "$p" ]]; then + if [[ -f $p && -x $p ]]; then install_type="APPIMAGE" exec_cmd="$p %U" echo "$install_type|$exec_cmd" @@ -186,7 +203,7 @@ create_handler_desktop() { local exec_cmd="$1" local dest="$desktop_dir/unityhub-url-handler.desktop" log_info "Writing handler desktop entry: $dest" - cat > "$dest" < "$dest" << DESK [Desktop Entry] Name=Unity Hub URL Handler Comment=Handle unityhub:// links for Unity Hub sign-in @@ -206,14 +223,14 @@ DESK register_mime_handler() { local desktop_file="$1" # Update desktop database if available - if command -v update-desktop-database >/dev/null 2>&1; then + if command -v update-desktop-database > /dev/null 2>&1; then update-desktop-database "$desktop_dir" || true else log_warn "update-desktop-database not found (install desktop-file-utils)." fi # Register as default handler for both schemes - if command -v xdg-mime >/dev/null 2>&1; then + if command -v xdg-mime > /dev/null 2>&1; then xdg-mime default "$(basename "$desktop_file")" x-scheme-handler/unityhub || true xdg-mime default "$(basename "$desktop_file")" x-scheme-handler/unity || true else @@ -224,12 +241,13 @@ register_mime_handler() { } verify_registration() { - local expected="$(basename "$1")" - local cur1="$(xdg-mime query default x-scheme-handler/unityhub 2>/dev/null || true)" - local cur2="$(xdg-mime query default x-scheme-handler/unity 2>/dev/null || true)" + local expected cur1 cur2 + expected="$(basename "$1")" + cur1="$(xdg-mime query default x-scheme-handler/unityhub 2> /dev/null || true)" + cur2="$(xdg-mime query default x-scheme-handler/unity 2> /dev/null || true)" log_info "Current handler (unityhub): ${cur1:-}" log_info "Current handler (unity): ${cur2:-}" - if [[ "$cur1" == "$expected" ]]; then + if [[ $cur1 == "$expected" ]]; then log_ok "unityhub scheme correctly set to $expected" else log_warn "unityhub scheme not set to $expected (currently: ${cur1:-none})." @@ -237,10 +255,10 @@ verify_registration() { } maybe_test_open() { - if [[ "$RUN_TEST" == true ]]; then + if [[ $RUN_TEST == true ]]; then log_info "Opening test link: unityhub://v1/editor-signin" - if command -v xdg-open >/dev/null 2>&1; then - xdg-open 'unityhub://v1/editor-signin' >/dev/null 2>&1 || true + if command -v xdg-open > /dev/null 2>&1; then + xdg-open 'unityhub://v1/editor-signin' > /dev/null 2>&1 || true log_ok "Test link invoked. Check if Unity Hub launches or focuses." else log_warn "xdg-open not found; cannot run test automatically." @@ -257,7 +275,7 @@ main() { log_info "Detecting Unity Hub installation..." IFS='|' read -r install_type exec_cmd < <(detect_unityhub) log_info "Detected type: $install_type" - if [[ -z "${exec_cmd:-}" ]]; then + if [[ -z ${exec_cmd:-} ]]; then log_warn "Could not find Unity Hub executable automatically." log_warn "- If using Flatpak: install with 'flatpak install flathub com.unity.UnityHub'" log_warn "- If native (AUR): ensure 'unityhub' is in PATH" @@ -273,7 +291,7 @@ main() { register_mime_handler "$desktop_file" verify_registration "$desktop_file" - cat <<'NOTE' + cat << 'NOTE' --- Next steps: - Sign in from Unity Hub. When the browser finishes, ALLOW the prompt to open xdg-open/Unity Hub. @@ -283,7 +301,7 @@ NOTE maybe_test_open - log_ok "Done. If login still fails, check the Hub's logs and share the outputs of:\n which unityhub || true\n flatpak info com.unity.UnityHub 2>/dev/null | sed -n '1,5p' || true\n xdg-mime query default x-scheme-handler/unityhub\n grep -R "x-scheme-handler/unityhub" ~/.local/share/applications /usr/share/applications 2>/dev/null | head -n 10" + log_ok "Done. If login still fails, check the Hub's logs and share the outputs of:\n which unityhub || true\n flatpak info com.unity.UnityHub 2>/dev/null | sed -n '1,5p' || true\n xdg-mime query default x-scheme-handler/unityhub\n grep -R \"x-scheme-handler/unityhub\" ~/.local/share/applications /usr/share/applications 2>/dev/null | head -n 10" } main "$@" diff --git a/scripts/misc/testsAndMisc-bash/generate_subfolders.sh b/scripts/misc/testsAndMisc-bash/generate_subfolders.sh index 843ee02..0578fb5 100755 --- a/scripts/misc/testsAndMisc-bash/generate_subfolders.sh +++ b/scripts/misc/testsAndMisc-bash/generate_subfolders.sh @@ -2,72 +2,81 @@ # Function to generate random number between two values random_number() { - echo $((RANDOM % ($2 - $1 + 1) + $1)) + echo $((RANDOM % ($2 - $1 + 1) + $1)) } # Function to generate random string with non-computer-friendly characters random_string() { - local length=$1 - tr -dc 'a-zA-Z0-9!@#$%^&*()_+{}|:<>?~' < /dev/urandom | head -c $length + local length="$1" + tr -dc 'a-zA-Z0-9!@#$%^&*()_+{}|:<>?~' < /dev/urandom | head -c "$length" } # Function to calculate total number of folders to be created calculate_total_folders() { - local depth=$1 - local total=0 - if [ "$depth" -le 10 ]; then - local num_subfolders=$(random_number 1 50) - total=$((num_subfolders + total)) - for ((i=1; i<=num_subfolders; i++)); do - total=$((total + $(calculate_total_folders $((depth + 1))))) - done - fi - echo $total + local depth="$1" + local total=0 + if [ "$depth" -le 10 ]; then + local num_subfolders + num_subfolders=$(random_number 1 50) + total=$((num_subfolders + total)) + for ((i = 1; i <= num_subfolders; i++)); do + total=$((total + $(calculate_total_folders $((depth + 1))))) + done + fi + echo "$total" } # Function to create folders and files recursively create_structure() { - local current_depth=$1 - local parent_dir=$2 - local start_time=$3 + local current_depth="$1" + local parent_dir="$2" + local start_time="$3" - if [ "$current_depth" -le 10 ]; then - local num_subfolders=$(random_number 1 50) - echo "Creating $num_subfolders subfolders at depth $current_depth" - for ((i=1; i<=num_subfolders; i++)); do - local subfolder="$parent_dir/$(random_string 255)" - mkdir -p "$subfolder" - ((generated_folders++)) - - # Display progress - local elapsed_time=$(( $(date +%s) - start_time )) - local estimated_total_time=$(( elapsed_time * total_folders / generated_folders )) - local remaining_time=$(( estimated_total_time - elapsed_time )) - echo "Generated: $generated_folders/$total_folders folders. Estimated time left: $remaining_time seconds." + if [ "$current_depth" -le 10 ]; then + local num_subfolders + num_subfolders=$(random_number 1 50) + echo "Creating $num_subfolders subfolders at depth $current_depth" + for ((i = 1; i <= num_subfolders; i++)); do + local subfolder + subfolder="$parent_dir/$(random_string 255)" + mkdir -p "$subfolder" + ((generated_folders++)) - # Create random number of empty files - local num_files=$(random_number 10 100) - echo "Creating $num_files files" - for ((j=1; j<=num_files; j++)); do - touch "$subfolder/$(random_string 255)" - done + # Display progress + local elapsed_time + elapsed_time=$(($(date +%s) - start_time)) + local estimated_total_time + estimated_total_time=$((elapsed_time * total_folders / generated_folders)) + local remaining_time + remaining_time=$((estimated_total_time - elapsed_time)) + echo "Generated: $generated_folders/$total_folders folders. Estimated time left: $remaining_time seconds." - # Recursively create subfolders - create_structure $((current_depth + 1)) "$subfolder" $start_time - done - fi + # Create random number of empty files + local num_files + num_files=$(random_number 10 100) + echo "Creating $num_files files" + for ((j = 1; j <= num_files; j++)); do + touch "$subfolder/$(random_string 255)" + done + + # Recursively create subfolders + create_structure $((current_depth + 1)) "$subfolder" "$start_time" + done + fi } # Main folder main_folder="/home/k.rudnicki@aiclearing.com/testsAndMisc/Bash/main_folder" mkdir -p "$main_folder" -# Calculate total folders to be created +# Calculate total folders to be created (best-effort). If calculation is expensive, you can uncomment. # total_folders=$(calculate_total_folders 1) +# Fallback when not precomputed: estimate grows as we generate +total_folders=${total_folders:-0} generated_folders=0 -echo "Total folders to be generated: $total_folders" +echo "Total folders to be generated: ${total_folders:-unknown}" # Start creating structure from the main folder start_time=$(date +%s) -create_structure 1 "$main_folder" $start_time \ No newline at end of file +create_structure 1 "$main_folder" "$start_time" diff --git a/scripts/misc/testsAndMisc-bash/get_rnnoise_model.sh b/scripts/misc/testsAndMisc-bash/get_rnnoise_model.sh index 2ac1057..9b1d856 100755 --- a/scripts/misc/testsAndMisc-bash/get_rnnoise_model.sh +++ b/scripts/misc/testsAndMisc-bash/get_rnnoise_model.sh @@ -14,18 +14,24 @@ set -euo pipefail ask_yes_no() { read -r -p "$1 [y/N]: " ans || true case "${ans:-}" in - y|Y|yes|YES) return 0;; - *) return 1;; + y | Y | yes | YES) return 0 ;; + *) return 1 ;; esac } -has_cmd() { command -v "$1" >/dev/null 2>&1; } +has_cmd() { command -v "$1" > /dev/null 2>&1; } YES=false while [[ $# -gt 0 ]]; do case "$1" in - -y|--yes) YES=true; shift;; - *) echo "Unknown option: $1" >&2; exit 2;; + -y | --yes) + YES=true + shift + ;; + *) + echo "Unknown option: $1" >&2 + exit 2 + ;; esac done @@ -35,7 +41,7 @@ RN_TARGET_NAME=${RN_TARGET_NAME:-"rnnoise_model.rnnn"} mkdir -p "$RN_TARGET_DIR" dest="$RN_TARGET_DIR/$RN_TARGET_NAME" -if [[ -f "$dest" ]]; then +if [[ -f $dest ]]; then echo "Model already exists at: $dest" exit 0 fi @@ -53,7 +59,7 @@ if ! has_cmd curl && ! has_cmd wget; then fi # Priority 1: explicit URL -if [[ -n "${RN_URL:-}" ]]; then +if [[ -n ${RN_URL:-} ]]; then echo "Downloading RNNoise model from RN_URL: $RN_URL" >&2 tmp=$(mktemp) if has_cmd curl; then @@ -61,7 +67,7 @@ if [[ -n "${RN_URL:-}" ]]; then else wget -qO "$tmp" "$RN_URL" fi - if [[ -s "$tmp" ]]; then + if [[ -s $tmp ]]; then mv "$tmp" "$dest" echo "Saved RNNoise model to: $dest" exit 0 @@ -83,7 +89,7 @@ for u in "${NU_URLS[@]}"; do tmp=$(mktemp) if has_cmd curl; then if curl -fsSL "$u" -o "$tmp"; then - if [[ -s "$tmp" ]]; then + if [[ -s $tmp ]]; then mv "$tmp" "$dest" echo "Saved RNNoise model to: $dest" >&2 exit 0 @@ -91,7 +97,7 @@ for u in "${NU_URLS[@]}"; do fi else if wget -qO "$tmp" "$u"; then - if [[ -s "$tmp" ]]; then + if [[ -s $tmp ]]; then mv "$tmp" "$dest" echo "Saved RNNoise model to: $dest" >&2 exit 0 @@ -110,7 +116,7 @@ for u in "${RNNDN_URLS[@]}"; do tmp=$(mktemp) if has_cmd curl; then if curl -fsSL "$u" -o "$tmp"; then - if [[ -s "$tmp" ]]; then + if [[ -s $tmp ]]; then mv "$tmp" "$dest" echo "Saved RNNoise model to: $dest" >&2 exit 0 @@ -118,7 +124,7 @@ for u in "${RNNDN_URLS[@]}"; do fi else if wget -qO "$tmp" "$u"; then - if [[ -s "$tmp" ]]; then + if [[ -s $tmp ]]; then mv "$tmp" "$dest" echo "Saved RNNoise model to: $dest" >&2 exit 0 @@ -172,10 +178,10 @@ done if has_cmd yay; then echo "Attempting to install AUR packages that may include RNNoise models..." >&2 set +e - yay -S --noconfirm denoiseit-git 2>/dev/null - yay -S --noconfirm speech-denoiser-git 2>/dev/null + yay -S --noconfirm denoiseit-git 2> /dev/null + yay -S --noconfirm speech-denoiser-git 2> /dev/null set -e - mapfile -t found < <(bash -lc 'shopt -s globstar nullglob; for f in /usr/share/**/*.nn /usr/share/**/*.rnnn /usr/local/share/**/*.nn /usr/local/share/**/*.rnnn; do [[ -f "$f" ]] && echo "$f"; done' 2>/dev/null || true) + mapfile -t found < <(bash -lc 'shopt -s globstar nullglob; for f in /usr/share/**/*.nn /usr/share/**/*.rnnn /usr/local/share/**/*.nn /usr/local/share/**/*.rnnn; do [[ -f "$f" ]] && echo "$f"; done' 2> /dev/null || true) if [[ ${#found[@]} -gt 0 ]]; then echo "Found candidate models:" >&2 printf ' %s\n' "${found[@]}" >&2 diff --git a/scripts/misc/testsAndMisc-bash/install_ffmpeg_with_arnndn.sh b/scripts/misc/testsAndMisc-bash/install_ffmpeg_with_arnndn.sh index 8c384c1..12cd94b 100755 --- a/scripts/misc/testsAndMisc-bash/install_ffmpeg_with_arnndn.sh +++ b/scripts/misc/testsAndMisc-bash/install_ffmpeg_with_arnndn.sh @@ -14,12 +14,12 @@ print_info() { ask_yes_no() { read -r -p "$1 [y/N]: " ans || true case "${ans:-}" in - y|Y|yes|YES) return 0;; - *) return 1;; + y | Y | yes | YES) return 0 ;; + *) return 1 ;; esac } -has_cmd() { command -v "$1" >/dev/null 2>&1; } +has_cmd() { command -v "$1" > /dev/null 2>&1; } detect_distro() { if [[ -f /etc/os-release ]]; then @@ -39,13 +39,13 @@ main() { print_info "Your ffmpeg already supports arnndn." else case "$distro" in - ubuntu|debian) + ubuntu | debian) print_info "On Ubuntu/Debian, the official repo may lack newer filters. Consider a PPA or build from source." echo "Options:" echo " - ppa: sudo add-apt-repository ppa:savoury1/ffmpeg6 && sudo apt update && sudo apt install ffmpeg" echo " - source build (recommended for latest): run this script to build from source" ;; - arch|manjaro|endeavouros) + arch | manjaro | endeavouros) print_info "On Arch-based distros, ffmpeg is recent. Try: sudo pacman -Syu ffmpeg" ;; fedora) @@ -89,12 +89,12 @@ main() { fi fi # Dependencies - if [[ "$distro" == "ubuntu" || "$distro" == "debian" ]]; then + if [[ $distro == "ubuntu" || $distro == "debian" ]]; then sudo apt update sudo apt install -y git build-essential yasm nasm pkg-config libx264-dev libx265-dev libvpx-dev libopus-dev libfdk-aac-dev libmp3lame-dev libvorbis-dev libass-dev libfreetype6-dev libgnutls28-dev libaom-dev libdav1d-dev libxvidcore-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev libxcb-shape0-dev libdrm-dev libvulkan-dev libva-dev libvdpau-dev librtmp-dev libunistring-dev libgnutls28-dev libchromaprint-dev libbluray-dev librubberband-dev libspeex-dev libsoxr-dev libvmaf-dev libzimg-dev libsvtav1-dev libtheora-dev libwebp-dev libopenal-dev libjack-jackd2-dev libpulse-dev librnnoise-dev - elif [[ "$distro" == "arch" || "$distro" == "manjaro" || "$distro" == "endeavouros" ]]; then + elif [[ $distro == "arch" || $distro == "manjaro" || $distro == "endeavouros" ]]; then sudo pacman -Syu --needed base-devel yasm nasm pkgconf rnnoise - elif [[ "$distro" == "fedora" ]]; then + elif [[ $distro == "fedora" ]]; then sudo dnf install -y git make gcc yasm nasm pkgconf-pkg-config rnnoise-devel libX11-devel libXext-devel libXfixes-devel libXv-devel libXrandr-devel libXi-devel libXtst-devel libXinerama-devel freetype-devel fontconfig-devel libass-devel libvpx-devel libaom-devel libdav1d-devel zimg-devel rubberband-devel soxr-devel libvorbis-devel opus-devel lame-devel else echo "Note: please ensure rnnoise development headers are installed (pkg-config rnnoise)." >&2 diff --git a/scripts/misc/testsAndMisc-bash/install_unity_mcp.sh b/scripts/misc/testsAndMisc-bash/install_unity_mcp.sh index 6fd34c7..e47e3f9 100755 --- a/scripts/misc/testsAndMisc-bash/install_unity_mcp.sh +++ b/scripts/misc/testsAndMisc-bash/install_unity_mcp.sh @@ -10,183 +10,185 @@ BLUE="\033[34m" RESET="\033[0m" info() { - printf "%b[%s]%b %s\n" "$BLUE" "$SCRIPT_NAME" "$RESET" "$*" + printf "%b[%s]%b %s\n" "$BLUE" "$SCRIPT_NAME" "$RESET" "$*" } warn() { - printf "%b[%s]%b %s\n" "$YELLOW" "$SCRIPT_NAME" "$RESET" "$*" >&2 + printf "%b[%s]%b %s\n" "$YELLOW" "$SCRIPT_NAME" "$RESET" "$*" >&2 } error() { - printf "%b[%s]%b %s\n" "$RED" "$SCRIPT_NAME" "$RESET" "$*" >&2 + printf "%b[%s]%b %s\n" "$RED" "$SCRIPT_NAME" "$RESET" "$*" >&2 } require_command() { - local cmd="$1" - local package_hint="${2:-}" + local cmd="$1" + local package_hint="${2:-}" - if ! command -v "$cmd" >/dev/null 2>&1; then - if [[ -n "$package_hint" ]]; then - error "Missing command '$cmd'. Try installing the package: $package_hint" - else - error "Missing command '$cmd'." - fi - exit 1 - fi + if ! command -v "$cmd" > /dev/null 2>&1; then + if [[ -n $package_hint ]]; then + error "Missing command '$cmd'. Try installing the package: $package_hint" + else + error "Missing command '$cmd'." + fi + exit 1 + fi } ensure_pacman_packages() { - local packages=("python" "git" "curl" "jq" "code") - local missing=() - for pkg in "${packages[@]}"; do - if ! pacman -Qi "$pkg" >/dev/null 2>&1; then - missing+=("$pkg") - fi - done + local packages=("python" "git" "curl" "jq" "code") + local missing=() + for pkg in "${packages[@]}"; do + if ! pacman -Qi "$pkg" > /dev/null 2>&1; then + missing+=("$pkg") + fi + done - if (( ${#missing[@]} > 0 )); then - info "Installing required packages with pacman: ${missing[*]}" - sudo pacman -S --needed --noconfirm "${missing[@]}" - else - info "All required pacman packages are already installed." - fi + if ((${#missing[@]} > 0)); then + info "Installing required packages with pacman: ${missing[*]}" + sudo pacman -S --needed --noconfirm "${missing[@]}" + else + info "All required pacman packages are already installed." + fi } install_uv() { - if command -v uv >/dev/null 2>&1; then - info "uv is already installed." - return - fi + if command -v uv > /dev/null 2>&1; then + info "uv is already installed." + return + fi - info "Installing uv toolchain manager via official installer." - curl -LsSf https://astral.sh/uv/install.sh | sh + info "Installing uv toolchain manager via official installer." + curl -LsSf https://astral.sh/uv/install.sh | sh - local local_bin="$HOME/.local/bin" - if [[ ":$PATH:" != *":$local_bin:"* ]]; then - warn "Adding $local_bin to PATH in ~/.profile and ~/.zshrc. Open a new shell to apply." - printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$HOME/.profile" - printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$HOME/.zshrc" - fi + local local_bin="$HOME/.local/bin" + if [[ :$PATH: != *":$local_bin:"* ]]; then + warn "Adding $local_bin to PATH in ~/.profile and ~/.zshrc. Open a new shell to apply." + printf "\nexport PATH=\"\$HOME/.local/bin:\$PATH\"\n" >> "$HOME/.profile" + printf "\nexport PATH=\"\$HOME/.local/bin:\$PATH\"\n" >> "$HOME/.zshrc" + fi } ensure_unity_hub() { - if command -v unityhub >/dev/null 2>&1; then - info "Unity Hub already installed." - return - fi + if command -v unityhub > /dev/null 2>&1; then + info "Unity Hub already installed." + return + fi - if command -v yay >/dev/null 2>&1; then - info "Installing Unity Hub from AUR using yay." - yay -S --needed --noconfirm unityhub - elif command -v flatpak >/dev/null 2>&1; then - warn "Unity Hub not found. Attempting Flatpak installation." - flatpak install -y com.unity.UnityHub || warn "Flatpak installation failed. Install Unity Hub manually via https://unity.com/download" - else - warn "Unity Hub not found and neither yay nor flatpak is available. Install Unity Hub manually from https://unity.com/download." - fi + if command -v yay > /dev/null 2>&1; then + info "Installing Unity Hub from AUR using yay." + yay -S --needed --noconfirm unityhub + elif command -v flatpak > /dev/null 2>&1; then + warn "Unity Hub not found. Attempting Flatpak installation." + flatpak install -y com.unity.UnityHub || warn "Flatpak installation failed. Install Unity Hub manually via https://unity.com/download" + else + warn "Unity Hub not found and neither yay nor flatpak is available. Install Unity Hub manually from https://unity.com/download." + fi } sync_unity_mcp_repo() { - local data_home="${XDG_DATA_HOME:-$HOME/.local/share}" - local unity_mcp_root="$data_home/UnityMCP" - local repo_dir="$unity_mcp_root/unity-mcp-repo" - local server_link="$unity_mcp_root/UnityMcpServer" - local candidates=( - "UnityMcpServer" - "UnityMcpBridge/UnityMcpServer" - "UnityMcpBridge/UnityMcpServer~" - ) - local server_subdir="" + local data_home="${XDG_DATA_HOME:-$HOME/.local/share}" + local unity_mcp_root="$data_home/UnityMCP" + local repo_dir="$unity_mcp_root/unity-mcp-repo" + local server_link="$unity_mcp_root/UnityMcpServer" + local candidates=( + "UnityMcpServer" + "UnityMcpBridge/UnityMcpServer" + "UnityMcpBridge/UnityMcpServer~" + ) + local server_subdir="" - mkdir -p "$unity_mcp_root" + mkdir -p "$unity_mcp_root" - if [[ -d "$repo_dir/.git" ]]; then - info "Updating existing unity-mcp repository." - git -C "$repo_dir" pull --ff-only - else - info "Cloning unity-mcp repository." - rm -rf "$repo_dir" - git clone --depth=1 https://github.com/CoplayDev/unity-mcp.git "$repo_dir" - fi + if [[ -d "$repo_dir/.git" ]]; then + info "Updating existing unity-mcp repository." + git -C "$repo_dir" pull --ff-only + else + info "Cloning unity-mcp repository." + rm -rf "$repo_dir" + git clone --depth=1 https://github.com/CoplayDev/unity-mcp.git "$repo_dir" + fi - for candidate in "${candidates[@]}"; do - if [[ -d "$repo_dir/$candidate/src" ]]; then - server_subdir="$candidate" - break - fi - done + for candidate in "${candidates[@]}"; do + if [[ -d "$repo_dir/$candidate/src" ]]; then + server_subdir="$candidate" + break + fi + done - if [[ -z "$server_subdir" ]]; then - error "UnityMcpServer src directory not found. Checked candidates: ${candidates[*]}" - error "Repository layout may have changed. Inspect $repo_dir for the new server location." - exit 1 - fi + if [[ -z $server_subdir ]]; then + error "UnityMcpServer src directory not found. Checked candidates: ${candidates[*]}" + error "Repository layout may have changed. Inspect $repo_dir for the new server location." + exit 1 + fi - ln -sfn "$repo_dir/$server_subdir" "$server_link" - info "UnityMcpServer synchronized at $server_link (source: $server_subdir)" + ln -sfn "$repo_dir/$server_subdir" "$server_link" + info "UnityMcpServer synchronized at $server_link (source: $server_subdir)" } configure_vscode_mcp() { - local data_home="${XDG_DATA_HOME:-$HOME/.local/share}" - local server_src="$data_home/UnityMCP/UnityMcpServer/src" - local mcp_config_dir="$HOME/.config/Code/User" - local mcp_config="$mcp_config_dir/mcp.json" - local tmp + local data_home="${XDG_DATA_HOME:-$HOME/.local/share}" + local server_src="$data_home/UnityMCP/UnityMcpServer/src" + local mcp_config_dir="$HOME/.config/Code/User" + local mcp_config="$mcp_config_dir/mcp.json" + local tmp - if [[ ! -d "$server_src" ]]; then - error "Server source directory $server_src is missing." - exit 1 - fi + if [[ ! -d $server_src ]]; then + error "Server source directory $server_src is missing." + exit 1 + fi - mkdir -p "$mcp_config_dir" + mkdir -p "$mcp_config_dir" - if [[ ! -f "$mcp_config" ]]; then - info "Creating new VS Code MCP configuration at $mcp_config" - echo '{}' > "$mcp_config" - else - info "Updating existing VS Code MCP configuration at $mcp_config" - fi + if [[ ! -f $mcp_config ]]; then + info "Creating new VS Code MCP configuration at $mcp_config" + echo '{}' > "$mcp_config" + else + info "Updating existing VS Code MCP configuration at $mcp_config" + fi - tmp="$(mktemp)" + tmp="$(mktemp)" - if ! jq '.' "$mcp_config" >/dev/null 2>&1; then - error "Existing $mcp_config is not valid JSON. Please fix it before running this script again." - exit 1 - fi + if ! jq '.' "$mcp_config" > /dev/null 2>&1; then + error "Existing $mcp_config is not valid JSON. Please fix it before running this script again." + exit 1 + fi - jq \ - --arg path "$server_src" \ - '(.servers //= {}) | - .servers.unityMCP = { - command: "uv", - args: ["--directory", $path, "run", "server.py"], - type: "stdio" - }' \ - "$mcp_config" > "$tmp" + jq \ + --arg path "$server_src" \ + '(.servers //= {}) | + .servers.unityMCP = { + command: "uv", + args: ["--directory", $path, "run", "server.py"], + type: "stdio" + }' \ + "$mcp_config" > "$tmp" - mv "$tmp" "$mcp_config" - info "VS Code MCP server configuration updated for UnityMCP." + mv "$tmp" "$mcp_config" + info "VS Code MCP server configuration updated for UnityMCP." } verify_python_version() { - require_command python "python" - local version - version="$(python - <<'PY' + + require_command python "python" + local version + version="$( + python - << 'PY' import sys print("%d.%d.%d" % sys.version_info[:3]) PY -)" - local major minor - IFS='.' read -r major minor _ <<< "$version" - if (( major < 3 || (major == 3 && minor < 12) )); then - error "Python 3.12+ is required. Detected version $version. Upgrade python before continuing." - exit 1 - fi - info "Python version $version satisfies requirement (>= 3.12)." + )" + local major minor + IFS='.' read -r major minor _ <<< "$version" + if ((major < 3 || (major == 3 && minor < 12))); then + error "Python 3.12+ is required. Detected version $version. Upgrade python before continuing." + exit 1 + fi + info "Python version $version satisfies requirement (>= 3.12)." } print_next_steps() { - cat <<'EOT' + cat << 'EOT' Next steps: 1. Launch Unity Hub and install a Unity Editor version 2021.3 LTS or newer. @@ -210,22 +212,22 @@ EOT } main() { - if [[ ! -f /etc/arch-release ]]; then - error "This script is intended for Arch Linux." - exit 1 - fi + if [[ ! -f /etc/arch-release ]]; then + error "This script is intended for Arch Linux." + exit 1 + fi - info "Ensuring base dependencies are installed." - require_command sudo "sudo" - require_command pacman "pacman" - ensure_pacman_packages - verify_python_version - install_uv - ensure_unity_hub - sync_unity_mcp_repo - configure_vscode_mcp - print_next_steps - info "Setup complete. Follow the next steps above to finish configuration inside Unity." + info "Ensuring base dependencies are installed." + require_command sudo "sudo" + require_command pacman "pacman" + ensure_pacman_packages + verify_python_version + install_uv + ensure_unity_hub + sync_unity_mcp_repo + configure_vscode_mcp + print_next_steps + info "Setup complete. Follow the next steps above to finish configuration inside Unity." } main "$@" diff --git a/scripts/misc/testsAndMisc-bash/libre_translate.sh b/scripts/misc/testsAndMisc-bash/libre_translate.sh index 502eef6..a59aa25 100755 --- a/scripts/misc/testsAndMisc-bash/libre_translate.sh +++ b/scripts/misc/testsAndMisc-bash/libre_translate.sh @@ -44,9 +44,19 @@ 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" + 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="" + GREEN="" + YELLOW="" + RED="" + BLUE="" + BOLD="" + RESET="" fi log() { echo -e "${BLUE}[INFO]${RESET} $*"; } @@ -55,7 +65,7 @@ err() { echo -e "${RED}[ERR ]${RESET} $*" >&2; } success() { echo -e "${GREEN}[OK ]${RESET} $*"; } usage() { - cat </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" + # 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; } + 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 + 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 + 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 + 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" + 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 + # 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 + 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}" + { + 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() { - log "Starting ephemeral container..." - 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..." + 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=$(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 + 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 + 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 + 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 + parse_args "$@" + ensure_root - if [[ ${UNINSTALL} -eq 1 ]]; then - uninstall_all - fi + 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 + install_docker + pull_image + if [[ ${PULL_ONLY} -eq 1 ]]; then + log "Pull-only requested, exiting." + exit 0 + fi - write_env_file + write_env_file - # Always ephemeral now - start_container_ephemeral + # Always ephemeral now + start_container_ephemeral - health_check - sample_request || true + 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 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 + 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: " - else - echo "API key authentication DISABLED (public instance)." - fi - [[ -n ${PRELOAD_LANGS} ]] && echo "Preloaded languages requested: ${PRELOAD_LANGS}" || true - echo "Environment file: ${ENV_FILE}" - echo "Manage: docker logs -f ${SERVICE_NAME} | docker stop ${SERVICE_NAME}" - echo "Uninstall: sudo ${SCRIPT_NAME} --uninstall" - echo + 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: " + else + echo "API key authentication DISABLED (public instance)." + fi + [[ -n ${PRELOAD_LANGS} ]] && echo "Preloaded languages requested: ${PRELOAD_LANGS}" || true + echo "Environment file: ${ENV_FILE}" + echo "Manage: docker logs -f ${SERVICE_NAME} | docker stop ${SERVICE_NAME}" + echo "Uninstall: sudo ${SCRIPT_NAME} --uninstall" + echo } main "$@" - diff --git a/scripts/misc/testsAndMisc-bash/process_table.sh b/scripts/misc/testsAndMisc-bash/process_table.sh index 553721b..ee15292 100755 --- a/scripts/misc/testsAndMisc-bash/process_table.sh +++ b/scripts/misc/testsAndMisc-bash/process_table.sh @@ -1,53 +1,52 @@ - #!/bin/bash process_table_schema() { - while IFS=$'\t' read -r column_name _ data_type _; do - # Print the column name and data type - echo -e "$column_name\t$data_type" - done < "$1" + while IFS=$'\t' read -r column_name _ data_type _; do + # Print the column name and data type + printf '%s\t%s\n' "$column_name" "$data_type" + done < "$1" } input_file="$1" # Check if a file is provided as an argument if [ $# -eq 0 ]; then - echo "Usage: $0 " - exit 1 + echo "Usage: $0 " + exit 1 fi # Process the provided file and skip the first row first_line=true process_table_schema "$input_file" | while IFS=$'\t' read -r column_name data_type; do - if [ "$first_line" = true ]; then - first_line=false - continue - fi - case "$data_type" in - "timestamp") - sqlalchemy_type="DateTime" - ;; - "int"|"integer"|"int4") - sqlalchemy_type="Integer" - ;; - "varchar"*|"text") - sqlalchemy_type="String" # handles types like varchar(256) - ;; - "boolean"|"bool") - sqlalchemy_type="Boolean" - ;; - "float"|"float8") - sqlalchemy_type="Float" - ;; - "serial4") - sqlalchemy_type="Integer" - ;; - "numeric"*) - sqlalchemy_type="Numeric" # handles types like numeric(12, 2) - ;; - *) - sqlalchemy_type="UNDEFINED_CHANGE_ME" # default to UNDEFINED_CHANGE_ME if data type is unrecognized - ;; - esac - echo "$column_name = Column($sqlalchemy_type)" -done \ No newline at end of file + if [ "$first_line" = true ]; then + first_line=false + continue + fi + case "$data_type" in + "timestamp") + sqlalchemy_type="DateTime" + ;; + "int" | "integer" | "int4") + sqlalchemy_type="Integer" + ;; + "varchar"* | "text") + sqlalchemy_type="String" # handles types like varchar(256) + ;; + "boolean" | "bool") + sqlalchemy_type="Boolean" + ;; + "float" | "float8") + sqlalchemy_type="Float" + ;; + "serial4") + sqlalchemy_type="Integer" + ;; + "numeric"*) + sqlalchemy_type="Numeric" # handles types like numeric(12, 2) + ;; + *) + sqlalchemy_type="UNDEFINED_CHANGE_ME" # default to UNDEFINED_CHANGE_ME if data type is unrecognized + ;; + esac + echo "$column_name = Column($sqlalchemy_type)" +done diff --git a/scripts/misc/testsAndMisc-bash/transcribe.sh b/scripts/misc/testsAndMisc-bash/transcribe.sh index e1cce85..deb0764 100755 --- a/scripts/misc/testsAndMisc-bash/transcribe.sh +++ b/scripts/misc/testsAndMisc-bash/transcribe.sh @@ -14,7 +14,7 @@ PY_RUNNER="$TOOLS_DIR/transcribe_fw.py" VENV_DIR="$PROJECT_DIR/.venv" usage() { - cat </dev/null 2>&1; then echo apt; return; fi - if command -v dnf >/dev/null 2>&1; then echo dnf; return; fi - if command -v yum >/dev/null 2>&1; then echo yum; return; fi - if command -v pacman >/dev/null 2>&1; then echo pacman; return; fi - if command -v zypper >/dev/null 2>&1; then echo zypper; return; fi - echo none + if command -v apt-get > /dev/null 2>&1; then + echo apt + return + fi + if command -v dnf > /dev/null 2>&1; then + echo dnf + return + fi + if command -v yum > /dev/null 2>&1; then + echo yum + return + fi + if command -v pacman > /dev/null 2>&1; then + echo pacman + return + fi + if command -v zypper > /dev/null 2>&1; then + echo zypper + return + fi + echo none } has_libcublas12() { - # Common system locations - for d in \ - /usr/lib \ - /usr/lib64 \ - /usr/local/cuda/lib64 \ - /usr/local/cuda-12*/lib64 \ - /opt/cuda/lib64 \ - /opt/cuda/targets/x86_64-linux/lib; do - [[ -e "$d/libcublas.so.12" ]] && return 0 || true - done - # venv-provided NVIDIA CUDA libs - if [[ -x "$VENV_DIR/bin/python" ]]; then - local pyver - pyver="$($VENV_DIR/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true)" - if [[ -n "$pyver" ]]; then - for d in "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib" \ - "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib" \ - "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib"; do - [[ -e "$d/libcublas.so.12" ]] && return 0 || true - done - fi - fi - return 1 + # Common system locations + for d in \ + /usr/lib \ + /usr/lib64 \ + /usr/local/cuda/lib64 \ + /usr/local/cuda-12*/lib64 \ + /opt/cuda/lib64 \ + /opt/cuda/targets/x86_64-linux/lib; do + [[ -e "$d/libcublas.so.12" ]] && return 0 || true + done + # venv-provided NVIDIA CUDA libs + if [[ -x "$VENV_DIR/bin/python" ]]; then + local pyver + pyver="$("$VENV_DIR"/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2> /dev/null || true)" + if [[ -n $pyver ]]; then + for d in "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib" \ + "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib" \ + "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib"; do + [[ -e "$d/libcublas.so.12" ]] && return 0 || true + done + fi + fi + return 1 } ensure_cuda_runtime() { - local mgr; mgr="$(detect_pkg_mgr)" - if [[ $OFFLINE -eq 1 ]]; then - if has_libcublas12; then return 0; fi - echo "CUDA runtime (libcublas.so.12) not found and offline mode is enabled. Install CUDA 12 runtime or rerun with --online." >&2 - exit 6 - fi - if has_libcublas12; then - return 0 - fi - if ! command -v sudo >/dev/null 2>&1; then - log "sudo not found; skipping CUDA runtime install attempt." - else - log "CUDA cuBLAS 12 not found; attempting to install CUDA runtime (manager: $mgr)" - set +e - case "$mgr" in - pacman) - sudo pacman -Sy --noconfirm cuda cudnn || true ;; - apt) - sudo apt-get update -y || true - sudo apt-get install -y nvidia-cuda-toolkit || true ;; - dnf|yum) - sudo "$mgr" install -y cuda cudnn || true ;; - zypper) - sudo zypper install -y cuda cudnn || true ;; - *) log "Unknown package manager; cannot install CUDA automatically." ;; - esac - set -e - fi - # Re-check - if ! has_libcublas12; then - echo "CUDA runtime (libcublas.so.12) not found after attempted install. Please install CUDA 12 toolkit/runtime and re-run." >&2 - exit 6 - fi + local mgr + mgr="$(detect_pkg_mgr)" + if [[ $OFFLINE -eq 1 ]]; then + if has_libcublas12; then return 0; fi + echo "CUDA runtime (libcublas.so.12) not found and offline mode is enabled. Install CUDA 12 runtime or rerun with --online." >&2 + exit 6 + fi + if has_libcublas12; then + return 0 + fi + if ! command -v sudo > /dev/null 2>&1; then + log "sudo not found; skipping CUDA runtime install attempt." + else + log "CUDA cuBLAS 12 not found; attempting to install CUDA runtime (manager: $mgr)" + set +e + case "$mgr" in + pacman) + sudo pacman -Sy --noconfirm cuda cudnn || true + ;; + apt) + sudo apt-get update -y || true + sudo apt-get install -y nvidia-cuda-toolkit || true + ;; + dnf | yum) + sudo "$mgr" install -y cuda cudnn || true + ;; + zypper) + sudo zypper install -y cuda cudnn || true + ;; + *) log "Unknown package manager; cannot install CUDA automatically." ;; + esac + set -e + fi + # Re-check + if ! has_libcublas12; then + echo "CUDA runtime (libcublas.so.12) not found after attempted install. Please install CUDA 12 toolkit/runtime and re-run." >&2 + exit 6 + fi } install_system_deps() { - have_cmd() { command -v "$1" >/dev/null 2>&1; } - local need_ffmpeg=0 need_espeak=0 - have_cmd ffmpeg || need_ffmpeg=1 - have_cmd espeak-ng || need_espeak=1 + have_cmd() { command -v "$1" > /dev/null 2>&1; } + local need_ffmpeg=0 need_espeak=0 + have_cmd ffmpeg || need_ffmpeg=1 + have_cmd espeak-ng || need_espeak=1 - # If diarization requested and online, we may also try to ensure libsndfile - local need_libsndfile=0 - if [[ "${FW_DIARIZE:-}" == "1" ]]; then - # Heuristic: check common library file - if [[ ! -e /usr/lib/x86_64-linux-gnu/libsndfile.so && ! -e /usr/lib/libsndfile.so && ! -e /usr/lib64/libsndfile.so ]]; then - need_libsndfile=1 - fi - fi + # If diarization requested and online, we may also try to ensure libsndfile + local need_libsndfile=0 + if [[ ${FW_DIARIZE:-} == "1" ]]; then + # Heuristic: check common library file + if [[ ! -e /usr/lib/x86_64-linux-gnu/libsndfile.so && ! -e /usr/lib/libsndfile.so && ! -e /usr/lib64/libsndfile.so ]]; then + need_libsndfile=1 + fi + fi - if [[ $need_ffmpeg -eq 0 && $need_espeak -eq 0 && $need_libsndfile -eq 0 ]]; then - log "System deps present: ffmpeg, espeak-ng${FW_DIARIZE:+, libsndfile}" - return 0 - fi + if [[ $need_ffmpeg -eq 0 && $need_espeak -eq 0 && $need_libsndfile -eq 0 ]]; then + log "System deps present: ffmpeg, espeak-ng${FW_DIARIZE:+, libsndfile}" + return 0 + fi - if [[ $OFFLINE -eq 1 ]]; then - echo "Missing system dependencies (ffmpeg/espeak-ng) but running in offline mode. Install them or rerun with --online." >&2 - exit 5 - fi + if [[ $OFFLINE -eq 1 ]]; then + echo "Missing system dependencies (ffmpeg/espeak-ng) but running in offline mode. Install them or rerun with --online." >&2 + exit 5 + fi - local mgr; mgr="$(detect_pkg_mgr)" - log "Detected package manager: $mgr (installing missing: $([[ $need_ffmpeg -eq 1 ]] && echo ffmpeg )$([[ $need_espeak -eq 1 ]] && echo espeak-ng )$([[ $need_libsndfile -eq 1 ]] && echo libsndfile))" + local mgr + mgr="$(detect_pkg_mgr)" + log "Detected package manager: $mgr (installing missing: $([[ $need_ffmpeg -eq 1 ]] && echo ffmpeg)$([[ $need_espeak -eq 1 ]] && echo espeak-ng)$([[ $need_libsndfile -eq 1 ]] && echo libsndfile))" - if ! command -v sudo >/dev/null 2>&1; then - log "sudo not found; skipping system package installation attempt." - return 0 - fi + if ! command -v sudo > /dev/null 2>&1; then + log "sudo not found; skipping system package installation attempt." + return 0 + fi - # Avoid exiting on install errors; continue best-effort - set +e - case "$mgr" in - apt) - sudo apt-get update -y || log "apt-get update failed; continuing" - pkgs=(python3-venv python3-pip) - [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) - [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) - if [[ $need_libsndfile -eq 1 ]]; then - # Try both names across releases - pkgs+=(libsndfile1) - sudo apt-get install -y libsndfile1 || true - # If that failed, try libsndfile2 (newer distros) - sudo apt-get install -y libsndfile2 || true - fi - sudo apt-get install -y "${pkgs[@]}" || log "apt-get install failed; continuing" ;; - dnf) - pkgs=(python3-venv python3-pip) - [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) - [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) - [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile) - sudo dnf install -y "${pkgs[@]}" || log "dnf install failed; continuing" ;; - yum) - pkgs=(python3-venv python3-pip) - [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) - [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) - [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile) - sudo yum install -y "${pkgs[@]}" || log "yum install failed; continuing" ;; - pacman) - pkgs=(python-virtualenv python-pip) - [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) - [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) - [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile) - sudo pacman -Sy --noconfirm "${pkgs[@]}" || log "pacman install failed; continuing" ;; - zypper) - pkgs=(python311-virtualenv python311-pip) - [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) - [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) - [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile1) - sudo zypper install -y "${pkgs[@]}" || log "zypper install failed; continuing" ;; - *) - log "Unknown package manager; please ensure ffmpeg and espeak-ng are installed." ;; - esac - set -e + # Avoid exiting on install errors; continue best-effort + set +e + case "$mgr" in + apt) + sudo apt-get update -y || log "apt-get update failed; continuing" + pkgs=(python3-venv python3-pip) + [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) + [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) + if [[ $need_libsndfile -eq 1 ]]; then + # Try both names across releases + pkgs+=(libsndfile1) + sudo apt-get install -y libsndfile1 || true + # If that failed, try libsndfile2 (newer distros) + sudo apt-get install -y libsndfile2 || true + fi + sudo apt-get install -y "${pkgs[@]}" || log "apt-get install failed; continuing" + ;; + dnf) + pkgs=(python3-venv python3-pip) + [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) + [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) + [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile) + sudo dnf install -y "${pkgs[@]}" || log "dnf install failed; continuing" + ;; + yum) + pkgs=(python3-venv python3-pip) + [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) + [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) + [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile) + sudo yum install -y "${pkgs[@]}" || log "yum install failed; continuing" + ;; + pacman) + pkgs=(python-virtualenv python-pip) + [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) + [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) + [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile) + sudo pacman -Sy --noconfirm "${pkgs[@]}" || log "pacman install failed; continuing" + ;; + zypper) + pkgs=(python311-virtualenv python311-pip) + [[ $need_ffmpeg -eq 1 ]] && pkgs+=(ffmpeg) + [[ $need_espeak -eq 1 ]] && pkgs+=(espeak-ng) + [[ $need_libsndfile -eq 1 ]] && pkgs+=(libsndfile1) + sudo zypper install -y "${pkgs[@]}" || log "zypper install failed; continuing" + ;; + *) + log "Unknown package manager; please ensure ffmpeg and espeak-ng are installed." + ;; + esac + set -e } setup_venv() { - if [[ ! -d "$VENV_DIR" ]]; then - log "Creating venv at $VENV_DIR" - python3 -m venv "$VENV_DIR" - fi - # shellcheck disable=SC1091 - source "$VENV_DIR/bin/activate" - if [[ $OFFLINE -eq 0 ]]; then - python -m pip install --upgrade pip wheel setuptools - fi + if [[ ! -d $VENV_DIR ]]; then + log "Creating venv at $VENV_DIR" + python3 -m venv "$VENV_DIR" + fi + # shellcheck disable=SC1091 + source "$VENV_DIR/bin/activate" + if [[ $OFFLINE -eq 0 ]]; then + python -m pip install --upgrade pip wheel setuptools + fi } install_python_deps() { - # Install deps; if NVIDIA GPU is present, prefer CUDA-capable stack (cu12) - local has_nvidia_flag="${1:-0}" - log "Installing faster-whisper and dependencies" - export PIP_DISABLE_PIP_VERSION_CHECK=1 - export PIP_DEFAULT_TIMEOUT=${PIP_DEFAULT_TIMEOUT:-20} - if [[ $OFFLINE -eq 1 ]]; then - # Offline: do not install, just verify modules - if ! python -c 'import faster_whisper' >/dev/null 2>&1; then - echo "Python dependency 'faster_whisper' not found in offline mode. Run with --online to install." >&2 - exit 7 - fi - # If diarization requested offline, check for its deps too (warn-only) - if [[ "${FW_DIARIZE:-}" == "1" ]]; then - python - <<'PY' || true + # Install deps; if NVIDIA GPU is present, prefer CUDA-capable stack (cu12) + local has_nvidia_flag="${1:-0}" + log "Installing faster-whisper and dependencies" + export PIP_DISABLE_PIP_VERSION_CHECK=1 + export PIP_DEFAULT_TIMEOUT=${PIP_DEFAULT_TIMEOUT:-20} + if [[ $OFFLINE -eq 1 ]]; then + # Offline: do not install, just verify modules + if ! python -c 'import faster_whisper' > /dev/null 2>&1; then + echo "Python dependency 'faster_whisper' not found in offline mode. Run with --online to install." >&2 + exit 7 + fi + # If diarization requested offline, check for its deps too (warn-only) + if [[ ${FW_DIARIZE:-} == "1" ]]; then + python - << 'PY' || true try: import soundfile, speechbrain, torch # noqa: F401 except Exception as e: print(f"[WARN] Diarization deps missing offline ({e}); speaker labels will be skipped.") PY - fi - return 0 - fi - if [[ "$has_nvidia_flag" -eq 1 ]]; then - # If ctranslate2 is not installed, attempt CUDA-enabled wheel (quiet, with fallback) - if ! "$VENV_DIR/bin/python" -c 'import ctranslate2' >/dev/null 2>&1; then - log "Installing CUDA-enabled CTranslate2 (cu12 wheel)" - python -m pip install -q --retries 1 --upgrade "ctranslate2<5,>=4.0" --extra-index-url https://download.opennmt.net/ctranslate2/cu12 || \ - log "Warning: could not reach cu12 wheel index; will proceed with available ctranslate2" - fi - # Ensure NVIDIA CUDA 12 runtime libs are available inside the venv - python -m pip install -q --retries 1 --upgrade nvidia-cublas-cu12 nvidia-cuda-runtime-cu12 nvidia-cudnn-cu12 || \ - log "Warning: failed to install NVIDIA cu12 runtime libs via pip" - fi - python -m pip install -q --retries 1 --upgrade faster-whisper ffmpeg-python + fi + return 0 + fi + if [[ $has_nvidia_flag -eq 1 ]]; then + # If ctranslate2 is not installed, attempt CUDA-enabled wheel (quiet, with fallback) + if ! "$VENV_DIR/bin/python" -c 'import ctranslate2' > /dev/null 2>&1; then + log "Installing CUDA-enabled CTranslate2 (cu12 wheel)" + python -m pip install -q --retries 1 --upgrade "ctranslate2<5,>=4.0" --extra-index-url https://download.opennmt.net/ctranslate2/cu12 || + log "Warning: could not reach cu12 wheel index; will proceed with available ctranslate2" + fi + # Ensure NVIDIA CUDA 12 runtime libs are available inside the venv + python -m pip install -q --retries 1 --upgrade nvidia-cublas-cu12 nvidia-cuda-runtime-cu12 nvidia-cudnn-cu12 || + log "Warning: failed to install NVIDIA cu12 runtime libs via pip" + fi + python -m pip install -q --retries 1 --upgrade faster-whisper ffmpeg-python - # If diarization requested and online, install its Python deps best-effort - if [[ "${FW_DIARIZE:-}" == "1" ]]; then - python -m pip install -q --retries 1 --upgrade soundfile speechbrain || \ - log "Warning: failed to install soundfile/speechbrain" - # Torch and torchaudio CPU wheels (force to avoid mismatched CUDA builds) - python -m pip install -q --retries 1 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cpu torch torchaudio || \ - log "Warning: failed to install torch/torchaudio CPU wheels" - fi - python - <<'PY' + # If diarization requested and online, install its Python deps best-effort + if [[ ${FW_DIARIZE:-} == "1" ]]; then + python -m pip install -q --retries 1 --upgrade soundfile speechbrain || + log "Warning: failed to install soundfile/speechbrain" + # Torch and torchaudio CPU wheels (force to avoid mismatched CUDA builds) + python -m pip install -q --retries 1 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cpu torch torchaudio || + log "Warning: failed to install torch/torchaudio CPU wheels" + fi + python - << 'PY' import sys print(f"[PY] Python {sys.version.split()[0]} dependencies installed.") PY } ensure_runner() { - if [[ ! -f "$PY_RUNNER" ]]; then - echo "Runner not found: $PY_RUNNER" >&2 - exit 3 - fi + if [[ ! -f $PY_RUNNER ]]; then + echo "Runner not found: $PY_RUNNER" >&2 + exit 3 + fi } generate_test_audio() { - local tmpwav - tmpwav="${PROJECT_DIR}/test_fw.wav" - if command -v espeak-ng >/dev/null 2>&1; then - log "Generating test audio via espeak-ng -> $tmpwav" >&2 - espeak-ng -w "$tmpwav" "This is a quick test of faster whisper transcription." >/dev/null 2>&1 || true - fi - # If espeak-ng failed or not present, try espeak - if [[ ! -s "$tmpwav" ]] && command -v espeak >/dev/null 2>&1; then - log "espeak-ng unavailable or failed; trying espeak -> $tmpwav" >&2 - espeak -w "$tmpwav" "This is a quick test of faster whisper transcription." >/dev/null 2>&1 || true - fi - # Fallback: generate tone via Python stdlib (no external deps) - if [[ ! -s "$tmpwav" ]]; then - log "Generating 3s 1kHz WAV via Python stdlib -> $tmpwav" >&2 - python3 -c 'import sys,wave,math,array;outfile=sys.argv[1];fr=16000;dur=3;freq=1000.0;ampl=0.3;n=fr*dur;data=array.array("h",[int(max(-1.0,min(1.0,ampl*math.sin(2*math.pi*freq*(i/fr))))*32767) for i in range(n)]);wf=wave.open(outfile,"w");wf.setnchannels(1);wf.setsampwidth(2);wf.setframerate(fr);wf.writeframes(data.tobytes());wf.close()' "$tmpwav" || true - fi - # Final fallback: tone via ffmpeg - if [[ ! -s "$tmpwav" ]]; then - log "Creating a 3s sine tone WAV via ffmpeg -> $tmpwav" >&2 - ffmpeg -f lavfi -i sine=frequency=1000:duration=3 -ar 16000 -ac 1 -f wav -y "$tmpwav" >/dev/null 2>&1 || true - fi - echo "$tmpwav" + local tmpwav + tmpwav="${PROJECT_DIR}/test_fw.wav" + if command -v espeak-ng > /dev/null 2>&1; then + log "Generating test audio via espeak-ng -> $tmpwav" >&2 + espeak-ng -w "$tmpwav" "This is a quick test of faster whisper transcription." > /dev/null 2>&1 || true + fi + # If espeak-ng failed or not present, try espeak + if [[ ! -s $tmpwav ]] && command -v espeak > /dev/null 2>&1; then + log "espeak-ng unavailable or failed; trying espeak -> $tmpwav" >&2 + espeak -w "$tmpwav" "This is a quick test of faster whisper transcription." > /dev/null 2>&1 || true + fi + # Fallback: generate tone via Python stdlib (no external deps) + if [[ ! -s $tmpwav ]]; then + log "Generating 3s 1kHz WAV via Python stdlib -> $tmpwav" >&2 + python3 -c 'import sys,wave,math,array;outfile=sys.argv[1];fr=16000;dur=3;freq=1000.0;ampl=0.3;n=fr*dur;data=array.array("h",[int(max(-1.0,min(1.0,ampl*math.sin(2*math.pi*freq*(i/fr))))*32767) for i in range(n)]);wf=wave.open(outfile,"w");wf.setnchannels(1);wf.setsampwidth(2);wf.setframerate(fr);wf.writeframes(data.tobytes());wf.close()' "$tmpwav" || true + fi + # Final fallback: tone via ffmpeg + if [[ ! -s $tmpwav ]]; then + log "Creating a 3s sine tone WAV via ffmpeg -> $tmpwav" >&2 + ffmpeg -f lavfi -i sine=frequency=1000:duration=3 -ar 16000 -ac 1 -f wav -y "$tmpwav" > /dev/null 2>&1 || true + fi + echo "$tmpwav" } prepare_model() { - # Download a model for offline use into MODEL_DIR - local name="$1" - mkdir -p "$MODEL_DIR" - # shellcheck disable=SC1091 - source "$VENV_DIR/bin/activate" - log "Preparing model '$name' into $MODEL_DIR" - python - <&2 - exit 2 - fi - install_python_deps 0 - export FW_PREPARE_NAME="$PREPARE_MODEL" - export FW_MODEL_DIR="$MODEL_DIR" - prepare_model "$PREPARE_MODEL" - log "Model '$PREPARE_MODEL' downloaded to $MODEL_DIR" - exit 0 - fi + # If asked to prepare a model, do that and exit + if [[ -n $PREPARE_MODEL ]]; then + if [[ $OFFLINE -eq 1 ]]; then + echo "--prepare-model requires network; rerun with --online." >&2 + exit 2 + fi + install_python_deps 0 + export FW_PREPARE_NAME="$PREPARE_MODEL" + export FW_MODEL_DIR="$MODEL_DIR" + prepare_model "$PREPARE_MODEL" + log "Model '$PREPARE_MODEL' downloaded to $MODEL_DIR" + exit 0 + fi - # Detect NVIDIA GPU and enforce CUDA if present - has_nvidia=0 - if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi -L >/dev/null 2>&1; then - has_nvidia=1 - fi - install_python_deps "$has_nvidia" - ensure_runner + # Detect NVIDIA GPU and enforce CUDA if present + has_nvidia=0 + if command -v nvidia-smi > /dev/null 2>&1 && nvidia-smi -L > /dev/null 2>&1; then + has_nvidia=1 + fi + install_python_deps "$has_nvidia" + ensure_runner - local input="$INPUT_FILE" - if [[ -z "$input" ]]; then - input="$(generate_test_audio)" - if [[ ! -s "$input" ]]; then - echo "Failed to generate test audio. Please provide an audio file." >&2 - exit 4 - fi - fi + local input="$INPUT_FILE" + if [[ -z $input ]]; then + input="$(generate_test_audio)" + if [[ ! -s $input ]]; then + echo "Failed to generate test audio. Please provide an audio file." >&2 + exit 4 + fi + fi - if [[ ! -f "$input" ]]; then - echo "Input file not found: $input" >&2 - exit 2 - fi + if [[ ! -f $input ]]; then + echo "Input file not found: $input" >&2 + exit 2 + fi - local args=("$input" "--model" "$MODEL") - [[ -n "$LANGUAGE" ]] && args+=("--language" "$LANGUAGE") - [[ -n "$OUTDIR" ]] && args+=("--outdir" "$OUTDIR") + local args=("$input" "--model" "$MODEL") + [[ -n $LANGUAGE ]] && args+=("--language" "$LANGUAGE") + [[ -n $OUTDIR ]] && args+=("--outdir" "$OUTDIR") - # Pass diarization via env if requested - if [[ "${FW_DIARIZE:-}" == "1" ]]; then - args+=("--diarize") - if [[ -n "${FW_NUM_SPEAKERS:-}" ]]; then - args+=("--num-speakers" "${FW_NUM_SPEAKERS}") - fi - fi + # Pass diarization via env if requested + if [[ ${FW_DIARIZE:-} == "1" ]]; then + args+=("--diarize") + if [[ -n ${FW_NUM_SPEAKERS:-} ]]; then + args+=("--num-speakers" "${FW_NUM_SPEAKERS}") + fi + fi - if [[ $has_nvidia -eq 1 ]]; then - ensure_cuda_runtime - # Export common CUDA paths in case the env lacks them - export CUDA_HOME="${CUDA_HOME:-/usr/local/cuda}" - # Include system and possible venv-provided CUDA libs - local pyver venv_cuda_paths="" - if [[ -x "$VENV_DIR/bin/python" ]]; then - pyver="$($VENV_DIR/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true)" - if [[ -n "$pyver" ]]; then - venv_cuda_paths="$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib" - fi - fi - export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}:${CUDA_HOME}/lib64:/usr/lib/x86_64-linux-gnu:/opt/cuda/lib64:/opt/cuda/targets/x86_64-linux/lib:${venv_cuda_paths}" - export PATH="${PATH}:${CUDA_HOME}/bin" - # shellcheck disable=SC1091 - source "$VENV_DIR/bin/activate" - python -c 'from faster_whisper import WhisperModel; WhisperModel("tiny", device="cuda", compute_type="float16"); print("[PY] CUDA test init succeeded.")' || { echo "CUDA environment check failed. Aborting as requested." >&2; exit 6; } - args+=("--device" "cuda") - fi + if [[ $has_nvidia -eq 1 ]]; then + ensure_cuda_runtime + # Export common CUDA paths in case the env lacks them + export CUDA_HOME="${CUDA_HOME:-/usr/local/cuda}" + # Include system and possible venv-provided CUDA libs + local pyver venv_cuda_paths="" + if [[ -x "$VENV_DIR/bin/python" ]]; then + pyver="$("$VENV_DIR"/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2> /dev/null || true)" + if [[ -n $pyver ]]; then + venv_cuda_paths="$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib" + fi + fi + export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}:${CUDA_HOME}/lib64:/usr/lib/x86_64-linux-gnu:/opt/cuda/lib64:/opt/cuda/targets/x86_64-linux/lib:${venv_cuda_paths}" + export PATH="${PATH}:${CUDA_HOME}/bin" + # shellcheck disable=SC1091 + source "$VENV_DIR/bin/activate" + python -c 'from faster_whisper import WhisperModel; WhisperModel("tiny", device="cuda", compute_type="float16"); print("[PY] CUDA test init succeeded.")' || { + echo "CUDA environment check failed. Aborting as requested." >&2 + exit 6 + } + args+=("--device" "cuda") + fi - log "Transcribing: $input" - # shellcheck disable=SC1091 - source "$VENV_DIR/bin/activate" - if [[ $has_nvidia -eq 1 ]]; then - if ! python "$PY_RUNNER" "${args[@]}"; then - echo "CUDA execution requested due to detected NVIDIA GPU, but it failed. Aborting as requested (no CPU fallback)." >&2 - exit 6 - fi - else - # Offline: prefer local directory if present; otherwise use cache without network - if [[ $OFFLINE -eq 1 ]]; then - local local_model_path="" - if [[ -d "$MODEL" ]]; then - local_model_path="$MODEL" - elif [[ -d "$MODEL_DIR/$MODEL" ]]; then - local_model_path="$MODEL_DIR/$MODEL" - fi - if [[ -n "$local_model_path" ]]; then - args=("$input" "--model" "$local_model_path") - [[ -n "$LANGUAGE" ]] && args+=("--language" "$LANGUAGE") - [[ -n "$OUTDIR" ]] && args+=("--outdir" "$OUTDIR") - fi - fi - python "$PY_RUNNER" "${args[@]}" - fi + log "Transcribing: $input" + # shellcheck disable=SC1091 + source "$VENV_DIR/bin/activate" + if [[ $has_nvidia -eq 1 ]]; then + if ! python "$PY_RUNNER" "${args[@]}"; then + echo "CUDA execution requested due to detected NVIDIA GPU, but it failed. Aborting as requested (no CPU fallback)." >&2 + exit 6 + fi + else + # Offline: prefer local directory if present; otherwise use cache without network + if [[ $OFFLINE -eq 1 ]]; then + local local_model_path="" + if [[ -d $MODEL ]]; then + local_model_path="$MODEL" + elif [[ -d "$MODEL_DIR/$MODEL" ]]; then + local_model_path="$MODEL_DIR/$MODEL" + fi + if [[ -n $local_model_path ]]; then + args=("$input" "--model" "$local_model_path") + [[ -n $LANGUAGE ]] && args+=("--language" "$LANGUAGE") + [[ -n $OUTDIR ]] && args+=("--outdir" "$OUTDIR") + fi + fi + python "$PY_RUNNER" "${args[@]}" + fi } main "$@" -