Added all
This commit is contained in:
240
batch-renderer.sh
Executable file
240
batch-renderer.sh
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# batch-renderer.sh
|
||||
# Batch manga text rendering using cleaned images and output.txt
|
||||
#
|
||||
# Usage:
|
||||
# ./batch-renderer.sh <folder>
|
||||
# ./batch-renderer.sh <folder> --start 3 --end 7
|
||||
#
|
||||
# Output per page lands in:
|
||||
# <folder>/translated/<page_stem>/
|
||||
# └── <page_stem>_translated.png
|
||||
# ============================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# CONFIGURATION
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
START_PAGE=1
|
||||
END_PAGE=999999
|
||||
PYTHON_BIN="python"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
RENDERER="${SCRIPT_DIR}/manga-renderer.py"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# COLOURS
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
RESET='\033[0m'
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# HELPERS
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
usage() {
|
||||
echo ""
|
||||
echo -e "${BOLD}Usage:${RESET}"
|
||||
echo " $0 <folder> [options]"
|
||||
echo ""
|
||||
echo -e "${BOLD}Options:${RESET}"
|
||||
echo " --start First page number (default: 1)"
|
||||
echo " --end Last page number (default: all)"
|
||||
echo " --python Python binary (default: python)"
|
||||
echo " --help, -h Show this help"
|
||||
echo ""
|
||||
echo -e "${BOLD}Examples:${RESET}"
|
||||
echo " $0 pages-for-tests"
|
||||
echo " $0 pages-for-tests --start 3 --end 7"
|
||||
echo ""
|
||||
}
|
||||
|
||||
log_info() { echo -e "${CYAN}ℹ️ $*${RESET}"; }
|
||||
log_ok() { echo -e "${GREEN}✅ $*${RESET}"; }
|
||||
log_warn() { echo -e "${YELLOW}⚠️ $*${RESET}"; }
|
||||
log_error() { echo -e "${RED}❌ $*${RESET}"; }
|
||||
log_section() {
|
||||
echo -e "\n${BOLD}${CYAN}══════════════════════════════════════════${RESET}"
|
||||
echo -e "${BOLD}${CYAN} 🔤 $*${RESET}"
|
||||
echo -e "${BOLD}${CYAN}══════════════════════════════════════════${RESET}"
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# ARGUMENT PARSING
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
if [[ $# -eq 0 ]]; then
|
||||
log_error "No folder specified."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FOLDER="$1"
|
||||
shift
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--start) START_PAGE="$2"; shift 2 ;;
|
||||
--end) END_PAGE="$2"; shift 2 ;;
|
||||
--python) PYTHON_BIN="$2"; shift 2 ;;
|
||||
--help|-h) usage; exit 0 ;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# VALIDATION
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
if [[ ! -d "$FOLDER" ]]; then
|
||||
log_error "Folder not found: $FOLDER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$RENDERER" ]]; then
|
||||
log_error "manga-renderer.py not found at: $RENDERER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v "$PYTHON_BIN" &>/dev/null; then
|
||||
log_error "Python binary not found: $PYTHON_BIN"
|
||||
log_error "Try --python python3"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# DISCOVER IMAGES
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
ALL_IMAGES=()
|
||||
while IFS= read -r -d '' img; do
|
||||
ALL_IMAGES+=("$img")
|
||||
done < <(
|
||||
find "$FOLDER" -maxdepth 1 -type f \
|
||||
\( -iname "*.jpg" -o -iname "*.jpeg" \
|
||||
-o -iname "*.png" -o -iname "*.webp" \) \
|
||||
-print0 | sort -z
|
||||
)
|
||||
|
||||
TOTAL=${#ALL_IMAGES[@]}
|
||||
|
||||
if [[ $TOTAL -eq 0 ]]; then
|
||||
log_error "No image files found in: $FOLDER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# SLICE TO REQUESTED PAGE RANGE
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
PAGES=()
|
||||
for i in "${!ALL_IMAGES[@]}"; do
|
||||
PAGE_NUM=$(( i + 1 ))
|
||||
if [[ $PAGE_NUM -ge $START_PAGE && $PAGE_NUM -le $END_PAGE ]]; then
|
||||
PAGES+=("${ALL_IMAGES[$i]}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#PAGES[@]} -eq 0 ]]; then
|
||||
log_error "No pages in range [${START_PAGE}, ${END_PAGE}] (total: ${TOTAL})"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# SUMMARY HEADER
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
log_section "BATCH MANGA RENDERER"
|
||||
log_info "📂 Folder : $(realpath "$FOLDER")"
|
||||
log_info "📄 Pages : ${#PAGES[@]} of ${TOTAL} total"
|
||||
log_info "🔢 Range : ${START_PAGE} → ${END_PAGE}"
|
||||
echo ""
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# PROCESS EACH PAGE
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
PASS=0
|
||||
FAIL=0
|
||||
FAIL_LIST=()
|
||||
|
||||
for i in "${!PAGES[@]}"; do
|
||||
IMAGE="${PAGES[$i]}"
|
||||
PAGE_NUM=$(( START_PAGE + i ))
|
||||
STEM="$(basename "${IMAGE%.*}")"
|
||||
WORKDIR="${FOLDER}/translated/${STEM}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}──────────────────────────────────────────${RESET}"
|
||||
echo -e "${BOLD} 🖼️ [${PAGE_NUM}/${TOTAL}] ${STEM}${RESET}"
|
||||
echo -e "${BOLD}──────────────────────────────────────────${RESET}"
|
||||
|
||||
INPUT_CLEANED="${WORKDIR}/${STEM}_cleaned.png"
|
||||
INPUT_JSON="${WORKDIR}/bubbles.json"
|
||||
INPUT_TXT="${WORKDIR}/output.txt"
|
||||
OUTPUT_RENDERED="${WORKDIR}/${STEM}_translated.png"
|
||||
|
||||
# Check for required files
|
||||
MISSING_FILES=0
|
||||
for REQ_FILE in "$INPUT_CLEANED" "$INPUT_JSON" "$INPUT_TXT"; do
|
||||
if [[ ! -f "$REQ_FILE" ]]; then
|
||||
log_warn "Missing required file: $(basename "$REQ_FILE")"
|
||||
MISSING_FILES=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $MISSING_FILES -eq 1 ]]; then
|
||||
log_error "Skipping ${STEM} due to missing files. Did you run batch-clean.sh?"
|
||||
FAIL=$(( FAIL + 1 ))
|
||||
FAIL_LIST+=("${STEM} (Missing Files)")
|
||||
continue
|
||||
fi
|
||||
|
||||
log_info "🗂️ Cleaned Image : $(basename "$INPUT_CLEANED")"
|
||||
log_info "🔤 Rendering translated text..."
|
||||
|
||||
# ── Run the renderer ──────────────────────────────────────
|
||||
if "$PYTHON_BIN" "$RENDERER" \
|
||||
-i "$INPUT_CLEANED" \
|
||||
-j "$INPUT_JSON" \
|
||||
-t "$INPUT_TXT" \
|
||||
-o "$OUTPUT_RENDERED"; then
|
||||
|
||||
if [[ -f "$OUTPUT_RENDERED" ]]; then
|
||||
log_ok "Translated image saved → ${STEM}_translated.png"
|
||||
PASS=$(( PASS + 1 ))
|
||||
else
|
||||
log_error "Script ran but output image is missing."
|
||||
FAIL=$(( FAIL + 1 ))
|
||||
FAIL_LIST+=("${STEM} (Missing Output)")
|
||||
fi
|
||||
else
|
||||
log_error "Page ${PAGE_NUM} FAILED — check output above."
|
||||
FAIL=$(( FAIL + 1 ))
|
||||
FAIL_LIST+=("${STEM} (Script Error)")
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# FINAL SUMMARY
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
log_section "BATCH RENDERING COMPLETE"
|
||||
echo -e " ✅ ${GREEN}Passed : ${PASS}${RESET}"
|
||||
echo -e " ❌ ${RED}Failed : ${FAIL}${RESET}"
|
||||
|
||||
if [[ ${#FAIL_LIST[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
log_warn "Failed pages:"
|
||||
for NAME in "${FAIL_LIST[@]}"; do
|
||||
echo -e " ❌ ${RED}${NAME}${RESET}"
|
||||
done
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "📦 Output folder: $(realpath "${FOLDER}/translated")"
|
||||
echo ""
|
||||
|
||||
[[ $FAIL -eq 0 ]] && exit 0 || exit 1
|
||||
Reference in New Issue
Block a user