#!/usr/bin/sh
set -eu

CONFIG=${YA_CONFIG:-/etc/yabo/config}
# shellcheck source=/dev/null
. "$CONFIG"
LIB=${YA_LIB:-/usr/share/yabo/lib.sh}
# shellcheck source=/dev/null
. "$LIB"

REC="$YA_ROOT/subscriptions.rec"
GEN=${YA_GEN:-/usr/share/yabo/gen.php}
SWEEP=${YA_SWEEP:-/usr/libexec/yabo/yabo-sweep}

# This-run attempt set: a failing row stays Downloaded='' / Attempts<MAX, so
# without it the drain loop would re-pick it and burn every retry in one run.
TRIED=$(mktemp)
# Progress marker for the drain loop, kept off stdout so yt-dlp's own output
# reaches the journal instead of being swallowed by a command substitution.
PROGRESS=$(mktemp)
trap 'rm -f "$TRIED" "$PROGRESS"' EXIT

# 00-07 -> looser night rate, else the tighter day rate. date +%H is
# zero-padded; test's -lt reads it as decimal (unlike $(( )), where 08/09 are
# invalid octal), so compare with [ ] directly.
rate_by_hour() {
  h=$(date +%H)
  if [ "$h" -lt 8 ]; then
    printf '%s' "$YA_RATE_NIGHT"
  else
    printf '%s' "$YA_RATE_DAY"
  fi
}

download_one() {
  dir=$1; id=$2
  cr="$dir/Channel.rec"
  url="https://www.youtube.com/watch?v=$id"
  rate=$(rate_by_hour)

  set -- \
    -S "$YA_FORMAT_SORT" \
    --js-runtimes node \
    --limit-rate "$rate" \
    --write-info-json --write-thumbnail --convert-thumbnails jpg \
    --cache-dir "$YA_CACHE_DIR" \
    -o "$dir/%(title)s [%(id)s].%(ext)s" \
    --download-archive "$dir/.ytdlp-archive"
  # Prepend --cookies only when the file is present (dormant fallback).
  [ -f "$YA_COOKIES" ] && set -- --cookies "$YA_COOKIES" "$@"

  # One video per call, so yt-dlp's exit code IS this video's outcome.
  if yt-dlp "$@" "$url"; then
    ( flock 9
      recset -t Video -e "Id = '$id'" -f Downloaded \
        -S "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$cr"
    ) 9>"$dir/.channel.lock"
    # gen.php feed regenerates every stale .nfo in the dir (mtime-guarded),
    # this fresh one included, so no separate per-id nfo pass is needed.
    php "$GEN" feed "$dir" "$YA_BASE_URL" || echo "warn: feed regen failed for $dir" >&2
  else
    ( flock 9
      cur=$(recsel -t Video -C -e "Id = '$id'" -P Attempts "$cr")
      recset -t Video -e "Id = '$id'" -f Attempts -S "$(( ${cur:-0} + 1 ))" "$cr"
    ) 9>"$dir/.channel.lock"
  fi
}

# First in-window, not-yet-tried ready video of a channel (empty if none).
# Pre-window rows stay untouched so they can't block the channel or spin the
# loop; empty Published counts as in-window (only the future /videos reconcile
# yields date-less rows).
pick_ready() {
  cr=$1; dir=$2; flag=$3
  ( flock 9
    recsel -t Video -C \
      -e "Downloaded = '' && Attempts < $YA_MAX_ATTEMPTS" -P Id "$cr" \
    | while IFS= read -r id; do
        grep -qxF "$id" "$TRIED" && continue
        published=$(recsel -t Video -C -e "Id = '$id'" -P Published "$cr")
        # Skip only a parseable date strictly before the window; empty or
        # unparseable Published counts as in-window (guards against an
        # integer-compare error on non-date text bypassing the gate).
        pub=$(ymd "$published")
        case $pub in
          [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])
            [ "$pub" -lt "$flag" ] && continue ;;
        esac
        printf '%s\n' "$id"
        break
      done
  ) 9>"$dir/.channel.lock"
}

# Download one in-window video from each subscribed channel, emitting a mark per
# download so the loop can tell the pass made progress. Window start = each
# channel's own Added day (today if unset), so a new sub never floods on backlog.
drain_pass() {
  recsel -t Subscription -C -e "#Enabled = 0 || Enabled = 'yes'" -P Url "$REC" \
  | while IFS= read -r url; do
      [ -n "$url" ] || continue
      dir="$YA_ROOT/$(sanitize "$url")"
      cr="$dir/Channel.rec"
      [ -e "$cr" ] || continue
      added=$(recsel -t Subscription -C -e "Url = '$url'" -P Added "$REC")
      flag=$(ymd "$added")
      # A missing/malformed Added defaults to today: never backfill, and keep
      # flag a valid YYYYMMDD for the compare in pick_ready.
      case $flag in
        [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) ;;
        *) flag=$(date +%Y%m%d) ;;
      esac
      id=$(pick_ready "$cr" "$dir" "$flag")
      [ -n "$id" ] || continue
      printf '%s\n' "$id" >> "$TRIED"
      download_one "$dir" "$id"
      printf 'x' >> "$PROGRESS"
    done
}

# Re-read the ledgers each pass so videos detection adds mid-run are picked up;
# stop when a pass downloads nothing. Progress goes to a file, not stdout, so
# yt-dlp/gen output reaches the journal instead of being captured and discarded.
while :; do
  : > "$PROGRESS"
  drain_pass
  [ -s "$PROGRESS" ] || break
done

php "$GEN" opml "$YA_ROOT" "$YA_BASE_URL"
"$SWEEP"
