This commit is contained in:
6
.dockerignore
Normal file
6
.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
||||
.git
|
||||
.upstream-open-stage-control
|
||||
node_modules
|
||||
dist
|
||||
data
|
||||
config
|
||||
114
.gitea/workflows/docker-publish.yml
Normal file
114
.gitea/workflows/docker-publish.yml
Normal file
@@ -0,0 +1,114 @@
|
||||
name: Build & Push Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "@weekly"
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Resolve latest Open Stage Control release
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
python3 <<'PY'
|
||||
import json
|
||||
import urllib.request
|
||||
|
||||
url = "https://framagit.org/api/v4/projects/jean-emmanuel%2Fopen-stage-control/releases"
|
||||
with urllib.request.urlopen(url) as response:
|
||||
releases = json.load(response)
|
||||
|
||||
if not releases:
|
||||
raise SystemExit("No releases returned by upstream API")
|
||||
|
||||
latest = releases[0]
|
||||
tag = latest["tag_name"]
|
||||
version = tag[1:] if tag.startswith("v") else tag
|
||||
|
||||
with open("release.env", "w", encoding="utf-8") as f:
|
||||
f.write(f"OSC_TAG={tag}\n")
|
||||
f.write(f"OSC_VERSION={version}\n")
|
||||
PY
|
||||
|
||||
cat release.env >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set image names
|
||||
shell: bash
|
||||
env:
|
||||
REPOSITORY: ${{ gitea.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
OWNER="${REPOSITORY%/*}"
|
||||
REPO="${REPOSITORY#*/}"
|
||||
echo "IMAGE_LATEST=git.f-40.com/${OWNER}/${REPO}:latest" >> "$GITHUB_ENV"
|
||||
echo "IMAGE_VERSIONED=git.f-40.com/${OWNER}/${REPO}:${OSC_VERSION}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Login to Gitea Container Registry
|
||||
shell: bash
|
||||
env:
|
||||
REGISTRY_USER: ${{ secrets.USER }}
|
||||
REGISTRY_TOKEN: ${{ secrets.TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "$REGISTRY_TOKEN" | docker login git.f-40.com -u "$REGISTRY_USER" --password-stdin
|
||||
|
||||
- name: Decide whether a build is needed
|
||||
shell: bash
|
||||
env:
|
||||
EVENT_NAME: ${{ gitea.event_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$EVENT_NAME" = "push" ] || [ "$EVENT_NAME" = "workflow_dispatch" ]; then
|
||||
echo "SHOULD_BUILD=true" >> "$GITHUB_ENV"
|
||||
echo "BUILD_REASON=repository change or manual run" >> "$GITHUB_ENV"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if docker manifest inspect "$IMAGE_VERSIONED" >/dev/null 2>&1; then
|
||||
echo "SHOULD_BUILD=false" >> "$GITHUB_ENV"
|
||||
echo "BUILD_REASON=version ${OSC_VERSION} already exists in registry" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "SHOULD_BUILD=true" >> "$GITHUB_ENV"
|
||||
echo "BUILD_REASON=new upstream release ${OSC_TAG}" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ "${SHOULD_BUILD}" != "true" ]; then
|
||||
echo "Skipping build: ${BUILD_REASON}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Building ${OSC_TAG} because ${BUILD_REASON}"
|
||||
docker build \
|
||||
--build-arg OPEN_STAGE_CONTROL_VERSION="${OSC_VERSION}" \
|
||||
-t "${IMAGE_LATEST}" \
|
||||
-t "${IMAGE_VERSIONED}" \
|
||||
.
|
||||
|
||||
- name: Push
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ "${SHOULD_BUILD}" != "true" ]; then
|
||||
echo "Skipping push: ${BUILD_REASON}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
docker push "${IMAGE_VERSIONED}"
|
||||
docker push "${IMAGE_LATEST}"
|
||||
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# OS / editor
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Temp / logs
|
||||
*.log
|
||||
*.tmp
|
||||
|
||||
# Docker app data
|
||||
config/
|
||||
data/
|
||||
|
||||
# Local upstream inspection clones
|
||||
.upstream-open-stage-control/
|
||||
|
||||
# Node / build artifacts
|
||||
node_modules/
|
||||
dist/
|
||||
42
Dockerfile
Normal file
42
Dockerfile
Normal file
@@ -0,0 +1,42 @@
|
||||
FROM debian:bookworm-slim AS downloader
|
||||
|
||||
ARG OPEN_STAGE_CONTROL_VERSION=1.30.3
|
||||
ARG OPEN_STAGE_CONTROL_BASE_URL=https://openstagecontrol.ammd.net/packages
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates curl unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
RUN curl -fsSLo open-stage-control.zip \
|
||||
"${OPEN_STAGE_CONTROL_BASE_URL}/open-stage-control_${OPEN_STAGE_CONTROL_VERSION}_node.zip" \
|
||||
&& unzip -q open-stage-control.zip -d extracted \
|
||||
&& mv extracted/open-stage-control_${OPEN_STAGE_CONTROL_VERSION}_node /open-stage-control
|
||||
|
||||
FROM node:20-bookworm-slim
|
||||
|
||||
LABEL org.opencontainers.image.title="Open Stage Control"
|
||||
LABEL org.opencontainers.image.description="Container image for the Open Stage Control node-only release"
|
||||
LABEL org.opencontainers.image.source="https://framagit.org/jean-emmanuel/open-stage-control"
|
||||
|
||||
ENV OSC_PORT=8080
|
||||
ENV OSC_OSC_PORT=8080
|
||||
ENV OSC_CACHE_DIR=/config
|
||||
ENV OSC_REMOTE_ROOT=/data
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
COPY --from=downloader /open-stage-control /opt/open-stage-control
|
||||
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||
|
||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh \
|
||||
&& mkdir -p /config /data
|
||||
|
||||
VOLUME ["/config", "/data"]
|
||||
|
||||
EXPOSE 8080/tcp
|
||||
EXPOSE 8080/udp
|
||||
|
||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||
CMD []
|
||||
87
README.md
87
README.md
@@ -1,3 +1,88 @@
|
||||
# OSC-Docker
|
||||
|
||||
A docker image for Open Stage Control
|
||||
Docker image for the Open Stage Control node-only release.
|
||||
|
||||
This image uses the upstream release artifact instead of building Electron from source. I verified on May 10, 2026 that Framagit's current release is `v1.30.3`, and that it publishes a `Node.js` package at:
|
||||
|
||||
`https://openstagecontrol.ammd.net/packages/open-stage-control_1.30.3_node.zip`
|
||||
|
||||
Source project:
|
||||
|
||||
`https://framagit.org/jean-emmanuel/open-stage-control`
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
docker build -t open-stage-control .
|
||||
```
|
||||
|
||||
To target a different upstream release:
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg OPEN_STAGE_CONTROL_VERSION=1.30.3 \
|
||||
-t open-stage-control .
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
docker run --rm \
|
||||
-p 8080:8080/tcp \
|
||||
-p 8080:8080/udp \
|
||||
-v "${PWD}/config:/config" \
|
||||
-v "${PWD}/data:/data" \
|
||||
open-stage-control
|
||||
```
|
||||
|
||||
Then open:
|
||||
|
||||
`http://localhost:8080`
|
||||
|
||||
## Docker Compose
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
## Gitea Actions
|
||||
|
||||
The repo includes a Gitea Actions workflow at `.gitea/workflows/docker-publish.yml`.
|
||||
|
||||
It will:
|
||||
|
||||
- build on pushes to `main`
|
||||
- allow manual runs with `workflow_dispatch`
|
||||
- poll the upstream Open Stage Control releases API once a week
|
||||
- build and push a new image only when a new upstream release tag is found
|
||||
|
||||
Required repository secrets:
|
||||
|
||||
- `USER`: registry username
|
||||
- `TOKEN`: registry token or PAT for `git.f-40.com`
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- `OSC_PORT`: HTTP port. Default `8080`.
|
||||
- `OSC_OSC_PORT`: OSC UDP input port. Default `8080`.
|
||||
- `OSC_TCP_PORT`: Optional OSC TCP input port.
|
||||
- `OSC_CACHE_DIR`: Config/cache path inside the container. Default `/config`.
|
||||
- `OSC_REMOTE_ROOT`: File browser root inside the container. Default `/data`.
|
||||
- `OSC_LOAD`: Optional session file to auto-load.
|
||||
- `OSC_STATE`: Optional state file to auto-load.
|
||||
- `OSC_CUSTOM_MODULE`: Optional custom module path.
|
||||
- `OSC_THEME`: Optional theme path or theme name.
|
||||
- `OSC_AUTHENTICATION`: Optional `user:password`.
|
||||
- `OSC_CLIENT_OPTIONS`: Optional single `key=value` client option. For multiple client options, pass extra CLI args after the image name.
|
||||
- `OSC_READ_ONLY`: Set to `true` to disable editing/saving.
|
||||
- `OSC_USE_SSL`: Set to `true` to enable HTTPS.
|
||||
- `OSC_DEBUG`: Set to `true` to log OSC traffic.
|
||||
- `OSC_NO_QRCODE`: Set to `true` to suppress QR output.
|
||||
|
||||
## Extra CLI Arguments
|
||||
|
||||
You can still pass native Open Stage Control arguments after the image name:
|
||||
|
||||
```bash
|
||||
docker run --rm -p 8080:8080/tcp -p 8080:8080/udp open-stage-control --send 192.168.1.50:9000
|
||||
```
|
||||
|
||||
17
compose.yaml
Normal file
17
compose.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
open-stage-control:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
OPEN_STAGE_CONTROL_VERSION: 1.30.3
|
||||
ports:
|
||||
- "8080:8080/tcp"
|
||||
- "8080:8080/udp"
|
||||
environment:
|
||||
OSC_PORT: 8080
|
||||
OSC_OSC_PORT: 8080
|
||||
OSC_REMOTE_ROOT: /data
|
||||
OSC_CACHE_DIR: /config
|
||||
volumes:
|
||||
- ./config:/config
|
||||
- ./data:/data
|
||||
56
docker-entrypoint.sh
Normal file
56
docker-entrypoint.sh
Normal file
@@ -0,0 +1,56 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
set -- \
|
||||
node /opt/open-stage-control \
|
||||
--no-gui \
|
||||
--cache-dir "${OSC_CACHE_DIR:-/config}" \
|
||||
--remote-root "${OSC_REMOTE_ROOT:-/data}" \
|
||||
--port "${OSC_PORT:-8080}" \
|
||||
--osc-port "${OSC_OSC_PORT:-${OSC_PORT:-8080}}"
|
||||
|
||||
if [ -n "${OSC_TCP_PORT:-}" ]; then
|
||||
set -- "$@" --tcp-port "${OSC_TCP_PORT}"
|
||||
fi
|
||||
|
||||
if [ -n "${OSC_LOAD:-}" ]; then
|
||||
set -- "$@" --load "${OSC_LOAD}"
|
||||
fi
|
||||
|
||||
if [ -n "${OSC_STATE:-}" ]; then
|
||||
set -- "$@" --state "${OSC_STATE}"
|
||||
fi
|
||||
|
||||
if [ -n "${OSC_CUSTOM_MODULE:-}" ]; then
|
||||
set -- "$@" --custom-module "${OSC_CUSTOM_MODULE}"
|
||||
fi
|
||||
|
||||
if [ -n "${OSC_THEME:-}" ]; then
|
||||
set -- "$@" --theme "${OSC_THEME}"
|
||||
fi
|
||||
|
||||
if [ -n "${OSC_CLIENT_OPTIONS:-}" ]; then
|
||||
set -- "$@" --client-options "${OSC_CLIENT_OPTIONS}"
|
||||
fi
|
||||
|
||||
if [ -n "${OSC_AUTHENTICATION:-}" ]; then
|
||||
set -- "$@" --authentication "${OSC_AUTHENTICATION}"
|
||||
fi
|
||||
|
||||
if [ "${OSC_READ_ONLY:-false}" = "true" ]; then
|
||||
set -- "$@" --read-only
|
||||
fi
|
||||
|
||||
if [ "${OSC_USE_SSL:-false}" = "true" ]; then
|
||||
set -- "$@" --use-ssl
|
||||
fi
|
||||
|
||||
if [ "${OSC_DEBUG:-false}" = "true" ]; then
|
||||
set -- "$@" --debug
|
||||
fi
|
||||
|
||||
if [ "${OSC_NO_QRCODE:-false}" = "true" ]; then
|
||||
set -- "$@" --no-qrcode
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
Reference in New Issue
Block a user