mirror of
https://github.com/wimpysworld/stream-sprout
synced 2026-03-14 14:45:50 +01:00
Compare commits
40 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6975589341 | ||
|
|
5df0f028e2 | ||
|
|
8393e053b9 | ||
|
|
7a63368963 |
||
|
|
da76e1c219 |
||
|
|
2bda8192f1 |
||
|
|
a811fe527e | ||
|
|
c417dc1b10 | ||
|
|
b3be5c43d9 | ||
|
|
90eb31a5e5 | ||
|
|
f76da1c62b | ||
|
|
5d864aacb8 | ||
|
|
382dff7a48 |
||
|
|
bd1676efa6 |
||
|
|
a79d451d0c | ||
|
|
c470ca46e4 | ||
|
|
c156db1f64 | ||
|
|
7c57494674 | ||
|
|
57a1f800d2 | ||
|
|
9fbbde4d6c | ||
|
|
1d7e3e8247 | ||
|
|
84a1e43137 | ||
|
|
48c4943d72 | ||
|
|
1a19e85d94 | ||
|
|
3f91c0f573 | ||
|
|
e5a0db3a8f | ||
|
|
6ec390f406 | ||
|
|
0bb875c287 | ||
|
|
901586e4bf | ||
|
|
ed5d5d136b | ||
|
|
5aa579111e | ||
|
|
39c182ecf7 | ||
|
|
6984d04f7a | ||
|
|
1cb4c8ced3 | ||
|
|
a9ed96eaea | ||
|
|
43d6b9ad88 | ||
|
|
8e3b4dc089 | ||
|
|
f1b552c2bd |
||
|
|
9de404f4b2 |
||
|
|
84b36880cb |
14 changed files with 194 additions and 42 deletions
8
.github/workflows/flake-checker.yml
vendored
8
.github/workflows/flake-checker.yml
vendored
|
|
@ -13,9 +13,9 @@ jobs:
|
|||
name: Flake Checker
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: DeterminateSystems/nix-installer-action@v13
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@v7
|
||||
- uses: DeterminateSystems/flake-checker-action@v8
|
||||
- uses: DeterminateSystems/nix-installer-action@v21
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@v13
|
||||
- uses: DeterminateSystems/flake-checker-action@v12
|
||||
|
|
|
|||
8
.github/workflows/flake-updater.yml
vendored
8
.github/workflows/flake-updater.yml
vendored
|
|
@ -10,11 +10,11 @@ jobs:
|
|||
name: Flake Lock Updater
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: DeterminateSystems/nix-installer-action@v13
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@v7
|
||||
- uses: DeterminateSystems/update-flake-lock@v23
|
||||
- uses: DeterminateSystems/nix-installer-action@v21
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@v13
|
||||
- uses: DeterminateSystems/update-flake-lock@v28
|
||||
with:
|
||||
pr-title: "chore: update flake.lock"
|
||||
|
|
|
|||
2
.github/workflows/lint-pr.yml
vendored
2
.github/workflows/lint-pr.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
name: Validate pull request title
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5
|
||||
- uses: amannn/action-semantic-pull-request@v6
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
|
|
|||
2
.github/workflows/lint-shellcheck.yml
vendored
2
.github/workflows/lint-shellcheck.yml
vendored
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
name: Shellcheck
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
with:
|
||||
|
|
|
|||
14
.github/workflows/publish-release.yml
vendored
14
.github/workflows/publish-release.yml
vendored
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
name: "Check versions ⚖️"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: "Compare App and Git versions 🟰"
|
||||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
name: "Build Release 👨🔧"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: "Build .deb 🍥"
|
||||
env:
|
||||
DEBFULLNAME: "Martin Wimpress"
|
||||
|
|
@ -69,7 +69,7 @@ jobs:
|
|||
id-token: "write"
|
||||
contents: "read"
|
||||
steps:
|
||||
- uses: "actions/checkout@v4"
|
||||
- uses: "actions/checkout@v6"
|
||||
with:
|
||||
ref: "${{ (inputs.tag != null) && format('refs/tags/{0}', inputs.tag) || '' }}"
|
||||
- uses: "DeterminateSystems/nix-installer-action@main"
|
||||
|
|
@ -86,7 +86,7 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout 🥡"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Container Buildx
|
||||
|
|
@ -113,5 +113,11 @@ jobs:
|
|||
ghcr.io/${{ github.repository }}:${{ env.STREAM_SPROUT_VER }}-alpine
|
||||
ghcr.io/${{ github.repository }}:${{ github.sha }}-alpine
|
||||
platforms: linux/amd64, linux/arm64
|
||||
- name: "Generate SBOM"
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ghcr.io/${{ github.repository }}:latest-alpine
|
||||
registry-username: ${{ github.actor }}
|
||||
registry-password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Logout from Container Registry
|
||||
run: docker logout ghcr.io
|
||||
|
|
|
|||
35
.github/workflows/scan-container.yaml
vendored
Normal file
35
.github/workflows/scan-container.yaml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
name: "Vulnerability 🐞 scan 🔍 container"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 10 * * 2"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
vulnerability-scan:
|
||||
name: "Build and scan"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: build local container
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Containerfile
|
||||
tags: localbuild/testimage:latest
|
||||
push: false
|
||||
load: true
|
||||
|
||||
- name: Scan image
|
||||
uses: anchore/scan-action@v7
|
||||
with:
|
||||
image: "localbuild/testimage:latest"
|
||||
output-format: table
|
||||
|
||||
- name: Inspect action report
|
||||
run: cat ${{ steps.scan.outputs.table }}
|
||||
14
.github/workflows/test-build-stream-sprout.yml
vendored
14
.github/workflows/test-build-stream-sprout.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout 🥡"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: "Build & Test .deb 🍥"
|
||||
env:
|
||||
DEBFULLNAME: "Martin Wimpress"
|
||||
|
|
@ -55,11 +55,11 @@ jobs:
|
|||
contents: "read"
|
||||
steps:
|
||||
- name: "Checkout 🥡"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
- name: "Install Nix ❄️"
|
||||
uses: "DeterminateSystems/nix-installer-action@v13"
|
||||
uses: "DeterminateSystems/nix-installer-action@v21"
|
||||
- name: "Enable Magic Nix Cache 🪄"
|
||||
uses: "DeterminateSystems/magic-nix-cache-action@v7"
|
||||
uses: "DeterminateSystems/magic-nix-cache-action@v13"
|
||||
- name: "Build & Test .nix ❄️"
|
||||
run: |
|
||||
nix build .#stream-sprout
|
||||
|
|
@ -69,7 +69,7 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout 🥡"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Container Buildx
|
||||
|
|
@ -103,7 +103,7 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout 🥡
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Build snap 🐊
|
||||
uses: snapcore/action-build@v1
|
||||
id: snapcraft
|
||||
|
|
@ -117,7 +117,7 @@ jobs:
|
|||
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||
isClassic: false
|
||||
- name: Upload artifacts ⤴️
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: stream-sprout-snap
|
||||
path: ${{ steps.snapcraft.outputs.snap}}
|
||||
|
|
|
|||
105
AGENTS.md
Normal file
105
AGENTS.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# AGENTS.md
|
||||
|
||||
## Overview
|
||||
|
||||
Stream Sprout is a bash-based RTMP restreaming tool that forwards a single video source (from OBS Studio or similar) to multiple destinations like Twitch, YouTube, Owncast, and Peertube simultaneously. It uses FFmpeg's tee muxer to copy streams without transcoding.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Language:** Bash 5.0+ (single script: `stream-sprout`)
|
||||
- **Runtime dependency:** FFmpeg (RTMP server and restreaming)
|
||||
- **Configuration:** YAML parsed via awk/sed
|
||||
- **Packaging:** Nix flake, Debian .deb, Snap, Docker/Podman
|
||||
|
||||
## Build and Run Commands
|
||||
|
||||
```bash
|
||||
# Run directly (requires ffmpeg, bash 5.0+, awk, grep, sed)
|
||||
./stream-sprout --config stream-sprout.yaml
|
||||
|
||||
# Show version and FFmpeg info
|
||||
./stream-sprout --version
|
||||
|
||||
# Show system info (useful for bug reports)
|
||||
./stream-sprout --info
|
||||
|
||||
# Nix build
|
||||
nix build
|
||||
|
||||
# Enter development shell with all dependencies
|
||||
nix develop
|
||||
|
||||
# Docker build and run
|
||||
docker build -t stream-sprout .
|
||||
docker run -p 1935:1935 -it -v $PWD:/data stream-sprout --config /data/stream-sprout.yaml
|
||||
```
|
||||
|
||||
## Linting
|
||||
|
||||
ShellCheck is enforced via CI on all pull requests.
|
||||
|
||||
```bash
|
||||
# Run locally before committing
|
||||
shellcheck stream-sprout
|
||||
```
|
||||
|
||||
The script includes `# shellcheck disable=SC2154` for variables set dynamically via `eval` from YAML parsing.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Bash scripts use `#!/usr/bin/env bash`
|
||||
- Functions use `function name() {}` syntax
|
||||
- Use `local` for function-scoped variables
|
||||
- Use `readonly` for constants
|
||||
- Validation with informative error messages using Unicode icons and ANSI colours
|
||||
- Version is tracked in the script: `readonly VERSION="x.y.z"`
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
stream-sprout # Main bash script (single file)
|
||||
stream-sprout.yaml # Local config (gitignored)
|
||||
stream-sprout.yaml.example # Example configuration
|
||||
package.nix # Nix package definition
|
||||
devshell.nix # Nix development shell
|
||||
flake.nix # Nix flake
|
||||
Dockerfile # Alpine-based container
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
YAML config with two main sections:
|
||||
|
||||
- `server:` - RTMP server settings (ip, port, app, key, archive options)
|
||||
- `services:` - Destination services (each with enabled, rtmp_server, key)
|
||||
|
||||
Config search order: `./stream-sprout.yaml`, `$XDG_CONFIG_HOME/stream-sprout.yaml`, `/etc/stream-sprout.yaml`
|
||||
|
||||
## PR and Commit Guidelines
|
||||
|
||||
- **Commit messages must follow [Conventional Commits](https://www.conventionalcommits.org/)**
|
||||
- PR titles are validated against Conventional Commits format
|
||||
- Single-commit PRs must have matching PR title and commit message
|
||||
- ShellCheck must pass with no warnings
|
||||
|
||||
Common prefixes: `feat:`, `fix:`, `chore:`, `refactor:`, `docs:`
|
||||
|
||||
## Version Updates
|
||||
|
||||
When changing version:
|
||||
|
||||
1. Update `VERSION` in `stream-sprout` script
|
||||
2. The Nix package extracts version automatically from the script
|
||||
|
||||
## Constraints
|
||||
|
||||
- Requires bash 5.0 or newer
|
||||
- FFmpeg must be available on PATH
|
||||
- RTMP only (no RTMPS support currently)
|
||||
- FFmpeg does not enforce stream keys (documented security limitation)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Stream keys are stored in plain text in YAML config
|
||||
- FFmpeg accepts any RTMP stream on the configured port regardless of app/key path
|
||||
- Do not expose the RTMP port to untrusted networks without additional protection (VPN, firewall, SSH tunnel)
|
||||
|
|
@ -1,5 +1,17 @@
|
|||
FROM ghcr.io/jrottenberg/ffmpeg:7-alpine
|
||||
RUN apk add --no-cache --update bash coreutils gawk grep sed
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache --update \
|
||||
bash \
|
||||
jellyfin-ffmpeg \
|
||||
gawk \
|
||||
grep \
|
||||
sed
|
||||
|
||||
RUN ln -sf /usr/lib/jellyfin-ffmpeg/ffmpeg /usr/local/bin/ffmpeg && \
|
||||
ln -sf /usr/lib/jellyfin-ffmpeg/ffprobe /usr/local/bin/ffprobe
|
||||
|
||||
COPY --chown=nobody:nobody --chmod=755 stream-sprout /usr/bin/stream-sprout
|
||||
|
||||
EXPOSE 1935
|
||||
USER nobody
|
||||
ENTRYPOINT [ "stream-sprout" ]
|
||||
|
|
|
|||
1
Dockerfile
Symbolic link
1
Dockerfile
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
Containerfile
|
||||
|
|
@ -39,7 +39,7 @@ Stream Sprout is developed on Linux 🐧 and should work on macOS 🍏 or any ot
|
|||
## Get Started
|
||||
|
||||
- [Install](#installation) Stream Sprout 🧑💻
|
||||
- [Configure](#configuration) Stream Sprout 🧑💻
|
||||
- [Configure](#configure-stream-sprout) Stream Sprout 🧑💻
|
||||
- [Configure](#configure-obs-studio) OBS Studio 🎛️
|
||||
- Start `stream-sprout` ⌨️
|
||||
- Click the *Start Streaming* button in OBS Studio 🖱️
|
||||
|
|
@ -271,10 +271,6 @@ services:
|
|||
[rtmp @ 0x2ca9be80] Unexpected stream STREAMBOMB, expecting c5b559b2-589d-4925-a28e-20d1954fd6c5
|
||||
Last message repeated 1 times
|
||||
```
|
||||
- Stream Sprout does not support restreaming using secure RTMP (RTMPS).
|
||||
- *At least I don't think it does, but I haven't fully tested it.*
|
||||
- Kick only appears to support rtmps:// URLs and Stream Sprout restreams do not appear on Kick.
|
||||
- https://superuser.com/questions/1438939/live-streaming-over-rtmps-using-ffmpeg
|
||||
- Each destination you add will increase your bandwidth requirements.
|
||||
|
||||
## References
|
||||
|
|
|
|||
20
flake.lock
generated
20
flake.lock
generated
|
|
@ -2,12 +2,12 @@
|
|||
"nodes": {
|
||||
"flake-schemas": {
|
||||
"locked": {
|
||||
"lastModified": 1721078157,
|
||||
"narHash": "sha256-c2AZH9cOnSpPXV8Lwy19/I8EgW7G+E+Zh6YQBZZwzxI=",
|
||||
"rev": "29e53dd33b1a38f235ef073e768c62821cb6146e",
|
||||
"revCount": 66,
|
||||
"lastModified": 1761577921,
|
||||
"narHash": "sha256-eK3/xbUOrxp9fFlei09XNjqcdiHXxndzrTXp7jFpOk8=",
|
||||
"rev": "47849c7625e223d36766968cc6dc23ba0e135922",
|
||||
"revCount": 107,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/DeterminateSystems/flake-schemas/0.1.3/0190b841-54d3-7b7a-8550-24942bc38caf/source.tar.gz"
|
||||
"url": "https://api.flakehub.com/f/pinned/DeterminateSystems/flake-schemas/0.2.0/019a4a84-544d-7c59-b26d-e334e320c932/source.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
|
|
@ -16,12 +16,12 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1721548954,
|
||||
"narHash": "sha256-7cCC8+Tdq1+3OPyc3+gVo9dzUNkNIQfwSDJ2HSi2u3o=",
|
||||
"rev": "63d37ccd2d178d54e7fb691d7ec76000740ea24a",
|
||||
"revCount": 633334,
|
||||
"lastModified": 1769318308,
|
||||
"narHash": "sha256-Mjx6p96Pkefks3+aA+72lu1xVehb6mv2yTUUqmSet6Q=",
|
||||
"rev": "1cd347bf3355fce6c64ab37d3967b4a2cb4b878c",
|
||||
"revCount": 906484,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2405.633334%2Brev-63d37ccd2d178d54e7fb691d7ec76000740ea24a/0190d847-0241-7628-8ab0-d49f442300f4/source.tar.gz"
|
||||
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2511.906484%2Brev-1cd347bf3355fce6c64ab37d3967b4a2cb4b878c/019bfb68-fb8e-7f55-bb2a-5bee98516c95/source.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@ platforms:
|
|||
arm64:
|
||||
build-on: [ arm64 ]
|
||||
build-for: [arm64 ]
|
||||
armhf:
|
||||
build-on: [ armhf ]
|
||||
build-for: [ armhf ]
|
||||
|
||||
parts:
|
||||
stream-sprout:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
stty -echoctl
|
||||
|
||||
readonly STREAM_SPROUT_YAML="stream-sprout.yaml"
|
||||
readonly VERSION="0.1.5"
|
||||
readonly VERSION="0.1.6"
|
||||
|
||||
function cleanup() {
|
||||
echo -e " \e[31m\U26D4\e[0m Control-C"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue