{"id":47809045,"url":"https://github.com/drjakeberg/stream247","last_synced_at":"2026-04-03T18:01:35.631Z","repository":{"id":347311144,"uuid":"1193507718","full_name":"DrJakeberg/stream247","owner":"DrJakeberg","description":"Self-hosted Twitch-first 24/7 channel automation platform with scheduling, source ingestion, playout control, Twitch sync, overlays, and   ops tooling.","archived":false,"fork":false,"pushed_at":"2026-03-27T19:09:28.000Z","size":400,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-27T22:45:02.837Z","etag":null,"topics":["automation","broadcast","docker","docker-compose","ffmpeg","mation","nextjs","obs","overlay","postgresql","scheduler","self-hosted","streaming","twitch","yt-dlp"],"latest_commit_sha":null,"homepage":"https://s.3jc.de/s247","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DrJakeberg.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-27T09:52:18.000Z","updated_at":"2026-03-27T19:09:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/DrJakeberg/stream247","commit_stats":null,"previous_names":["drjakeberg/stream247"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/DrJakeberg/stream247","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrJakeberg%2Fstream247","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrJakeberg%2Fstream247/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrJakeberg%2Fstream247/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrJakeberg%2Fstream247/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DrJakeberg","download_url":"https://codeload.github.com/DrJakeberg/stream247/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrJakeberg%2Fstream247/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31368156,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T17:53:18.093Z","status":"ssl_error","status_checked_at":"2026-04-03T17:53:17.617Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","broadcast","docker","docker-compose","ffmpeg","mation","nextjs","obs","overlay","postgresql","scheduler","self-hosted","streaming","twitch","yt-dlp"],"created_at":"2026-04-03T18:01:32.174Z","updated_at":"2026-04-03T18:01:35.613Z","avatar_url":"https://github.com/DrJakeberg.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stream247\n\nStream247 is a self-hosted platform for running a Twitch-first 24/7 channel from managed video sources such as local media, direct media URLs, YouTube playlists, and Twitch VODs.\n\nIt ships as Docker / Docker Compose, publishes images through GitHub Actions and GHCR, and gives operators a browser-based admin UI for scheduling, playout control, Twitch sync, moderation policy, and incident handling.\n\n## What It Does Today\n\n- Docker-first self-hosted deployment with published GHCR images\n- setup wizard with owner account bootstrap\n- local login plus Twitch broadcaster connect and Twitch SSO team access\n- PostgreSQL-backed runtime state\n- source ingestion for:\n  - local media library\n  - direct media URLs\n  - YouTube playlists via `yt-dlp`\n  - Twitch VODs via `yt-dlp`\n- schedule management with:\n  - minute-accurate blocks\n  - overlap validation\n  - drag-and-drop day timeline editing\n- playout operations with:\n  - FFmpeg RTMP output foundation\n  - fallback asset selection\n  - manual restart\n  - temporary fallback override\n  - pin asset on air\n  - skip current asset\n  - resume schedule control\n- Twitch automation with:\n  - title sync from active schedule block\n  - category sync from active schedule block\n  - upcoming Twitch schedule segment sync\n  - moderation policy support for emote-only fallback\n- ops tooling with:\n  - incidents\n  - incident history and filters\n  - acknowledge / resolve actions\n  - runtime drift checks\n  - recent audit trail visibility\n  - worker/playout healthcheck commands\n  - Discord webhook alerts\n  - SMTP email alerts\n  - readiness and health endpoints\n- encrypted-at-rest managed secret storage for Twitch and alert credentials\n- viewer-facing pages with:\n  - public schedule page\n  - browser-source overlay page with admin-managed branding\n\n## What Is Not Done Yet\n\n- richer multi-scene overlay composition inside the playout runtime\n- more advanced playout transitions and scene-aware switchovers\n- deeper analytics views and richer incident correlation\n- richer timeline editing such as resize / duplicate flows and inline override lanes\n\n## Quick Start\n\n1. Copy `.env.example` to `.env`.\n2. Set:\n   - `APP_URL`\n   - `APP_SECRET`\n   - `POSTGRES_PASSWORD`\n   - the matching password inside `DATABASE_URL`\n3. Optional but recommended:\n   - `TWITCH_CLIENT_ID`\n   - `TWITCH_CLIENT_SECRET`\n   - `TWITCH_STREAM_KEY`\n   - `CHANNEL_TIMEZONE`\n4. Start the stack:\n   ```bash\n   docker compose up -d\n   ```\n5. Open:\n   - `http://localhost:3000/setup`\n6. Create the owner account.\n7. Sign in to the admin UI.\n8. Optional during bootstrap:\n   - enter `TWITCH_CLIENT_ID`\n   - enter `TWITCH_CLIENT_SECRET`\n9. Or add/update encrypted managed credentials later in:\n   - `/settings`\n10. Connect Twitch from the dashboard if you want broadcaster sync and Twitch SSO.\n11. Add media by either:\n   - placing files into `data/media`\n   - adding direct media URLs\n   - adding a YouTube playlist source\n   - adding a Twitch VOD source\n12. Build a schedule and let the worker ingest assets.\n\nFor local-development builds instead of GHCR images:\n\n```bash\ndocker compose -f docker-compose.dev.yml up -d --build\n```\n\nFor pinned production deployment, start from:\n\n```bash\ncp .env.production.example .env\n```\n\nIn most cases you only need to set these before first start:\n\n- `APP_URL`\n- `APP_SECRET`\n- `POSTGRES_PASSWORD`\n- `DATABASE_URL`\n- `TRAEFIK_HOST` and `TRAEFIK_ACME_EMAIL` if you use the Traefik profile\n- `TWITCH_STREAM_KEY` if you want real Twitch output immediately\n\nTwitch client credentials, SMTP, and Discord can also be entered later in the setup wizard or `/settings`.\n\nFor Traefik-based HTTPS deployment:\n\n```bash\ndocker compose --profile proxy up -d\n```\n\n## Configuration\n\n### Required Environment Variables\n\n- `APP_URL`: externally reachable base URL, for example `https://stream247.example.com`\n- `APP_SECRET`: session-signing secret\n- `POSTGRES_PASSWORD`: password used by PostgreSQL\n- `DATABASE_URL`: must use the same PostgreSQL password as `POSTGRES_PASSWORD`\n\n### Required Only For The Traefik Profile\n\n- `TRAEFIK_HOST`: public hostname for Traefik routing\n- `TRAEFIK_ACME_EMAIL`: email used for Let's Encrypt\n\n### Common Optional Environment Variables\n\n- `TWITCH_CLIENT_ID`: Twitch application client id\n- `TWITCH_CLIENT_SECRET`: Twitch application client secret\n- `TWITCH_STREAM_KEY`: Twitch stream key for RTMP output\n- `TWITCH_RTMP_URL`: defaults to `rtmp://live.twitch.tv/app`\n- `STREAM_OUTPUT_URL`: generic RTMP output override\n- `STREAM_OUTPUT_KEY`: generic RTMP key override\n- `CHANNEL_TIMEZONE`: schedule timezone, for example `Europe/Berlin`\n- `DISCORD_WEBHOOK_URL`: Discord alert target\n- `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_FROM`, `ALERT_EMAIL_TO`: email alerting\n- `TRAEFIK_CERT_RESOLVER`: Traefik certificate resolver name, defaults to `letsencrypt`\n\n### What Belongs In `.env`\n\n- infrastructure secrets\n- RTMP stream keys\n- optional fallback OAuth application credentials\n- optional fallback SMTP / Discord credentials\n- deployment-level defaults such as `CHANNEL_TIMEZONE`\n\n### What Does Not Belong In `.env`\n\n- moderator presence policy\n- schedule blocks\n- operator overrides\n- sources and assets\n- incidents and acknowledgements\n\nThose are runtime settings stored in PostgreSQL and managed from the admin UI.\n\n### Managed Secrets In The Admin UI\n\nStream247 can now store these credentials encrypted at rest in PostgreSQL:\n\n- `TWITCH_CLIENT_ID`\n- `TWITCH_CLIENT_SECRET`\n- default Twitch category id\n- Discord webhook URL\n- SMTP host / port / user / password\n- SMTP from address\n- alert recipient email\n\nBehavior:\n\n- setup can capture Twitch client id and secret during bootstrap\n- `/settings` can update managed credentials later\n- blank password/secret fields keep the existing stored value\n- `.env` values still work as fallback if no managed value exists\n\n## Twitch App Credentials\n\nIf you need `TWITCH_CLIENT_ID` and `TWITCH_CLIENT_SECRET`, follow this section or the dedicated guide in [docs/twitch-setup.md](docs/twitch-setup.md#how-to-get-client-id-and-secret).\n\n1. Open the Twitch developer console.\n2. Create a new application or edit the existing Stream247 application.\n3. Register both redirect URLs:\n   - `\u003cAPP_URL\u003e/api/integrations/twitch/callback`\n   - `\u003cAPP_URL\u003e/api/auth/twitch/callback`\n4. Copy the generated Client ID into `TWITCH_CLIENT_ID`.\n5. Generate, reveal, or regenerate the Client Secret and store it in `TWITCH_CLIENT_SECRET`.\n6. Restart the stack after changing `.env`.\n7. Use the dashboard for:\n   - broadcaster connect\n   - Twitch SSO sign-in for team members\n\nImportant:\n\n- `TWITCH_CLIENT_ID` is public application identity.\n- `TWITCH_CLIENT_SECRET` is private application secret.\n- both can now be stored as encrypted managed settings in Stream247.\n- `.env` remains supported as bootstrap and deployment fallback.\n\n## Deployment\n\n### Production Defaults\n\n- Linux host\n- Docker Compose\n- reverse proxy in front of `web`\n- optional built-in Traefik profile for HTTPS and Let's Encrypt\n- persistent storage for:\n  - PostgreSQL\n  - Redis\n  - `data/media`\n\nSee [docs/deployment.md](docs/deployment.md) for the deployment-focused guide.\n\n### Published Images\n\n- `ghcr.io/drjakeberg/stream247-web`\n- `ghcr.io/drjakeberg/stream247-worker`\n- `ghcr.io/drjakeberg/stream247-playout`\n\nThe default `.env.example` already points Compose at the `latest` GHCR tags.\nFor production pinning, use `.env.production.example` or set the image tags explicitly to the target release.\n\n### Release Behavior\n\n- `push` to `main` validates, builds, smoke-tests, and publishes current images\n- `push` of `v*` tags runs the release workflow for versioned images\n- CI uses the public ECR mirror for `node:22-alpine` to avoid Docker Hub rate limits on GitHub-hosted runners\n- production should pin explicit release tags and not follow `latest`\n- release rehearsal helpers are available:\n  - `pnpm release:preflight`\n  - `./scripts/upgrade-rehearsal.sh v1.0.0`\n  - `./scripts/soak-monitor.sh --hours 24`\n\nOperational docs:\n\n- [docs/upgrading.md](docs/upgrading.md)\n- [docs/backup-and-restore.md](docs/backup-and-restore.md)\n- [docs/operations.md](docs/operations.md)\n- [docs/versioning.md](docs/versioning.md)\n\n## Release Readiness Workflow\n\nBefore tagging a production release:\n\n1. Pin explicit GHCR version tags in `.env`.\n2. Run:\n   ```bash\n   pnpm release:preflight\n   ```\n3. Rehearse the target version:\n   ```bash\n   ./scripts/upgrade-rehearsal.sh v1.0.0\n   ```\n4. Run an extended soak:\n   ```bash\n   ./scripts/soak-monitor.sh --hours 24\n   ```\n5. Review `/ops`, `/api/health`, and `/api/system/readiness`.\n6. Tag only after the rehearsal and soak are clean.\n\nNotes:\n\n- set `CHECK_BASE_URL=http://127.0.0.1:3000` if your public `APP_URL` points through an external proxy or domain that is not reachable from the host running the scripts\n- set `SESSION_COOKIE=\"stream247_session=...\"` if you want the soak monitor to fail on open critical incidents via the authenticated incidents API\n\n## Feature Overview\n\n### Authentication And Access\n\n- owner bootstrap via setup wizard\n- local session-based authentication\n- Twitch SSO team login\n- role-based access with `owner`, `admin`, `operator`, `moderator`, `viewer`\n- team access grants by Twitch login\n- optional Twitch client credential capture during setup\n\n### Sources And Assets\n\n- local media scan from `data/media`\n- direct media URL sources\n- YouTube playlist ingestion via `yt-dlp`\n- Twitch VOD ingestion via `yt-dlp`\n- PostgreSQL-backed asset catalog\n- fallback asset priority and global fallback support\n\n### Scheduling\n\n- schedule block CRUD\n- minute-accurate start times\n- duration validation\n- overlap detection\n- day timeline with drag-and-drop rescheduling\n- public-facing schedule page\n\n### Playout And Broadcast Ops\n\n- FFmpeg-based RTMP playout foundation\n- destination readiness state\n- operator restart control\n- operator pin-asset override\n- operator skip-current control\n- temporary fallback override\n- resume-schedule control\n- worker-managed playout runtime state\n\n### Twitch Automation\n\n- broadcaster OAuth connect\n- title sync from active schedule block\n- category lookup and sync from active schedule block\n- Twitch schedule segment sync for upcoming blocks\n- Twitch SSO for team members\n- moderation policy automation for emote-only fallback windows\n\n### Moderation\n\n- explicit moderator presence windows such as `here 30`\n- configurable moderation policy in admin UI\n- emote-only fallback when no active moderator window is present\n\n### Alerts And Incident Management\n\n- incident creation from runtime failures\n- incident history with status / severity / scope filters\n- incident acknowledgement\n- incident resolution\n- runtime drift reporting for worker, playout, schedule alignment, destination readiness, and Twitch metadata\n- recent audit trail visibility in the ops view\n- Discord webhook alerts\n- SMTP email alerts\n- audit events\n- encrypted-at-rest managed integration secrets with `.env` fallback\n\n### Overlay And Viewer Pages\n\n- public schedule page at `/channel`\n- browser-source overlay at `/overlay`\n- overlay studio in admin UI\n- configurable channel name, headline, accent color, emergency banner, and now/next teaser toggles\n\n## Local Development\n\n1. Copy `.env.example` to `.env`.\n2. Start dependencies:\n   ```bash\n   docker compose up -d postgres redis\n   ```\n3. Install dependencies:\n   ```bash\n   pnpm install\n   ```\n4. Start the web app:\n   ```bash\n   pnpm dev\n   ```\n\n## Validation\n\nThe intended validation path is:\n\n- `pnpm validate`\n- Docker image build\n- container smoke test\n\nCurrent validation covers:\n\n- lint\n- typecheck\n- unit tests\n- integration tests\n- production build\n- Docker builds\n- smoke test for the web image\n\n## Troubleshooting\n\n### Twitch OAuth does not work\n\n- check that `APP_URL` matches the externally reachable URL exactly\n- confirm both redirect URLs are registered in the Twitch developer application\n- verify `TWITCH_CLIENT_ID` and `TWITCH_CLIENT_SECRET`\n\n### No assets are available\n\n- put files into `data/media`\n- or add a direct media URL / YouTube playlist / Twitch VOD source\n- check worker incidents if ingestion failed\n\n### Stream output is not ready\n\n- verify `TWITCH_STREAM_KEY` or `STREAM_OUTPUT_KEY`\n- verify `TWITCH_RTMP_URL` or `STREAM_OUTPUT_URL`\n- inspect destination state and incidents on the dashboard\n\n### Email alerts do not send\n\n- verify `SMTP_HOST`\n- verify `SMTP_FROM`\n- verify `ALERT_EMAIL_TO`\n- verify SMTP auth settings if your server requires them\n\n## Monorepo Layout\n\n- `apps/web`: Next.js admin UI, public pages, and API routes\n- `apps/worker`: background ingestion, reconciliation, and playout logic\n- `packages/core`: scheduling and moderation domain logic\n- `packages/config`: runtime config helpers\n- `packages/db`: PostgreSQL-backed application state layer\n- `docs`: architecture, deployment, and Twitch setup docs\n- `.github`: CI, release, issues, and PR templates\n\n## Roadmap\n\n- encrypted secret management from the setup/admin UI\n- richer multi-scene overlay composition\n- more advanced playout transitions and switchovers\n- deeper ops views, filtering, and historical analytics\n- more powerful timeline authoring directly in the schedule editor\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrjakeberg%2Fstream247","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrjakeberg%2Fstream247","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrjakeberg%2Fstream247/lists"}