From 693b4a42f6a05179eb7c5717bc3a87fe043ca8b7 Mon Sep 17 00:00:00 2001 From: zwitschi Date: Tue, 4 Aug 2026 16:58:05 +0200 Subject: [PATCH] fix: improve CI workflows and README documentation --- .gitea/workflows/dependency-updates.yml | 51 ++++++++++----- .gitea/workflows/release.yml | 12 +++- README.md | 83 +++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 20 deletions(-) diff --git a/.gitea/workflows/dependency-updates.yml b/.gitea/workflows/dependency-updates.yml index f9a1400..751a386 100644 --- a/.gitea/workflows/dependency-updates.yml +++ b/.gitea/workflows/dependency-updates.yml @@ -13,7 +13,6 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - token: ${{ secrets.CI_REGISTRY_TOKEN }} - name: Setup Node.js uses: actions/setup-node@v4 @@ -39,20 +38,38 @@ jobs: cd backend/playout && go get -u ./... && go mod tidy cd ../chat && go get -u ./... && go mod tidy - - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 - with: - token: ${{ secrets.CI_REGISTRY_TOKEN }} - commit-message: "chore: update dependencies" - title: "chore: weekly dependency updates" - body: | - Automated weekly dependency updates. + - name: Commit and push changes + run: | + git config user.name "linearvoid-bot" + git config user.email "bot@linearvoid.local" + git add frontend/package*.json backend/playout/go.* backend/chat/go.* + if git diff --cached --quiet; then + echo "No dependency changes detected." + exit 0 + fi + git commit -m "chore: update dependencies" + git push origin HEAD:dependency-updates --force - This PR updates: - - Frontend npm dependencies - - Go module dependencies - - Please review the changes and ensure tests pass before merging. - branch: dependency-updates - delete-branch: true - labels: dependencies, automated + - name: Create Pull Request via Gitea API + run: | + RESPONSE=$(curl -s -o /tmp/pr-response.json -w "%{http_code}" \ + -X POST "$CI_SERVER_URL/api/v1/repos/zwitschi/linearvoid/pulls" \ + -H "Authorization: token ${{ secrets.CI_REGISTRY_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d '{ + "title": "chore: weekly dependency updates", + "head": "dependency-updates", + "base": "main", + "body": "Automated weekly dependency updates.\n\nThis PR updates:\n- Frontend npm dependencies\n- Go module dependencies\n\nPlease review the changes and ensure tests pass before merging." + }') + if [ "$RESPONSE" -eq 201 ]; then + PR_URL=$(cat /tmp/pr-response.json | jq -r '.html_url') + echo "PR created: $PR_URL" + elif [ "$RESPONSE" -eq 409 ]; then + echo "PR already exists. Pushing updated commits..." + git push origin dependency-updates --force + else + echo "Error creating PR (HTTP $RESPONSE):" + cat /tmp/pr-response.json + exit 1 + fi diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 8e3ba0b..d58e67f 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -34,10 +34,16 @@ jobs: id: version run: | if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT + VERSION="${{ github.event.inputs.version }}" else - echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + VERSION="${GITHUB_REF#refs/tags/}" fi + if [[ -z "$VERSION" ]]; then + echo "::error::VERSION is empty. Provide a version via workflow_dispatch input or push a tag." + exit 1 + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Releasing version: $VERSION" - name: Extract metadata for Playout id: meta-playout @@ -96,7 +102,7 @@ jobs: - name: Create Release on Gitea run: | - curl -X POST "$CI_SERVER_URL/api/v1/repos/$CI_REPO_OWNER/$CI_REPO_NAME/releases" \ + curl -X POST "https://git.allucanget.biz/api/v1/repos/zwitschi/linearvoid/releases" \ -H "Authorization: token ${{ secrets.CI_REGISTRY_TOKEN }}" \ -H "Content-Type: application/json" \ -d "{\"tag_name\":\"${{ steps.version.outputs.version }}\",\"name\":\"${{ steps.version.outputs.version }}\",\"body\":\"Release ${{ steps.version.outputs.version }}\n\nSee [CHANGELOG.md](https://git.allucanget.biz/zwitschi/linearvoid/src/branch/main/CHANGELOG.md) for details.\",\"draft\":false,\"prerelease\":false}" diff --git a/README.md b/README.md index 5b169c8..7a9995a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ [![Build Status](https://git.allucanget.biz/zwitschi/linearvoid/actions/workflows/ci.yml/badge.svg)](https://git.allucanget.biz/zwitschi/linearvoid/actions) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Gitea](https://img.shields.io/badge/Gitea-1.27.1-blue)](https://git.allucanget.biz) +[![Version](https://img.shields.io/badge/version-1.0.3-blue)](https://git.allucanget.biz/zwitschi/linearvoid/releases) +[![Release Notes](https://img.shields.io/badge/release-notes-green)](CHANGELOG.md) ## Architecture @@ -27,6 +29,23 @@ See [`docs/architecture/adr/`](docs/architecture/adr/) for the full set of decis - Video normalization, monitoring, fallback slate, and easy playlist management. - US-centric performance (Ashburn origin + Cloudflare POPs). +## Architecture Diagram + +```mermaid +flowchart TD + V[US Viewers] -->|HTTPS| CF[Cloudflare CDN] + CF -->|Cache HIT| R2[Cloudflare R2] + CF -->|Cache MISS| N[Nginx :80] + N -->|/ws| CH[Chat :3000] + N -->|/admin| CH + N -->|/hls| P[Playout :8081] + N -->|/*| FE[Frontend SPA] + CH --> R[(Redis)] + CH --> DB[(PostgreSQL)] + P -->|ffmpeg| HLS[/data/hls/] + P -->|sync| R2 +``` + ## Project Structure ```text @@ -97,9 +116,16 @@ This structure directly reflects the building blocks, runtime flows, deployment git clone https://git.allucanget.biz/zwitschi/linearvoid.git cd linearvoid cp .env.example .env +# Edit .env with your R2 credentials and domain settings docker compose up --build ``` +Then open: + +- **Viewer**: [https://linearvoid.tv](https://linearvoid.tv) (or `http://localhost`) +- **Admin**: [https://linearvoid.tv/admin](https://linearvoid.tv/admin) (or `http://localhost/admin`) +- **Metrics**: [https://linearvoid.tv/metrics](https://linearvoid.tv/metrics) + Full setup guide: [`SETUP.md`](SETUP.md). See the [architecture docs](docs/architecture/README.md) for detailed architecture and ADRs. @@ -111,6 +137,50 @@ See the [architecture docs](docs/architecture/README.md) for detailed architectu - Normalize all source videos before adding to playlist (see ADR-001 for exact codec/fps/keyframe requirements). - Monitor cache hit ratio and R2 operations closely — they determine real cost. +### Environment Variables + +| Variable | Default | Description | +| ---------------------- | ----------------------------------------------- | -------------------------------- | +| `R2_ACCESS_KEY_ID` | — | Cloudflare R2 access key | +| `R2_SECRET_ACCESS_KEY` | — | Cloudflare R2 secret key | +| `R2_BUCKET_NAME` | `linearvoid-media` | R2 bucket for HLS segments | +| `DATABASE_URL` | `postgres://...@db:5432/...` | Chat DB (Postgres or SQLite) | +| `REDIS_URL` | `redis://redis:6379/0` | Redis for presence/rate limiting | +| `VITE_PUBLIC_APP_URL` | `https://linearvoid.tv` | Public viewer URL | +| `VITE_PUBLIC_WS_URL` | `wss://linearvoid.tv/ws` | WebSocket endpoint | +| `VITE_PUBLIC_HLS_URL` | `https://media.linearvoid.tv/hls/playlist.m3u8` | HLS playlist URL | +| `ADMIN_USERNAME` | `admin` | Admin panel username | +| `ADMIN_PASSWORD` | — | Admin panel password | +| `HLS_SEGMENT_DURATION` | `6` | HLS segment duration in seconds | +| `HLS_WINDOW_SIZE` | `24` | HLS playlist window size | + +Full reference: [`.env.example`](.env.example). + +### Troubleshooting + +| Problem | Check | +| ------------------------ | ------------------------------------------------------------------------------------- | +| **Playout not starting** | Verify playlist exists in `data/playlist/playlist.txt` and media files are accessible | +| **HLS not playing** | Check `docker compose logs playout` for ffmpeg errors; verify `data/hls/` permissions | +| **Chat not connecting** | Ensure Redis is running: `docker compose logs redis`; check `DATABASE_URL` | +| **Admin panel 401** | Verify `ADMIN_USERNAME`/`ADMIN_PASSWORD` in `.env` match login credentials | +| **Docker build fails** | Run `docker compose build --no-cache`; check `backend/playout/.dockerignore` | +| **R2 upload failures** | Verify `R2_ACCESS_KEY_ID` and `R2_SECRET_ACCESS_KEY`; check bucket CORS settings | + +### API Endpoints + +| Service | Endpoint | Description | +| ----------- | ------------------------ | -------------------------- | +| **Chat** | `GET /health` | Health check | +| **Chat** | `GET /metrics` | Prometheus metrics | +| **Chat** | `GET /ws` | WebSocket upgrade for chat | +| **Chat** | `GET /api/admin/*` | Admin API (auth required) | +| **Chat** | `POST /api/admin/login` | Admin login | +| **Playout** | `GET /health` | Health check (port 8081) | +| **Nginx** | `GET /` | Viewer SPA | +| **Nginx** | `GET /admin/` | Admin panel | +| **Nginx** | `GET /hls/playlist.m3u8` | HLS manifest | + ## Architecture Documentation The architecture is fully documented using the [arc42 template](docs/architecture/README.md) (with populated sections, Mermaid context and building-block diagrams, deployment view, cross-cutting concepts, quality goals, risks, and glossary). @@ -141,4 +211,17 @@ Contributions, issues, and further evolution (LL-HLS, ABR, multi-channel, E2EE) **Container Registry**: `git.allucanget.biz/zwitschi/linearvoid/:latest` +## Contributing + +Contributions are welcome! See [`CONTRIBUTING.md`](CONTRIBUTING.md) for guidelines. Quick overview: + +1. Read the [architecture docs](docs/architecture/README.md) and ADRs first. +2. Plan tasks in `.github/instructions/TODO.md`. +3. Open PRs on [Gitea](https://git.allucanget.biz/zwitschi/linearvoid). +4. CI validates builds and tests automatically. + +Since this a linear project, we also rely on a linear development and release model: Only main branch is used for releases, and all features are merged into main after review and CI validation. Releases are tagged with semantic versioning (v1.0.3, v1.0.4, etc.) and automatically built/pushed to the container registry. + +[MIT License](LICENSE) + The project is ready for use. See [`SETUP.md`](SETUP.md) for detailed installation instructions.