1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env bash
#
# Download every file listed in download.txt (Google Drive links)
# into ./pdfs/, preserving the "Book Name" filenames.
#
# Usage:
#   ./download_all.sh [download.txt] [dest_dir]
#   ./download_all.sh --force          # re-download even if the file exists
#
set -euo pipefail

SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIST="$SRC_DIR/download.txt"
DEST="$SRC_DIR/pdfs"
FORCE=0
for arg in "$@"; do
  case "$arg" in
    --force) FORCE=1 ;;
    *) if [[ -f "$arg" ]]; then LIST="$arg"; else DEST="$arg"; fi ;;
  esac
done

mkdir -p "$DEST"

command -v curl >/dev/null 2>&1 || { echo "ERROR: curl is required." >&2; exit 1; }

# Download one Google Drive file by its file ID.
dl_drive_file() {
  local id="$1" out="$2"
  local cookies tmp
  cookies="$(mktemp)"
  tmp="${out}.part"
  rm -f "$tmp"

  if command -v gdown >/dev/null 2>&1; then
    gdown --id "$id" -O "$tmp"
  else
    # First attempt (works directly for small files).
    curl -sSL -c "$cookies" "https://drive.google.com/uc?export=download&id=${id}" -o "$tmp"
    # Large files return a virus-scan interstitial HTML page instead of the
    # file; re-request by submitting its download form (action on
    # drive.usercontent.google.com with id/export/confirm/uuid fields).
    if head -c 2048 "$tmp" 2>/dev/null | grep -qi 'html'; then
      local action query
      action="$(grep -o '<form[^>]*action="[^"]*"' "$tmp" | head -n1 | sed 's/.*action="//;s/"//')"
      query="$(grep -o 'name="[a-zA-Z]*" value="[^"]*"' "$tmp" | sed 's/name="//;s/" value="/=/;s/"//' | paste -sd'&' -)"
      if [[ -n "${action:-}" && -n "${query:-}" ]]; then
        curl -sSL -b "$cookies" "${action}?${query}" -o "$tmp"
      fi
    fi
  fi
  rm -f "$cookies"

  # Sanity check: refuse to silently keep an HTML error page as the "pdf".
  mv -f "$tmp" "$out"
  # Sanity check: refuse to silently keep an HTML error page as the "pdf".
  if head -c 2048 "$out" 2>/dev/null | grep -qi '<html'; then
    echo "  WARNING: got an HTML page instead of the file (link may need access). Saved for inspection: $out" >&2
    return 1
  fi
}

declare -A SEEN=()
total="$(($(wc -l < "$LIST") - 1))"
i=0
while IFS=$'\t' read -r name link || [[ -n "${name:-}" ]]; do
  i=$((i + 1))
  [[ -z "${name:-}" || -z "${link:-}" ]] && continue
  id="$(printf '%s' "$link" | sed -n 's#.*/file/d/\([^/?]*\).*#\1#p')"
  if [[ -z "$id" ]]; then echo "[$i/$total] SKIP (no file id): $name" >&2; continue; fi

  # De-duplicate display names: the list contains e.g. two different
  # "Rgveda darshana vol 11.pdf" links -> second becomes "vol 11 (2).pdf".
  target="$name"
  count="${SEEN["$name"]:-0}"
  SEEN["$name"]=$((count + 1))
  if ((count > 0)); then
    if [[ "$name" == *.* ]]; then
      target="${name%.*} ($((count + 1))).${name##*.}"
    else
      target="$name ($((count + 1)))"
    fi
  fi

  out="$DEST/$target"
  if [[ -e "$out" && $FORCE -eq 0 ]]; then
    echo "[$i/$total] SKIP (exists): $target"
    continue
  fi

  echo "[$i/$total] Downloading: $target"
  dl_drive_file "$id" "$out" || true
done < <(tail -n +2 "$LIST")

echo "Done. Files are in: $DEST"