···1+#!/bin/bash
2+#
3+# Validates all .ts files in the current directory have a video stream.
4+# Run this before streaming to catch bad encodes.
5+6+bad=0
7+8+for f in *.ts; do
9+ [[ -f "$f" ]] || continue
10+11+ if ! ffprobe -v error -select_streams v:0 \
12+ -show_entries stream=codec_type -of csv=p=0 "$f" 2>/dev/null \
13+ | grep -q video; then
14+ echo "INVALID: $f" >&2
15+ bad=$((bad + 1))
16+ fi
17+done
18+19+if [[ $bad -gt 0 ]]; then
20+ echo "$bad invalid file(s) found" >&2
21+ exit 1
22+fi
23+24+echo "All files valid"
+34-16
stream.sh
···4[[ -z "$STREAM_KEY" ]] && echo "STREAM_KEY is required" >&2 && exit 1
56HISTORY_SIZE=5
7-declare -a history=()
0000000089-CURRENT_VIDEO_TRACKER=$(mktemp)
10-trap 'echo "Last playing: $(cat "$CURRENT_VIDEO_TRACKER")" >&2; rm -f "$CURRENT_VIDEO_TRACKER"' EXIT
1112-pick_video() {
13- local all_videos=(*.ts)
14 local available=()
15-16- # Filter out recently played videos
17 for v in "${all_videos[@]}"; do
18 local in_history=0
19 for h in "${history[@]}"; do
···22 [[ $in_history -eq 0 ]] && available+=("$v")
23 done
2425- # If fewer videos than history size, use all
26 [[ ${#available[@]} -eq 0 ]] && available=("${all_videos[@]}")
2728- # Pick random from available
29 echo "${available[$((RANDOM % ${#available[@]}))]}"
30}
31032while true; do
33- video=$(pick_video)
03435- # Update history (add new, keep last HISTORY_SIZE)
36- history+=("$video")
37- (( ${#history[@]} > HISTORY_SIZE )) && history=("${history[@]:1}")
0000000000003839- echo "$video" > "$CURRENT_VIDEO_TRACKER"
40- cat "$video"
41-done | ffmpeg -loglevel error -re -fflags +genpts -i pipe:0 -c copy -f flv "$RTMP_URL/$STREAM_KEY"
000
···4[[ -z "$STREAM_KEY" ]] && echo "STREAM_KEY is required" >&2 && exit 1
56HISTORY_SIZE=5
7+RETRY_DELAY=1
8+MAX_RETRY_DELAY=30
9+10+pick_video() {
11+ local all_videos=()
12+ for f in *.ts; do
13+ [[ -f "$f" ]] || continue
14+ all_videos+=("$f")
15+ done
1617+ [[ ${#all_videos[@]} -eq 0 ]] && return 1
0180019 local available=()
0020 for v in "${all_videos[@]}"; do
21 local in_history=0
22 for h in "${history[@]}"; do
···25 [[ $in_history -eq 0 ]] && available+=("$v")
26 done
27028 [[ ${#available[@]} -eq 0 ]] && available=("${all_videos[@]}")
29030 echo "${available[$((RANDOM % ${#available[@]}))]}"
31}
3233+# Outer loop: reconnect on disconnect
34while true; do
35+ echo "Connecting to $RTMP_URL..." >&2
36+ declare -a history=()
3738+ # Inner loop: pick and stream videos, piped into ffmpeg
39+ while true; do
40+ video=$(pick_video)
41+ if [[ -z "$video" ]]; then
42+ echo "No .ts files found, waiting..." >&2
43+ sleep 5
44+ continue
45+ fi
46+47+ history+=("$video")
48+ (( ${#history[@]} > HISTORY_SIZE )) && history=("${history[@]:1}")
49+50+ echo "Playing: $video" >&2
51+ cat "$video"
52+ done | ffmpeg -loglevel error -re -fflags +genpts -i pipe:0 -c copy -f flv "$RTMP_URL/$STREAM_KEY"
5354+ echo "Stream disconnected, reconnecting in ${RETRY_DELAY}s..." >&2
55+ sleep "$RETRY_DELAY"
56+57+ RETRY_DELAY=$(( RETRY_DELAY * 2 ))
58+ (( RETRY_DELAY > MAX_RETRY_DELAY )) && RETRY_DELAY=$MAX_RETRY_DELAY
59+done