Ctrl K
ComunidadGuías…

consolidate-watch.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/bash
# inotify watcher (close_write / moved_to): runs the pipeline on new videos, and on the sibling
# video when a sidecar .srt/.ass/.vtt arrives.
set -u
_here="$(cd "$(dirname "$0")" && pwd)"
PATH="$_here/.venv/bin:$PATH"  # the stack runs from the repo venv
# shellcheck source=lib/paths.sh
. "$_here/lib/paths.sh"

ROOT="$MEDIA_ROOT"
SCRIPT="$MEDIA_STACK_ROOT/consolidate-subs.py"
LOG="$VAR_LOG/consolidate-watch.log"
COOLDOWN=15
STATE_DEBOUNCE_DIR="$VAR_RUN/consolidate-watch-debounce"
mkdir -p "$STATE_DEBOUNCE_DIR"

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG"; }

trigger() {
    local video="$1" reason="$2"
    [ -f "$video" ] || return 0
    local key
    key=$(echo -n "$video" | md5sum | awk '{print $1}')
    local debfile="$STATE_DEBOUNCE_DIR/$key"
    if [ -f "$debfile" ]; then
        local age=$(( $(date +%s) - $(stat -c %Y "$debfile" 2>/dev/null || echo 0) ))
        [ "$age" -lt 60 ] && return 0
    fi
    touch "$debfile"
    (
        sleep "$COOLDOWN"
        [ -f "$video" ] || exit 0
        local s1 s2
        s1=$(stat -c %s "$video" 2>/dev/null || echo 0)
        sleep 5
        s2=$(stat -c %s "$video" 2>/dev/null || echo 0)
        [ "$s1" != "$s2" ] && { log "still writing, skip: $video"; exit 0; }
        local out
        out=$(python3 "$SCRIPT" "$video" 2>&1 | tail -1)
        log "[$reason] $out"
    ) &
}

log "watcher start: ROOT=$ROOT"

# --exclude keeps the watcher out of $ROOT/.dupe-recycle/ (re-normalizing files about to be
# purged cascades); the case-guard below is belt-and-suspenders.
inotifywait -m -r -e close_write,moved_to --exclude '/\.dupe-recycle(/|$)' \
    --format '%w%f|%e' "$ROOT" 2>>"$LOG" |
while IFS='|' read -r path event; do
    case "$path" in
        *.consol.*.tmp.mkv|*.tmp.mkv|*.partial|*.consolidate-subs.state.*) continue ;;
        */.dupe-recycle/*) continue ;;
        */.normalize-tmp/*) continue ;;
    esac
    case "${path,,}" in
        *.mkv|*.mp4)
            log "video event: $path ($event)"
            trigger "$path" "video-import"
            ;;
        *.srt|*.ass|*.ssa|*.vtt)
            dir=$(dirname "$path")
            base=$(basename "$path")
            # "Show.S01E01.en.cc.srt" -> "Show.S01E01": peel up to 3 trailing lang/forced/sdh/
            # generated/dub tags ("generated" = sub-fallback.py's Whisper sidecar, "dub" = the
            # subtitle for the English dub audio). A video named exactly like the stem at a step
            # wins and stops the peeling ("The.Generated.mkv" is never cut). A video takes the
            # sidecar only under media_stack.subtitles's rule (find_sidecar_subs and
            # find_dub_sidecars): no tags left after its stem, or an English one (has_en: any tag
            # starting with "en") among them.
            stem="${base%.*}"
            found=""
            has_en=0
            for step in 0 1 2 3; do
                if [ "$step" -eq 0 ] || [ "$has_en" -eq 1 ]; then
                    for ext in mkv mp4; do
                        if [ -f "$dir/$stem.$ext" ]; then
                            found="$dir/$stem.$ext"
                            break 2
                        fi
                    done
                fi
                [ "$step" -eq 3 ] && break
                last="${stem##*.}"
                ll="${last,,}"
                if [[ "$ll" == en* || "$ll" =~ ^(cc|sdh|forced|hi|generated|dub)$ ]]; then
                    if [[ "$ll" == en* ]]; then
                        has_en=1
                    fi
                    stem="${stem%.*}"
                else
                    break
                fi
            done
            if [ -n "$found" ]; then
                log "sidecar event: $path → $found ($event)"
                trigger "$found" "sidecar-arrival"
            fi
            ;;
    esac
done