Upload play-stream.sh
Browse files- play-stream.sh +155 -0
play-stream.sh
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Stream playback helper — takes BEX stream JSON output and plays with mpv/ffplay
|
| 3 |
+
#
|
| 4 |
+
# Usage:
|
| 5 |
+
# ./play-stream.sh <stream_json>
|
| 6 |
+
# echo '{"manifest_url":"...", "headers":[...]}' | ./play-stream.sh
|
| 7 |
+
# ./play-stream.sh --from-file stream_output.json
|
| 8 |
+
#
|
| 9 |
+
# Supports:
|
| 10 |
+
# - HLS (.m3u8) streams
|
| 11 |
+
# - Direct MP4/MKV URLs
|
| 12 |
+
# - Custom headers (Referer, User-Agent, etc.)
|
| 13 |
+
# - mpv (preferred) or ffplay (fallback)
|
| 14 |
+
#
|
| 15 |
+
# The script extracts the stream URL and headers from the BEX engine's
|
| 16 |
+
# resolve-stream JSON output and constructs the correct player command.
|
| 17 |
+
|
| 18 |
+
set -euo pipefail
|
| 19 |
+
|
| 20 |
+
# Read JSON from stdin, argument, or file
|
| 21 |
+
if [ "${1:-}" = "--from-file" ] && [ -f "${2:-}" ]; then
|
| 22 |
+
JSON=$(cat "$2")
|
| 23 |
+
elif [ -n "${1:-}" ] && [ "${1:-}" != "-" ]; then
|
| 24 |
+
JSON="$1"
|
| 25 |
+
else
|
| 26 |
+
JSON=$(cat)
|
| 27 |
+
fi
|
| 28 |
+
|
| 29 |
+
if [ -z "$JSON" ]; then
|
| 30 |
+
echo "Error: No stream JSON provided"
|
| 31 |
+
echo "Usage: ./play-stream.sh '<json>' or pipe JSON to stdin"
|
| 32 |
+
exit 1
|
| 33 |
+
fi
|
| 34 |
+
|
| 35 |
+
# Parse JSON with jq (or python fallback)
|
| 36 |
+
if command -v jq &>/dev/null; then
|
| 37 |
+
STREAM_URL=$(echo "$JSON" | jq -r '.manifest_url // .videos[0].url // empty')
|
| 38 |
+
# Extract headers as key: value pairs
|
| 39 |
+
HEADERS=$(echo "$JSON" | jq -r '.headers[]? | "\(.key): \(.value)"')
|
| 40 |
+
FORMAT=$(echo "$JSON" | jq -r '.format // "hls"')
|
| 41 |
+
LABEL=$(echo "$JSON" | jq -r '.label // "Stream"')
|
| 42 |
+
elif command -v python3 &>/dev/null; then
|
| 43 |
+
STREAM_URL=$(echo "$JSON" | python3 -c "
|
| 44 |
+
import json, sys
|
| 45 |
+
d = json.load(sys.stdin)
|
| 46 |
+
url = d.get('manifest_url') or (d.get('videos', [{}])[0].get('url', ''))
|
| 47 |
+
print(url)
|
| 48 |
+
")
|
| 49 |
+
HEADERS=$(echo "$JSON" | python3 -c "
|
| 50 |
+
import json, sys
|
| 51 |
+
d = json.load(sys.stdin)
|
| 52 |
+
for h in d.get('headers', []):
|
| 53 |
+
print(f\"{h['key']}: {h['value']}\")
|
| 54 |
+
")
|
| 55 |
+
FORMAT=$(echo "$JSON" | python3 -c "
|
| 56 |
+
import json, sys
|
| 57 |
+
d = json.load(sys.stdin)
|
| 58 |
+
print(d.get('format', 'hls'))
|
| 59 |
+
")
|
| 60 |
+
LABEL="Stream"
|
| 61 |
+
else
|
| 62 |
+
echo "Error: requires 'jq' or 'python3' to parse JSON"
|
| 63 |
+
exit 1
|
| 64 |
+
fi
|
| 65 |
+
|
| 66 |
+
if [ -z "$STREAM_URL" ]; then
|
| 67 |
+
echo "Error: Could not extract stream URL from JSON"
|
| 68 |
+
echo "JSON received:"
|
| 69 |
+
echo "$JSON" | head -20
|
| 70 |
+
exit 1
|
| 71 |
+
fi
|
| 72 |
+
|
| 73 |
+
echo "=== BEX Stream Player ==="
|
| 74 |
+
echo "URL: $STREAM_URL"
|
| 75 |
+
echo "Format: $FORMAT"
|
| 76 |
+
echo "Label: $LABEL"
|
| 77 |
+
echo ""
|
| 78 |
+
|
| 79 |
+
# Build header arguments
|
| 80 |
+
MPV_HEADERS=""
|
| 81 |
+
FFPLAY_HEADERS=""
|
| 82 |
+
|
| 83 |
+
while IFS= read -r header; do
|
| 84 |
+
if [ -n "$header" ]; then
|
| 85 |
+
KEY=$(echo "$header" | cut -d: -f1 | xargs)
|
| 86 |
+
VALUE=$(echo "$header" | cut -d: -f2- | xargs)
|
| 87 |
+
MPV_HEADERS="${MPV_HEADERS}${KEY}: ${VALUE}\r\n"
|
| 88 |
+
FFPLAY_HEADERS="${FFPLAY_HEADERS}-headers \"${KEY}: ${VALUE}\r\n\" "
|
| 89 |
+
echo "Header: $KEY: $VALUE"
|
| 90 |
+
fi
|
| 91 |
+
done <<< "$HEADERS"
|
| 92 |
+
|
| 93 |
+
echo ""
|
| 94 |
+
|
| 95 |
+
# Try mpv first (best experience)
|
| 96 |
+
if command -v mpv &>/dev/null; then
|
| 97 |
+
echo "Playing with mpv..."
|
| 98 |
+
MPV_ARGS=(
|
| 99 |
+
"$STREAM_URL"
|
| 100 |
+
"--title=BEX: $LABEL"
|
| 101 |
+
"--force-media-title=$LABEL"
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
if [ -n "$MPV_HEADERS" ]; then
|
| 105 |
+
MPV_ARGS+=("--http-header-fields=${MPV_HEADERS}")
|
| 106 |
+
fi
|
| 107 |
+
|
| 108 |
+
# HLS-specific options
|
| 109 |
+
if [ "$FORMAT" = "hls" ] || echo "$STREAM_URL" | grep -q "m3u8"; then
|
| 110 |
+
MPV_ARGS+=(
|
| 111 |
+
"--demuxer-max-bytes=100MiB"
|
| 112 |
+
"--demuxer-max-back-bytes=50MiB"
|
| 113 |
+
"--cache=yes"
|
| 114 |
+
"--cache-secs=30"
|
| 115 |
+
)
|
| 116 |
+
fi
|
| 117 |
+
|
| 118 |
+
exec mpv "${MPV_ARGS[@]}"
|
| 119 |
+
|
| 120 |
+
# Fallback to ffplay
|
| 121 |
+
elif command -v ffplay &>/dev/null; then
|
| 122 |
+
echo "Playing with ffplay..."
|
| 123 |
+
FFPLAY_ARGS=(
|
| 124 |
+
-i "$STREAM_URL"
|
| 125 |
+
-window_title "BEX: $LABEL"
|
| 126 |
+
-loglevel warning
|
| 127 |
+
-autoexit
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
if [ -n "$MPV_HEADERS" ]; then
|
| 131 |
+
FFPLAY_ARGS+=(-headers "$MPV_HEADERS")
|
| 132 |
+
fi
|
| 133 |
+
|
| 134 |
+
exec ffplay "${FFPLAY_ARGS[@]}"
|
| 135 |
+
|
| 136 |
+
# Last resort: just print the URL for manual use
|
| 137 |
+
else
|
| 138 |
+
echo "No player found (mpv or ffplay required)"
|
| 139 |
+
echo ""
|
| 140 |
+
echo "Manual playback commands:"
|
| 141 |
+
echo ""
|
| 142 |
+
echo " mpv \"$STREAM_URL\" \\"
|
| 143 |
+
if [ -n "$MPV_HEADERS" ]; then
|
| 144 |
+
echo " --http-header-fields=\"${MPV_HEADERS}\" \\"
|
| 145 |
+
fi
|
| 146 |
+
echo " --cache=yes"
|
| 147 |
+
echo ""
|
| 148 |
+
echo " ffplay -i \"$STREAM_URL\" \\"
|
| 149 |
+
if [ -n "$MPV_HEADERS" ]; then
|
| 150 |
+
echo " -headers \"${MPV_HEADERS}\""
|
| 151 |
+
fi
|
| 152 |
+
echo ""
|
| 153 |
+
echo " curl -L -H 'User-Agent: Mozilla/5.0' \"$STREAM_URL\" | ffplay -"
|
| 154 |
+
exit 1
|
| 155 |
+
fi
|