Tactical Media Broadcast Hub — initial release
Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
This commit is contained in:
commit
aa5e262f3a
880 changed files with 111042 additions and 0 deletions
42
infra/peertube/.env.example
Normal file
42
infra/peertube/.env.example
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# === Copy to .env on the PeerTube server and fill in ===
|
||||
PEERTUBE_WEBSERVER_HOSTNAME=peertube.example.com
|
||||
PEERTUBE_WEBSERVER_PORT=443
|
||||
PEERTUBE_WEBSERVER_HTTPS=true
|
||||
|
||||
# Initial admin (set on first boot only)
|
||||
PEERTUBE_ADMIN_EMAIL=admin@example.com
|
||||
|
||||
# --- S3 object storage (REQUIRED per project decision) ---
|
||||
# Works with any S3-compatible endpoint: MinIO on the same server, another server, or a cloud provider.
|
||||
# Tactical Media Broadcast Hub's own media plane already speaks S3 (StorageService) — use the same bucket infra
|
||||
# but a DEDICATED bucket for PeerTube (e.g. tactical-media-broadcast-hub-peertube) with its own credentials.
|
||||
PEERTUBE_OBJECT_STORAGE_ENABLED=true
|
||||
PEERTUBE_OBJECT_STORAGE_WEB_ENDPOINT=https://s3.example.com
|
||||
PEERTUBE_OBJECT_STORAGE_WEB_REGION=us-east-1
|
||||
PEERTUBE_OBJECT_STORAGE_ACCESS_KEY_ID=CHANGEME
|
||||
PEERTUBE_OBJECT_STORAGE_SECRET_ACCESS_KEY=CHANGEME
|
||||
PEERTUBE_OBJECT_STORAGE_VIDEOS_BUCKET=tactical-media-broadcast-hub-peertube-videos
|
||||
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BUCKET=tactical-media-broadcast-hub-peertube-playlists
|
||||
PEERTUBE_OBJECT_STORAGE_REDUNDANCY_BUCKET=tactical-media-broadcast-hub-peertube-redundancy
|
||||
# Same credentials/endpoint config repeated for the internal (non-web) endpoints if different:
|
||||
# PEERTUBE_OBJECT_STORAGE_ENDPOINT=...
|
||||
|
||||
# --- Livestreaming (fed by the Tactical Media Broadcast Hub compositor via RTMP) ---
|
||||
PEERTUBE_TRANSCODING_ENABLED=true
|
||||
PEERTUBE_LIVE_ENABLED=true
|
||||
PEERTUBE_LIVE_ALLOW_REPLAY=true
|
||||
PEERTUBE_LIVE_MAX_DURATION=-1
|
||||
PEERTUBE_LIVE_TRANSCODING_ENABLED=true
|
||||
PEERTUBE_LIVE_RTMP_PORT=1935
|
||||
|
||||
# --- Database (use the container's postgres or point at your own) ---
|
||||
PEERTUBE_DB_USERNAME=peertube
|
||||
PEERTUBE_DB_PASSWORD=CHANGEME
|
||||
PEERTUBE_DB_HOSTNAME=postgres
|
||||
# For an external DB, add a postgres service or set PEERTUBE_DB_HOSTNAME to the server.
|
||||
|
||||
# --- Federation ---
|
||||
PEERTUBE_FEDERATION_ENABLED=true
|
||||
|
||||
# --- Trust the Tactical Media Broadcast Hub API server for connector/bridge calls ---
|
||||
PEERTUBE_TRUST_PROXY=127.0.0.1,::1
|
||||
50
infra/peertube/brand-sync/sync-brand.sh
Executable file
50
infra/peertube/brand-sync/sync-brand.sh
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
# sync-brand.sh — propagate the Tactical Media Broadcast Hub brand to a PeerTube instance.
|
||||
# SOURCE OF TRUTH: this repo (brand assets + design tokens). Re-run after ANY brand change.
|
||||
# Requires: PEERTUBE_URL (e.g. https://peertube.example.com), PEERTUBE_TOKEN (a user token with
|
||||
# manage settings scope), both exported or in a .env next to this script.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/../.."
|
||||
REPO_ROOT="$(pwd)/.." # infra/peertube -> repo root one level up from infra
|
||||
BRAND="$REPO_ROOT/apps/web/public/brand"
|
||||
[ -f "$(dirname "$0")/.env" ] && source "$(dirname "$0")/.env"
|
||||
: "${PEERTUBE_URL:?export PEERTUBE_URL=https://peertube.example.com}"
|
||||
: "${PEERTUBE_TOKEN:?export PEERTUBE_TOKEN=<user token with settings scope>}"
|
||||
|
||||
echo "→ syncing Tactical Media Broadcast Hub brand to $PEERTUBE_URL"
|
||||
|
||||
# 1. Instance name + short description
|
||||
curl -sf -X PUT "$PEERTUBE_URL/api/v1/config/custom" \
|
||||
-H "Authorization: Bearer $PEERTUBE_TOKEN" -H "Content-Type: application/json" \
|
||||
-d '{"instance":{"name":"Tactical Media Broadcast Hub Live","shortDescription":"Our platform. Their feeds. No algorithm in between."}}'
|
||||
|
||||
# 2. Custom CSS derived from the brand tokens (warm red on black, tilted identity)
|
||||
# The CSS below is the PROPAGATED COPY — when tokens change in apps/web globals.css,
|
||||
# update docs/peertube-setup.md says: re-run scripts/update-brand-css.sh (or edit here + rerun sync).
|
||||
css=$(cat <<'CSS'
|
||||
:root { --ap-accent: #FF1610; --ap-bg: #000000; }
|
||||
.custom-navbar, body { background: var(--ap-bg) !important; }
|
||||
.custom-navbar .navbar-brand, .title-page { color: #fff !important; }
|
||||
a, .btn-orange, .peertube-button-link { --mainColor: var(--ap-accent) !important; color: var(--ap-accent) !important; }
|
||||
.btn-primary { background-color: var(--ap-accent) !important; border-color: var(--ap-accent) !important; }
|
||||
CSS
|
||||
)
|
||||
python3 - "$css" <<'PY' | curl -sf -X PUT "$PEERTUBE_URL/api/v1/config/custom" -H "Authorization: Bearer $PEERTUBE_TOKEN" -H "Content-Type: application/json" -d @-
|
||||
import json, sys, os
|
||||
css = sys.argv[1]
|
||||
body = {"customization": {"css": css}}
|
||||
print(json.dumps(body))
|
||||
PY
|
||||
|
||||
# 3. Logo — PeerTube takes instance banners/avatar via the config API image endpoints
|
||||
# (uploads the tilted circle-A mark; fallback to avatar upload if banner endpoint differs by version)
|
||||
if [ -f "$BRAND/logo.svg" ]; then
|
||||
PNG=$(mktemp --suffix=.png)
|
||||
convert -background none "$BRAND/logo.svg" -resize 512x512 "$PNG" 2>/dev/null || \
|
||||
npx --yes sharp-cli -i "$BRAND/logo.svg" -o "$PNG" 2>/dev/null || true
|
||||
[ -s "$PNG" ] && curl -sf -X POST "$PEERTUBE_URL/api/v1/config/custom/logo" \
|
||||
-H "Authorization: Bearer $PEERTUBE_TOKEN" -F "image=@$PNG" || echo " (logo upload skipped — check endpoint for your PeerTube version)"
|
||||
rm -f "$PNG"
|
||||
fi
|
||||
|
||||
echo "✓ brand synced. Re-run this script after any brand change (assets or tokens) — it is idempotent."
|
||||
33
infra/peertube/docker-compose.yml
Normal file
33
infra/peertube/docker-compose.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# PeerTube instance for Tactical Media Broadcast Hub — DESIGNED TO RUN ON A DIFFERENT SERVER.
|
||||
# Deploy: copy this directory to the media server, create .env from .env.example, then `docker compose up -d`.
|
||||
# Docs: docs/peertube-setup.md (S3, branding sync, connector bridge, livechat)
|
||||
|
||||
services:
|
||||
peertube:
|
||||
image: chocobozzz/peertube:production-bookworm
|
||||
# Pin to a specific tag in production, e.g. chocobozzz/peertube:v7.x
|
||||
env_file: .env
|
||||
ports:
|
||||
- "80:9000" # put behind your reverse proxy (nginx/caddy) with HTTPS
|
||||
- "1935:1935" # RTMP ingest — the Tactical Media Broadcast Hub media worker pushes live here
|
||||
volumes:
|
||||
- peertube_assets:/app/storage/client-overrides # custom logo/emoji live here too, but BRAND SYNC via API is canonical
|
||||
- peertube_config:/app/config
|
||||
depends_on:
|
||||
- redis
|
||||
- postfix
|
||||
restart: unless-stopped
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
|
||||
postfix:
|
||||
image: mwader/postfix-relay
|
||||
environment:
|
||||
- POSTFIX_myhostname=${PEERTUBE_WEBSERVER_HOSTNAME}
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
peertube_assets:
|
||||
peertube_config:
|
||||
Loading…
Add table
Add a link
Reference in a new issue