test-image.sh publishes the plugin on the host, bakes it into a stock jellyfin/jellyfin image via Dockerfile.test, and runs it on :8096, with optional egress through a LAN gateway (DOCKER_GATEWAY, e.g. the Swiss VPN box) for geo-blocked streams. JELLYFIN_TAG (default 12) selects the image and the matching plugin build: 10.9/10.10 -> net8.0, 10.11 -> net9.0, 12 -> net10.0, with the generated meta.json targetAbi to match. Images are tagged per version (srfplay-test:<tag>) so several can coexist. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
107 lines
4.3 KiB
Bash
Executable File
107 lines
4.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build the SRF Play plugin from the local checkout, bake it into a stock
|
|
# Jellyfin image, and run it on http://localhost:8096.
|
|
#
|
|
# ./test-image.sh build + run
|
|
# ./test-image.sh build build image only (no run)
|
|
#
|
|
# JELLYFIN_TAG picks the Jellyfin image (default 12) and, with it, the matching
|
|
# plugin build (see the TargetFrameworks comment in the plugin csproj):
|
|
#
|
|
# JELLYFIN_TAG=10.11.0 ./test-image.sh
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")"
|
|
|
|
JELLYFIN_TAG="${JELLYFIN_TAG:-12}"
|
|
PLUGIN_DIR=".test-plugin/SRFPlay"
|
|
IMAGE="srfplay-test:${JELLYFIN_TAG}"
|
|
|
|
case "$JELLYFIN_TAG" in
|
|
10.9*|10.10*) FRAMEWORK="net8.0"; ABI="10.9.0.0" ;;
|
|
10.11*) FRAMEWORK="net9.0"; ABI="10.11.0.0" ;;
|
|
*) FRAMEWORK="net10.0"; ABI="12.0.0.0" ;;
|
|
esac
|
|
|
|
echo ">> Publishing plugin for Jellyfin ${JELLYFIN_TAG} (${FRAMEWORK}, host build, warm cache)..."
|
|
rm -rf .test-plugin
|
|
dotnet publish Jellyfin.Plugin.SRFPlay/Jellyfin.Plugin.SRFPlay.csproj \
|
|
--configuration Release --framework "$FRAMEWORK" --no-self-contained -o /tmp/srfplay-publish >/dev/null
|
|
|
|
mkdir -p "$PLUGIN_DIR"
|
|
cp /tmp/srfplay-publish/Jellyfin.Plugin.SRFPlay.dll "$PLUGIN_DIR/"
|
|
|
|
# Generate the meta.json Jellyfin needs to load the plugin, from build.yaml.
|
|
# targetAbi follows the framework chosen above rather than build.yaml.
|
|
GUID=$(grep -E '^guid:' build.yaml | sed -E 's/^guid:[[:space:]]*"?([^"]+)"?.*/\1/')
|
|
VERSION=$(grep -E '^version:' build.yaml | sed -E 's/^version:[[:space:]]*"?([^"]+)"?.*/\1/')
|
|
|
|
cat > "$PLUGIN_DIR/meta.json" <<EOF
|
|
{
|
|
"guid": "$GUID",
|
|
"name": "SRF Play",
|
|
"version": "$VERSION",
|
|
"targetAbi": "$ABI",
|
|
"owner": "dtourolle",
|
|
"overview": "SRF Play plugin for Jellyfin (test build)",
|
|
"description": "Local test build of the SRF Play plugin.",
|
|
"category": "Live TV",
|
|
"status": "Active",
|
|
"autoUpdate": false
|
|
}
|
|
EOF
|
|
|
|
echo ">> Building image $IMAGE (stock Jellyfin + plugin COPY)..."
|
|
docker build -f Dockerfile.test --build-arg JELLYFIN_TAG="$JELLYFIN_TAG" -t "$IMAGE" .
|
|
|
|
if [ "${1:-run}" = "build" ]; then
|
|
echo ">> Built $IMAGE. Run with: docker run --rm -p 8096:8096 $IMAGE"
|
|
exit 0
|
|
fi
|
|
|
|
# --- Optional: route the container's egress via a LAN gateway ----------------
|
|
# Set DOCKER_GATEWAY to a LAN gateway IP (e.g. the Swiss VPN box 192.168.1.52)
|
|
# to send this container's outbound traffic through it. Needs sudo once to add
|
|
# host policy-route + masquerade; both are removed automatically on exit.
|
|
#
|
|
# DOCKER_GATEWAY=192.168.1.52 ./test-image.sh
|
|
#
|
|
# When unset, the container uses Docker's normal default route (your ISP).
|
|
|
|
TEST_NET="srfplay-testnet"
|
|
TEST_SUBNET="172.31.250.0/24"
|
|
TEST_TABLE="250" # dedicated rt table for this subnet
|
|
# The uplink is the interface that actually reaches the gateway (the LAN NIC,
|
|
# e.g. wlan0) — NOT the host default route, which a VPN killswitch may point
|
|
# at the tunnel. Derive it from the route to DOCKER_GATEWAY when set.
|
|
if [ -n "${DOCKER_GATEWAY:-}" ]; then
|
|
UPLINK_IF="$(ip route get "$DOCKER_GATEWAY" 2>/dev/null | grep -oE 'dev [^ ]+' | awk '{print $2}')"
|
|
fi
|
|
|
|
cleanup() {
|
|
echo ">> Cleaning up..."
|
|
docker rm -f srfplay-test-run >/dev/null 2>&1 || true
|
|
if [ -n "${DOCKER_GATEWAY:-}" ]; then
|
|
sudo ip rule del from "$TEST_SUBNET" table "$TEST_TABLE" 2>/dev/null || true
|
|
sudo ip route flush table "$TEST_TABLE" 2>/dev/null || true
|
|
sudo iptables -t nat -D POSTROUTING -s "$TEST_SUBNET" -o "$UPLINK_IF" -j MASQUERADE 2>/dev/null || true
|
|
fi
|
|
docker network rm "$TEST_NET" >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
docker network rm "$TEST_NET" >/dev/null 2>&1 || true
|
|
docker network create --subnet "$TEST_SUBNET" "$TEST_NET" >/dev/null
|
|
|
|
if [ -n "${DOCKER_GATEWAY:-}" ]; then
|
|
echo ">> Routing container egress via gateway $DOCKER_GATEWAY (uplink $UPLINK_IF)..."
|
|
echo " (sudo needed once to install host routes; removed on exit)"
|
|
sudo ip route replace default via "$DOCKER_GATEWAY" dev "$UPLINK_IF" table "$TEST_TABLE"
|
|
sudo ip rule add from "$TEST_SUBNET" table "$TEST_TABLE" 2>/dev/null || true
|
|
sudo iptables -t nat -C POSTROUTING -s "$TEST_SUBNET" -o "$UPLINK_IF" -j MASQUERADE 2>/dev/null \
|
|
|| sudo iptables -t nat -A POSTROUTING -s "$TEST_SUBNET" -o "$UPLINK_IF" -j MASQUERADE
|
|
fi
|
|
|
|
echo ">> Starting Jellyfin on http://localhost:8096 (Ctrl-C to stop)..."
|
|
docker run --rm --name srfplay-test-run --network "$TEST_NET" -p 8096:8096 "$IMAGE"
|