Aggiunge overlay server-side burn-in e stabilizza diretta live.
Tabellone, badge e brand sono ricodificati nel flusso _air via OverlayRelay; sync punteggio HTTP, volume condiviso rails/sidekiq, qualità 720p migliorata e badge CONNECTING in ripresa da pausa. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
9
infra/scripts/cron/run_rails_task.sh
Executable file
9
infra/scripts/cron/run_rails_task.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Esegue un task Rails in produzione (usato da crontab).
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="${MATCHLIVETV_INFRA:-/opt/matchlivetv/infra}"
|
||||
cd "$ROOT"
|
||||
|
||||
exec docker compose -f docker-compose.prod.yml --env-file .env exec -T rails \
|
||||
bundle exec rails "$@"
|
||||
37
infra/scripts/garage_set_capacity.sh
Executable file
37
infra/scripts/garage_set_capacity.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# Ridimensiona capacità Garage (layout assign + apply). Uso: garage_set_capacity.sh 85G
|
||||
set -euo pipefail
|
||||
|
||||
CAPACITY="${1:-}"
|
||||
RESERVE_GB="${GARAGE_RESERVE_GB:-20}"
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.prod.yml}"
|
||||
ENV_FILE="${ENV_FILE:-${ROOT}/.env}"
|
||||
GARAGE_CONTAINER="${GARAGE_CONTAINER:-}"
|
||||
|
||||
if [ -z "$CAPACITY" ]; then
|
||||
avail="$(df -BG "${ROOT}" 2>/dev/null | awk 'NR==2 {print $4}' | tr -d 'G' || echo 0)"
|
||||
if [ "$avail" -lt 1 ]; then
|
||||
avail="$(df -BG / 2>/dev/null | awk 'NR==2 {print $4}' | tr -d 'G')"
|
||||
fi
|
||||
cap_gb=$((avail - RESERVE_GB))
|
||||
[ "$cap_gb" -lt 10 ] && cap_gb=10
|
||||
CAPACITY="${cap_gb}G"
|
||||
echo "Spazio disponibile ~${avail}G, riservo ${RESERVE_GB}G → capacità Garage ${CAPACITY}"
|
||||
fi
|
||||
|
||||
cd "$ROOT"
|
||||
if [ -z "$GARAGE_CONTAINER" ]; then
|
||||
GARAGE_CONTAINER="$(docker ps --format '{{.Names}}' | grep -E 'garage-1$' | head -1)"
|
||||
fi
|
||||
[ -n "$GARAGE_CONTAINER" ] || { echo "Container garage non trovato"; exit 1; }
|
||||
|
||||
node_id="$(docker exec "$GARAGE_CONTAINER" /garage status 2>/dev/null | awk '/^[0-9a-f]{16,}/{print $1; exit}')"
|
||||
[ -n "$node_id" ] || { echo "Node id non trovato"; exit 1; }
|
||||
|
||||
echo "Node: $node_id → capacità $CAPACITY"
|
||||
docker exec "$GARAGE_CONTAINER" /garage layout assign -z dc1 -c "$CAPACITY" "$node_id"
|
||||
ver="$(docker exec "$GARAGE_CONTAINER" /garage layout show 2>/dev/null | awk '/layout version:/{print $NF; exit}')"
|
||||
next=$((ver + 1))
|
||||
docker exec "$GARAGE_CONTAINER" /garage layout apply --version "$next"
|
||||
docker exec "$GARAGE_CONTAINER" /garage layout show
|
||||
@@ -1,13 +1,33 @@
|
||||
#!/bin/sh
|
||||
# Generate offline slate MP4 for MediaMTX alwaysAvailable (pausa / attesa segnale)
|
||||
# Slate MP4 per MediaMTX alwaysAvailable (pausa / attesa / perdita rete).
|
||||
# H.264 1280x720 30fps + AAC 48kHz mono (allineato all'app Android).
|
||||
set -e
|
||||
OUT_DIR="$(dirname "$0")/../slates"
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
OUT_DIR="$(cd "$(dirname "$0")/../slates" && pwd)"
|
||||
BRAND_IMAGE="${BRAND_IMAGE:-$ROOT/brand/CopertinaCanale_6.png}"
|
||||
OUT="$OUT_DIR/offline.mp4"
|
||||
|
||||
if [ ! -f "$BRAND_IMAGE" ]; then
|
||||
echo "Manca immagine brand: $BRAND_IMAGE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$OUT_DIR"
|
||||
docker run --rm -v "$OUT_DIR:/out" linuxserver/ffmpeg:latest \
|
||||
-f lavfi -i color=c=0x1a1a1a:s=1280x720:r=30 \
|
||||
-vf "drawtext=text='Match Live TV':fontcolor=white:fontsize=48:x=(w-text_w)/2:y=(h-text_h)/2-40,drawtext=text='Trasmissione in pausa':fontcolor=0xaaaaaa:fontsize=28:x=(w-text_w)/2:y=(h-text_h)/2+20" \
|
||||
-f lavfi -i sine=frequency=440:sample_rate=48000 \
|
||||
-t 30 -c:v libx264 -pix_fmt yuv420p -g 30 -preset fast \
|
||||
-c:a aac -b:a 128k -y /out/offline.mp4
|
||||
echo "Created $OUT"
|
||||
BRAND_DIR="$(cd "$(dirname "$BRAND_IMAGE")" && pwd)"
|
||||
BRAND_FILE="$(basename "$BRAND_IMAGE")"
|
||||
|
||||
docker run --rm \
|
||||
-v "$OUT_DIR:/out" \
|
||||
-v "$BRAND_DIR:/brand:ro" \
|
||||
linuxserver/ffmpeg:latest \
|
||||
-loop 1 -framerate 30 -i "/brand/$BRAND_FILE" \
|
||||
-f lavfi -i anullsrc=r=48000:cl=mono \
|
||||
-filter:v "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=0x0a0a0e" \
|
||||
-map 0:v -map 1:a \
|
||||
-t 30 -c:v libx264 -pix_fmt yuv420p -profile:v baseline -level 3.1 \
|
||||
-x264-params "keyint=30:min-keyint=30:scenecut=0:bframes=0" \
|
||||
-g 30 -keyint_min 30 -force_key_frames "expr:gte(t,n_forced*1)" \
|
||||
-preset fast \
|
||||
-c:a aac -b:a 128k -ac 1 -shortest -y /out/offline.mp4
|
||||
|
||||
echo "Created $OUT from $BRAND_IMAGE"
|
||||
|
||||
35
infra/scripts/install_production_cron.sh
Executable file
35
infra/scripts/install_production_cron.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# Installa crontab replay su server produzione (utente corrente).
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
RUNNER="${ROOT}/scripts/cron/run_rails_task.sh"
|
||||
LOG_DIR="${MATCHLIVETV_LOG_DIR:-/opt/matchlivetv/log}"
|
||||
LOG_FILE="${LOG_DIR}/cron-replay.log"
|
||||
|
||||
chmod +x "$RUNNER"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
MARKER="# matchlivetv-replay-cron"
|
||||
CRON_BLOCK="${MARKER}
|
||||
0 3 * * * ${RUNNER} recordings:purge_expired >> ${LOG_FILE} 2>&1
|
||||
0 8 * * * ${RUNNER} recordings:expiry_warnings >> ${LOG_FILE} 2>&1
|
||||
"
|
||||
|
||||
existing="$(crontab -l 2>/dev/null || true)"
|
||||
if echo "$existing" | grep -q "$MARKER"; then
|
||||
echo "Crontab replay già presente, aggiorno..."
|
||||
echo "$existing" | awk -v block="$CRON_BLOCK" '
|
||||
BEGIN { skip=0 }
|
||||
/# matchlivetv-replay-cron/ { skip=1; next }
|
||||
skip && /^[^#]/ && $0 !~ /^$/ { skip=0 }
|
||||
skip { next }
|
||||
{ print }
|
||||
END { print block }
|
||||
' | crontab -
|
||||
else
|
||||
(echo "$existing"; echo "$CRON_BLOCK") | crontab -
|
||||
fi
|
||||
|
||||
echo "Crontab installato:"
|
||||
crontab -l | grep -A3 "$MARKER"
|
||||
@@ -14,6 +14,13 @@ bash "${ROOT}/scripts/ensure_garage_prod_config.sh"
|
||||
echo "Avvio Garage..."
|
||||
docker compose -f docker-compose.prod.yml --env-file .env up -d garage
|
||||
|
||||
avail_gb="$(df -BG / 2>/dev/null | awk 'NR==2 {print $4}' | tr -d 'G')"
|
||||
reserve="${GARAGE_RESERVE_GB:-20}"
|
||||
cap_gb=$((avail_gb - reserve))
|
||||
[ "$cap_gb" -lt 10 ] && cap_gb=10
|
||||
export GARAGE_NODE_CAPACITY="${GARAGE_NODE_CAPACITY:-${cap_gb}G}"
|
||||
echo "Capacità nodo Garage: ${GARAGE_NODE_CAPACITY} (disco ~${avail_gb}G, riserva ${reserve}G)"
|
||||
|
||||
bash "${ROOT}/scripts/setup_garage_replays.sh"
|
||||
|
||||
echo "Riavvio Rails e Sidekiq..."
|
||||
|
||||
@@ -46,7 +46,8 @@ ensure_layout() {
|
||||
exit 1
|
||||
fi
|
||||
echo "Node id: $node_id"
|
||||
gexec layout assign -z dc1 -c 1G "$node_id" 2>/dev/null || true
|
||||
local cap="${GARAGE_NODE_CAPACITY:-1G}"
|
||||
gexec layout assign -z dc1 -c "$cap" "$node_id" 2>/dev/null || true
|
||||
gexec layout apply --version 1 2>/dev/null || gexec layout apply 2>/dev/null || true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user