-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplex_probe_large.sh
More file actions
executable file
·108 lines (92 loc) · 3.61 KB
/
Copy pathplex_probe_large.sh
File metadata and controls
executable file
·108 lines (92 loc) · 3.61 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env bash
# plex_probe_large.sh — ffprobe the largest video files across the primary share.
# Reports codec, bitrate, resolution, and duration to identify bloated/inefficient encodes.
# Logs to ./logs/plex_probe_<timestamp>.log
#
# Usage: ./plex_probe_large.sh
# Env overrides: MOVIES_DIR, TVSHOWS_DIR, TOP_N, FFPROBE_BIN, LOG_DIR
#
# ffprobe only reads container headers over NFS — it does NOT download whole files.
set -euo pipefail
MOVIES_DIR="${MOVIES_DIR:-/mnt/media/movies/primary}"
TVSHOWS_DIR="${TVSHOWS_DIR:-/mnt/media/tvshows/primary}"
TOP_N="${TOP_N:-25}"
FFPROBE_BIN="${FFPROBE_BIN:-ffprobe}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
LOG_DIR="${LOG_DIR:-$SCRIPT_DIR/logs}"
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
LOG="$LOG_DIR/plex_probe_${TIMESTAMP}.log"
mkdir -p "$LOG_DIR"
exec > >(tee -a "$LOG") 2>&1
if ! command -v "$FFPROBE_BIN" &>/dev/null; then
echo "ERROR: ffprobe not found (FFPROBE_BIN=$FFPROBE_BIN)"
exit 1
fi
echo "========================================"
echo " Plex Large File Probe"
echo " $(date)"
echo " Top $TOP_N largest video files"
echo "========================================"
echo
# Build list of directories to search
search_dirs=()
[[ -d "$MOVIES_DIR" ]] && search_dirs+=("$MOVIES_DIR")
[[ -d "$TVSHOWS_DIR" ]] && search_dirs+=("$TVSHOWS_DIR")
[[ ${#search_dirs[@]} -eq 0 ]] && { echo "ERROR: No mounts accessible."; exit 1; }
echo "Finding largest video files..."
mapfile -t large_files < <(
find "${search_dirs[@]}" \
-type f \
\( -iname '*.mkv' -o -iname '*.mp4' -o -iname '*.avi' -o -iname '*.m4v' -o -iname '*.mov' \) \
-printf '%s\t%p\n' 2>/dev/null \
| sort -rn \
| head -n "$TOP_N" \
| cut -f2-
)
echo "Probing ${#large_files[@]} files (this may take a moment over NFS)..."
echo
# Header
printf '%-9s %-6s %7s %7s %-9s %s\n' \
"Size" "Codec" "Kbps" "Dur" "Res" "File"
printf '%0.s-' {1..115}
echo
for file in "${large_files[@]}"; do
size_h=$(du -sh "$file" 2>/dev/null | cut -f1 || echo "?")
# ffprobe: video stream info + format-level bitrate/duration
probe=$("$FFPROBE_BIN" -v quiet \
-select_streams v:0 \
-show_entries "stream=codec_name,width,height:format=bit_rate,duration" \
-of default=noprint_wrappers=1 \
"$file" 2>/dev/null || true)
vcodec=$(echo "$probe" | grep '^codec_name=' | head -1 | cut -d= -f2- || echo "?")
width=$(echo "$probe" | grep '^width=' | head -1 | cut -d= -f2- || echo "?")
height=$(echo "$probe" | grep '^height=' | head -1 | cut -d= -f2- || echo "?")
bitrate=$(echo "$probe" | grep '^bit_rate=' | head -1 | cut -d= -f2- || echo "")
duration=$(echo "$probe"| grep '^duration=' | head -1 | cut -d= -f2- || echo "")
# Format bitrate as Kbps
if [[ "$bitrate" =~ ^[0-9]+$ ]]; then
kbps=$(( bitrate / 1000 ))
else
kbps="N/A"
fi
# Format duration as H:MM
if [[ "$duration" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
dur_int=${duration%%.*}
dur_h=$(( dur_int / 3600 ))
dur_m=$(( (dur_int % 3600) / 60 ))
dur_fmt="${dur_h}:$(printf '%02d' "$dur_m")"
else
dur_fmt="?"
fi
res="${width}x${height}"
[[ "$width" == "?" || "$height" == "?" ]] && res="?"
printf '%-9s %-6s %7s %7s %-9s %s\n' \
"$size_h" "${vcodec:-?}" "$kbps" "$dur_fmt" "$res" "$(basename "$file")"
done
echo
echo "Inefficient codecs to watch for: xvid, divx, mpeg4, mpeg2"
echo "High bitrate = large file for its runtime. Low bitrate may indicate SD source."
echo
echo "========================================"
echo " Done. Log: $LOG"
echo "========================================"