Files
Linux_post_install/bin/pos-media-mp4
T
he 5ef38dc46f fix: resolve all 23 MAINTENANCE audit tickets
- deps guards before -h|--help in docker-health/ps, network-scan,
  usb-server, media-mp3/mp4 (--dry-run pre-scan kept); system-firewall
  gains usage()/--help; autostart/usb-automount get flags.sh + template
- install.sh: normalize N-M range syntax in --steps
- bin/pos: INTERACTIVE_CMDS += docker-compose docker-vbox network-hotspot
- common.sh: canonical XDG-aware CONFIG_DIR + DIM color var; notify.sh
  stderr fallback; ent_plugin_* registry renames (runtime plugin API kept)
- docker-compose SCALE_DIR/CONFIG_ENV env seams; ffmpeg in PACKAGES;
  scrcpy.sh exec bit
- docs: health is console-only (--send/--markdown removed), POS.md file
  refs for config/tree/entertainment, DEV.md no-guard exception, docmap/
  filetable regenerated (make gen), hand-maintained line rows bumped
- add scripts/lint-conventions.sh gate + Makefile lint target; record
  all VERIFIED outcomes in MAINTENANCE.md; AGENT_TODO Done entry
  (2026-08-14)
- gates: make gen/check/lint all green (0 FAIL, 0 WARN); bash -n sweep
  clean; restricted-PATH dep tests + step-matrix dry-runs verified
2026-08-14 12:57:00 -04:00

133 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# POS: media mp4 — Download video as MP4 (smart/interactive format select)
# POS_FLAGS: --format --best --worst --output --no-playlist --cookies --dry-run
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
# --dry-run is parsed before the deps guards (below): it previews the yt-dlp
# command without requiring yt-dlp/ffmpeg to be installed.
DRY_RUN=0
for arg in "$@"; do
[ "$arg" = "--dry-run" ] && DRY_RUN=1
done
# Deps guards sit before -h|--help (help also errors on a box missing the deps).
if [ "$DRY_RUN" -eq 0 ]; then
command -v yt-dlp &>/dev/null || err "yt-dlp not found — install it with: sudo apt install yt-dlp"
command -v ffmpeg &>/dev/null || err "ffmpeg not found (needed for MP4 merge) — install it with: sudo apt install ffmpeg"
fi
OUT_DIR="$HOME/Videos"
FORMAT=""
BEST=0
WORST=0
EXTRA_ARGS=()
usage() {
cat <<EOF
Usage: pos media mp4 [options] <url>
Download video from a URL via yt-dlp. Without -f/--best/--worst, formats are
listed and picked interactively.
Options:
-f, --format <id> Download that format id directly (no prompt)
--best Best video + audio (no prompt)
--worst Lowest quality (no prompt)
-o, --output <dir> Output directory (default: $OUT_DIR)
--no-playlist Download only the single video
--cookies <file> Netscape cookies.txt for age-gated content
--dry-run Print the yt-dlp command without running it
-h, --help This help
Examples:
pos media mp4 https://youtube.com/watch?v=dQw4w9WgXcQ
pos media mp4 --best https://youtube.com/watch?v=dQw4w9WgXcQ
pos media mp4 -f 22 https://youtube.com/watch?v=dQw4w9WgXcQ
EOF
exit 0
}
URL=""
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help) usage ;;
-f|--format)
[ $# -ge 2 ] || err "--format needs a value"
FORMAT="$2"; shift 2 ;;
--best) BEST=1; shift ;;
--worst) WORST=1; shift ;;
-o|--output)
[ $# -ge 2 ] || err "--output needs a value"
OUT_DIR="$2"; shift 2 ;;
--no-playlist) EXTRA_ARGS+=(--no-playlist); shift ;;
--cookies)
[ $# -ge 2 ] || err "--cookies needs a value"
[ -f "$2" ] || err "cookies file not found: $2"
EXTRA_ARGS+=(--cookies "$2"); shift 2 ;;
--dry-run) DRY_RUN=1; shift ;;
-*) err "Unknown option: $1 (see --help)" ;;
*)
[ -z "$URL" ] && URL="$1" && shift || err "Unexpected argument: $1" ;;
esac
done
[ -n "$URL" ] || usage
[ -n "$FORMAT" ] && { [ "$BEST" -eq 1 ] || [ "$WORST" -eq 1 ]; } \
&& err "--format and --best/--worst are mutually exclusive"
[ "$BEST" -eq 1 ] && [ "$WORST" -eq 1 ] && err "--best and --worst are mutually exclusive"
# Resolve the format selector: explicit flag → smart preset → interactive.
# The curated table goes to stderr; stdout carries ONLY the chosen format id
# (same ui_pick lesson — a $(...) capture must not swallow the menu).
fmt_spec=""
if [ -n "$FORMAT" ]; then
fmt_spec="$FORMAT"
elif [ "$BEST" -eq 1 ]; then
fmt_spec="bestvideo*+bestaudio/best"
elif [ "$WORST" -eq 1 ]; then
fmt_spec="worst"
else
table="$(yt-dlp -F "$URL" 2>&1)" || {
echo "ERROR: no formats listed (unsupported site or age-gated content)" >&2
exit 1
}
printf '%s' "$table" | awk -F'[[:space:]][[:space:]]+' '
NR <= 2 { print; next }
$0 ~ /^-+$/ { print; next }
$0 ~ /audio only/ && $0 !~ /storyboard/ && $1 !~ /^sb/ { print " [audio] " $0; next }
$0 ~ /video only/ && $1 !~ /^sb/ { print " [video] " $0; next }
$1 ~ /^[0-9]+$/ && $2 ~ /^(mp4|webm)$/ && $3 ~ /x/ { print " [combo] " $0 }
' >&2
echo >&2
read -rp "Format ID ('best'/'worst'/empty = best): " chosen
case "${chosen:-best}" in
best) fmt_spec="bestvideo*+bestaudio/best" ;;
worst) fmt_spec="worst" ;;
*)
if printf '%s' "$table" | grep -qE "^[[:space:]]*${chosen}[[:space:]]"; then
fmt_spec="$chosen"
else
echo "ERROR: unknown format id '$chosen'" >&2
exit 1
fi
;;
esac
fi
args=(yt-dlp -f "$fmt_spec"
--merge-output-format mp4
--embed-metadata --embed-chapters
--embed-subs --sub-langs all
--embed-thumbnail
--no-overwrites
-o "$OUT_DIR/%(title)s.%(ext)s"
"${EXTRA_ARGS[@]}" "$URL")
if [ "$DRY_RUN" -eq 1 ]; then
echo "yt-dlp ${args[*]:1}"
else
spawn "downloading video → $OUT_DIR" "${args[@]}"
fi