- Created a new login page for admin access at frontend/admin/login/index.html. - Implemented form submission with error handling for login credentials. - Updated frontend/index.html to mute the video player and removed unnecessary Alpine.js data binding. - Enhanced manifest URL resolution in frontend/src/main.ts to include cache-busting parameters. - Modified vite.config.ts to include the new admin login page in the build process. - Updated nginx.conf to handle admin login routing, authentication, and API proxying for admin actions.
Linear Void
Linear Void is a self-managed 24/7 linear video channel for a primarily US audience. It runs a continuous playlist of self-owned videos with true/near-true synchronization, a custom lightweight viewer SPA (hls.js player + chat), and full independence from third-party platforms (YouTube, Twitch, etc.).
Repository: git.allucanget.biz/zwitschi/linearvoid
Architecture
The architecture (detailed in docs/architecture/README.md) uses:
- Hetzner Ashburn VPS for playout (FFmpeg + MediaMTX/SRS) and chat.
- Cloudflare R2 + CDN with aggressive immutable caching of HLS
.tssegments ($0 egress). - Lightweight static frontend and WebSocket chat backend.
- Gitea self-hosted CI/CD (Actions) and Container Registry.
See docs/architecture/adr/ for the full set of decision records (ADR-001 through ADR-007) covering architecture, storage calculations, cache rules, cost model, module structure, tech stack, admin interfaces, data storage, and caching strategy.
Key Features
- Continuous synchronized playback from a playlist (standard HLS, 15–35s latency).
- Self-hosted custom SPA with embedded chat (public rooms + private 1:1 DMs, moderation).
- Extreme cost efficiency via Cloudflare R2 edge caching.
- Video normalization, monitoring, fallback slate, and easy playlist management.
- US-centric performance (Ashburn origin + Cloudflare POPs).
Project Structure
linearvoid/
├── frontend/ # Static Single-Page Application (HTML/CSS/JS)
│ ├── src/
│ │ ├── components/ # Video player, chat sidebar, now-playing overlay
│ │ ├── js/ # hls.js integration, WebSocket client, UI logic
│ │ └── styles/ # Tailwind / custom CSS
│ ├── index.html
│ └── package.json # Build tools (Vite recommended)
├── backend/
│ ├── playout/ # Continuous HLS generation from playlist
│ │ ├── src/ # FFmpeg orchestration, playlist manager
│ │ ├── config/
│ │ └── Dockerfile
│ ├── chat/ # Real-time WebSocket service
│ │ ├── src/ # Rooms, DMs, moderation, presence (Node/Go)
│ │ ├── config/
│ │ └── Dockerfile
│ └── shared/ # Common utilities, types, normalization helpers
├── infrastructure/ # Deployment, IaC, Cloudflare configs
│ ├── docker-compose.yml # Local/dev orchestration
│ ├── nginx/ # Proxy, static serving, HLS delivery
│ ├── cloudflare/ # Cache rule examples, Workers
│ └── terraform/ # (optional) provisioning
├── scripts/ # Automation scripts
│ ├── normalize-video.sh # Pre-process MP4s (codec, keyframes, CRF)
│ ├── sync-to-r2.sh # Upload segments/manifests to R2
│ └── backup.sh
├── monitoring/ # Dashboards, alerts, logging
│ ├── grafana/
│ └── prometheus/
├── docs/
│ └── architecture/
│ ├── README.md # arc42 template (fully populated)
│ └── adr/
│ ├── ADR-001.md # Consolidated decision record
│ ├── ADR-002-module-structure.md
│ ├── ADR-003-tech-stack.md
│ ├── ADR-004-admin-video.md
│ ├── ADR-005-admin-moderation-analytics.md
│ ├── ADR-006-data-storage.md
│ └── ADR-007-redis-usage.md
├── .env.example
├── .gitignore
├── docker-compose.yml # Top-level for dev (playout + chat + nginx)
├── README.md
└── LICENSE
Folder Explanations
frontend/: The viewer experience — minimal, modern SPA with Tailwind + Alpine.js (or vanilla). Useshls.jsfor playback and a WebSocket client for chat.backend/playout/: Core linear engine. FFmpeg consumes a normalized playlist and outputs continuous HLS. Includes normalization validation.backend/chat/: Independent WebSocket service (Node.js/Socket.io or Go). Handles public rooms, private DMs, presence (Redis), persistence (PostgreSQL/SQLite), rate limiting, and moderation.backend/shared/: Reusable code (types, utils, video validation).infrastructure/: Everything needed to deploy and configure the stack (Docker, Nginx, Cloudflare rules, future Terraform).scripts/: One-off and CI-friendly scripts for video preparation, R2 sync, backups, and playlist management.monitoring/: Grafana dashboards, Prometheus rules, logging configuration.docs/architecture/: Complete arc42 documentation + ADRs 001-007 (the single source of truth for all architectural decisions).
This structure directly reflects the building blocks, runtime flows, deployment view, and cross-cutting concepts defined in the arc42 documentation.
Getting Started
git clone https://git.allucanget.biz/zwitschi/linearvoid.git
cd linearvoid
cp .env.example .env
docker compose up --build
Full setup guide: SETUP.md.
See the architecture docs for detailed architecture and ADRs.
Development
- Use Docker Compose for local development (playout + chat + frontend).
- Public production host model:
https://linearvoid.tvfor viewer/admin/chat andhttps://media.linearvoid.tvfor HLS delivery. - 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.
Architecture Documentation
The architecture is fully documented using the arc42 template (with populated sections, Mermaid context and building-block diagrams, deployment view, cross-cutting concepts, quality goals, risks, and glossary).
Decision Records (in docs/architecture/adr/):
- ADR-001: Overall system architecture, HLS + Cloudflare R2 caching strategy, storage calculations, cost model, risks, and implementation plan.
- ADR-002: Chosen project folder/module structure (frontend, backend/playout, backend/chat, infrastructure, scripts, monitoring) and mapping to arc42 building blocks.
- ADR-003: Technology stack, language choices per module (TypeScript for frontend, Go preferred for chat and playout wrapper, Bash/Python for scripts), Docker-first approach, and all implicit assumptions.
- ADR-004: Video admin web interface (upload, playlist management, schedule overrides, normalization enforcement).
- ADR-005: Web admin interfaces for user management, moderation dashboard, analytics, and system configuration.
- ADR-006: Data storage strategy (SQLite vs PostgreSQL for v1, migration path, admin interface capabilities).
- ADR-007: Redis usage (exact use cases, TTL policies, persistence, fallback behavior, admin configuration).
See the architecture README for the big-picture view and the individual ADR files for detailed rationale, alternatives, and consequences.
Contributions, issues, and further evolution (LL-HLS, ABR, multi-channel, E2EE) should reference the architecture documentation.
Resources
- CHANGELOG.md - Version history and completed features.
- CONTRIBUTING.md - Guidelines for contributing to the project.
- SETUP.md - Complete setup guide with prerequisites, environment configuration, running the application, and troubleshooting.
- Architecture Documentation - Full arc42 template with diagrams and decisions.
- ADRs - Detailed decision records (ADR-001 to ADR-007).
CI/CD: View workflows on Gitea Actions.
Container Registry: git.allucanget.biz/zwitschi/linearvoid/<service>:latest
The project is ready for use. See SETUP.md for detailed installation instructions.