diff --git a/deploy/truenas/core/Dockerfile b/deploy/truenas/core/Dockerfile index 0e51269..f1f9166 100644 --- a/deploy/truenas/core/Dockerfile +++ b/deploy/truenas/core/Dockerfile @@ -39,9 +39,20 @@ FROM node:21-alpine3.20 AS ui-builder ARG RESTREAMER_UI_REF=v1.14.0 RUN apk add --no-cache git WORKDIR /ui + +# 1. Pull upstream restreamer-ui at the pinned tag. RUN git clone --depth=1 --branch ${RESTREAMER_UI_REF} \ - https://github.com/datarhei/restreamer-ui.git . \ - && yarn install --frozen-lockfile --network-timeout 600000 \ + https://github.com/datarhei/restreamer-ui.git . + +# 2. Layer Wild Dragon overlays on top of the upstream tree before the +# build runs. apply-overlay.sh does the rsync + targeted seds; see +# deploy/truenas/core/ui-overlay/apply-overlay.sh for the contract. +COPY deploy/truenas/core/ui-overlay /overlay +RUN OVERLAY=/overlay UI=/ui /overlay/apply-overlay.sh + +# 3. Install + build. PUBLIC_URL=./ keeps asset references relative so +# the bundle is portable across mount paths. +RUN yarn install --frozen-lockfile --network-timeout 600000 \ && PUBLIC_URL="./" GENERATE_SOURCEMAP=false yarn build # ---- runtime ---- diff --git a/deploy/truenas/core/ui-overlay/apply-overlay.sh b/deploy/truenas/core/ui-overlay/apply-overlay.sh new file mode 100755 index 0000000..02e2343 --- /dev/null +++ b/deploy/truenas/core/ui-overlay/apply-overlay.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# apply-overlay.sh — Wild Dragon reskin patches applied to a freshly +# cloned datarhei/restreamer-ui tree. Two phases: +# +# 1. File overlay: rsync the contents of $OVERLAY/{public,src} on top +# of the upstream working tree. Whole-file replacements only — +# simple and idempotent. +# +# 2. Targeted in-place sed for one-line UI strings that aren't worth +# a whole-file overlay (the header title, a few welcome strings). +# Each pattern is anchored to a unique surrounding context so a +# future upstream rename doesn't silently rewrite the wrong line. +# +# Caller: the Dockerfile's ui-builder stage. Expects: +# $OVERLAY = /overlay (the COPY destination) +# $UI = /ui (the cloned upstream source root) +# +# Idempotent on a single source tree (rerunning is a no-op). + +set -eu + +OVERLAY="${OVERLAY:-/overlay}" +UI="${UI:-/ui}" + +echo "wilddragon-overlay: layering $OVERLAY -> $UI" + +# Phase 1 — file copies. -L follows any future symlinks, -p preserves +# perms, -R recursive. We deliberately avoid --delete: the upstream +# tree must stay intact except for the files we override. +for sub in public src; do + if [ -d "$OVERLAY/$sub" ]; then + cp -RLp "$OVERLAY/$sub/." "$UI/$sub/" + fi +done + +# Phase 2 — targeted seds. Each replacement is wrapped in a check so +# the script fails loudly if upstream changed the line we're patching +# (rather than silently no-op'ing and shipping un-rebranded UI). +patch_line() { + file="$1"; needle="$2"; replacement="$3" + if ! grep -qF "$needle" "$file"; then + echo "wilddragon-overlay: ERROR — pattern not found in $file:" + echo " $needle" + exit 1 + fi + # Use awk for safe literal substitution (sed's regex would mishandle + # special chars in the replacement). + tmp="$(mktemp)" + awk -v n="$needle" -v r="$replacement" ' + index($0, n) { sub(n, r); } + { print } + ' "$file" > "$tmp" + mv "$tmp" "$file" + echo "wilddragon-overlay: patched $(basename "$file") — $needle -> $replacement" +} + +patch_line "$UI/src/Header.js" \ + 'Restreamer' \ + 'Wild Dragon' + +# Welcome view top-of-page card. +patch_line "$UI/src/views/Welcome.js" \ + 'title="Welcome to Restreamer v2"' \ + 'title="Welcome to Wild Dragon"' + +patch_line "$UI/src/views/Settings.js" \ + 'title="Welcome to Restreamer v2"' \ + 'title="Welcome to Wild Dragon"' + +echo "wilddragon-overlay: done." diff --git a/deploy/truenas/core/ui-overlay/public/favicon.ico b/deploy/truenas/core/ui-overlay/public/favicon.ico new file mode 100644 index 0000000..c5bf589 Binary files /dev/null and b/deploy/truenas/core/ui-overlay/public/favicon.ico differ diff --git a/deploy/truenas/core/ui-overlay/public/index.html b/deploy/truenas/core/ui-overlay/public/index.html new file mode 100644 index 0000000..4465026 --- /dev/null +++ b/deploy/truenas/core/ui-overlay/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + + Wild Dragon + + + +
+ + diff --git a/deploy/truenas/core/ui-overlay/public/logo192.png b/deploy/truenas/core/ui-overlay/public/logo192.png new file mode 100644 index 0000000..8985006 Binary files /dev/null and b/deploy/truenas/core/ui-overlay/public/logo192.png differ diff --git a/deploy/truenas/core/ui-overlay/public/logo512.png b/deploy/truenas/core/ui-overlay/public/logo512.png new file mode 100644 index 0000000..da15e57 Binary files /dev/null and b/deploy/truenas/core/ui-overlay/public/logo512.png differ diff --git a/deploy/truenas/core/ui-overlay/public/manifest.json b/deploy/truenas/core/ui-overlay/public/manifest.json new file mode 100644 index 0000000..90a0fef --- /dev/null +++ b/deploy/truenas/core/ui-overlay/public/manifest.json @@ -0,0 +1,13 @@ +{ + "short_name": "Wild Dragon", + "name": "Wild Dragon — Live Streaming", + "icons": [ + { "src": "favicon.ico", "sizes": "64x64 32x32 16x16", "type": "image/x-icon" }, + { "src": "logo192.png", "type": "image/png", "sizes": "192x192" }, + { "src": "logo512.png", "type": "image/png", "sizes": "512x512" } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#0d0e12", + "background_color": "#0d0e12" +} diff --git a/deploy/truenas/core/ui-overlay/src/misc/Logo/images/logo.svg b/deploy/truenas/core/ui-overlay/src/misc/Logo/images/logo.svg new file mode 100644 index 0000000..f7d2242 --- /dev/null +++ b/deploy/truenas/core/ui-overlay/src/misc/Logo/images/logo.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + WD + + + + WILD DRAGON + + diff --git a/deploy/truenas/core/ui-overlay/src/misc/Logo/images/rs-logo.svg b/deploy/truenas/core/ui-overlay/src/misc/Logo/images/rs-logo.svg new file mode 100644 index 0000000..5842917 --- /dev/null +++ b/deploy/truenas/core/ui-overlay/src/misc/Logo/images/rs-logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/deploy/truenas/core/ui-overlay/src/misc/Logo/index.js b/deploy/truenas/core/ui-overlay/src/misc/Logo/index.js new file mode 100644 index 0000000..ee3c4e2 --- /dev/null +++ b/deploy/truenas/core/ui-overlay/src/misc/Logo/index.js @@ -0,0 +1,24 @@ +import React from 'react'; + +import makeStyles from '@mui/styles/makeStyles'; + +import company_logo from './images/logo.svg'; + +const useStyles = makeStyles((theme) => ({ + Logo: { + height: 27, + }, +})); + +export default function Logo(props) { + const classes = useStyles(); + + let link = 'https://forge.wilddragon.net/zgaetano/datarhei-dragonfork-core'; + + // eslint-disable-next-line no-useless-escape + return ( + + Wild Dragon logo + + ); +} diff --git a/deploy/truenas/core/ui-overlay/src/misc/Logo/rsLogo.js b/deploy/truenas/core/ui-overlay/src/misc/Logo/rsLogo.js new file mode 100644 index 0000000..be2a60f --- /dev/null +++ b/deploy/truenas/core/ui-overlay/src/misc/Logo/rsLogo.js @@ -0,0 +1,24 @@ +import React from 'react'; + +import makeStyles from '@mui/styles/makeStyles'; + +import company_logo from './images/rs-logo.svg'; + +const useStyles = makeStyles((theme) => ({ + Logo: { + height: 95, + }, +})); + +export default function Logo(props) { + const classes = useStyles(); + + let link = 'https://forge.wilddragon.net/zgaetano/datarhei-dragonfork-core'; + + // eslint-disable-next-line no-useless-escape + return ( + + Wild Dragon mark + + ); +}