{"id":49516387,"url":"https://github.com/hu553in/tempstream","last_synced_at":"2026-05-01T22:03:18.999Z","repository":{"id":345766773,"uuid":"1187206606","full_name":"hu553in/tempstream","owner":"hu553in","description":"Video access service for a single live stream.","archived":false,"fork":false,"pushed_at":"2026-05-01T13:06:06.000Z","size":116,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-01T15:08:25.525Z","etag":null,"topics":["access-control","caddy","golang","hls","live-streaming","mediamtx","rtmp","self-hosted","telegram","telegram-bot","temporary-links","video-streaming"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hu553in.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-20T13:12:43.000Z","updated_at":"2026-05-01T13:06:09.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hu553in/tempstream","commit_stats":null,"previous_names":["hu553in/tempstream"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hu553in/tempstream","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hu553in%2Ftempstream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hu553in%2Ftempstream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hu553in%2Ftempstream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hu553in%2Ftempstream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hu553in","download_url":"https://codeload.github.com/hu553in/tempstream/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hu553in%2Ftempstream/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32514341,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["access-control","caddy","golang","hls","live-streaming","mediamtx","rtmp","self-hosted","telegram","telegram-bot","temporary-links","video-streaming"],"created_at":"2026-05-01T22:03:18.059Z","updated_at":"2026-05-01T22:03:18.994Z","avatar_url":"https://github.com/hu553in.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tempstream\n\n[![CI](https://github.com/hu553in/tempstream/actions/workflows/ci.yml/badge.svg)](https://github.com/hu553in/tempstream/actions/workflows/ci.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/hu553in/tempstream)](https://goreportcard.com/report/github.com/hu553in/tempstream)\n[![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/hu553in/tempstream)](https://github.com/hu553in/tempstream/blob/main/go.mod)\n\n- [License](./LICENSE)\n- [Contributing](./CONTRIBUTING.md)\n- [Code of conduct](./CODE_OF_CONDUCT.md)\n\ntempstream is a video access service for a single live stream.\n\nCore components:\n\n- a Telegram bot for operators\n- an HTTP service for watch links\n- MediaMTX for RTMP ingest and HLS output\n- Caddy as the public reverse proxy\n- SQLite for link storage\n\n## What it does\n\n- Creates temporary or permanent watch links from Telegram\n- Lists active links and disables them on demand\n- Exposes a watch page at `/live/stream/{token}`\n- Proxies HLS playback through `/play/*` after token validation\n- Accepts RTMP publishing through MediaMTX on `live/stream`\n\nA typical operator flow looks like this:\n\n1. Start the stack.\n2. Publish video to MediaMTX over RTMP.\n3. Create a watch link from Telegram.\n4. Open the generated URL in a browser.\n5. Disable the link when access should end.\n\n## Components\n\n### Telegram bot\n\nThe bot is the only admin interface. It supports:\n\n- `/new \u003cduration\u003e` for a temporary link\n- `/newperm` for a permanent link\n- `/active` to list active links\n- `/status` to show stream status\n- `/off ID` to disable a link by ID\n- `/offlast` to disable the latest active link\n- `/whoami` to show the current chat ID\n\nLinks returned by the bot include a direct disable action.\n\n### HTTP service\n\nThe Go service exposes:\n\n- `/healthz`\n- `/live/stream/{token}`\n- `/play/*`\n\n`/live/stream/{token}` validates the token, sets a session cookie for playback, and renders the watch page.\n\n`/play/*` validates the playback cookie again and proxies HLS traffic to MediaMTX.\n\n### MediaMTX\n\nMediaMTX:\n\n- accepts RTMP publishing\n- remuxes the stream to low-latency HLS\n- restricts publishing with username and password authentication\n\n### Caddy\n\nCaddy is the public entry point and reverse-proxies incoming HTTP traffic to the Go service.\n\n## Environment variables\n\n| Name                        | Required              | Default       | Description                                                                                                             |\n| --------------------------- | --------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------- |\n| `HTTP_ADDR`                 | No                    | `:8080`       | HTTP listen address for the Go service.                                                                                 |\n| `BASE_URL`                  | Yes                   | -             | Public base URL used in generated watch links.                                                                          |\n| `DB_PATH`                   | No                    | `./db.sqlite` | SQLite database path. In Docker Compose, `/data/db.sqlite` is typically used.                                           |\n| `TELEGRAM_BOT_TOKEN`        | Yes                   | -             | Telegram bot token.                                                                                                     |\n| `ALLOWED_CHAT_IDS`          | Yes                   | -             | Comma-separated list of Telegram chat IDs allowed to control the bot.                                                   |\n| `MEDIAMTX_HLS_BASE_URL`     | Yes                   | -             | Internal HLS base URL used by the Go service to probe stream health and proxy playback.                                 |\n| `COOKIE_SECURE`             | No                    | `true`        | Whether the playback cookie is marked `Secure`. Use `false` for plain local HTTP.                                       |\n| `DEFAULT_LINK_TTL`          | No                    | `1h`          | Default TTL used when a link is created with a zero duration internally.                                                |\n| `LINK_TTL_OPTIONS`          | No                    | `30m,1h,3h`   | Comma-separated list of temporary link durations shown in the Telegram bot. If empty, only permanent links are offered. |\n| `TIME_ZONE`                 | No                    | `UTC`         | IANA time zone used in bot responses, for example `UTC`, `Europe/Berlin`, or `Asia/Omsk`.                               |\n| `LOG_LEVEL`                 | No                    | `info`        | Log level for the Go service.                                                                                           |\n| `MEDIAMTX_PUBLISH_USER`     | Yes in Docker Compose | -             | Username required for RTMP publishing to MediaMTX.                                                                      |\n| `MEDIAMTX_PUBLISH_PASSWORD` | Yes in Docker Compose | -             | Password required for RTMP publishing to MediaMTX.                                                                      |\n\nSee [.env.example](./.env.example) for a complete example.\n\n## Local run\n\n### Docker Compose\n\n1. Copy the example environment:\n\n```bash\nmake ensure-env\n```\n\n2. Fill in:\n\n- `TELEGRAM_BOT_TOKEN`\n- `ALLOWED_CHAT_IDS`\n- `MEDIAMTX_PUBLISH_USER`\n- `MEDIAMTX_PUBLISH_PASSWORD`\n\n3. For phone access on the same Wi-Fi, set `BASE_URL` to the machine's LAN IP:\n\n```env\nBASE_URL=http://192.168.1.42\nCOOKIE_SECURE=false\n```\n\n4. Start the stack:\n\n```bash\nmake start\n```\n\nAfter startup:\n\n- the Go service is available behind Caddy\n- MediaMTX listens for RTMP on `:1935`\n- MediaMTX serves HLS on `:8888`\n\n### Without Docker\n\nTo run only the Go service:\n\n```bash\nmake build\ndist/tempstream\n```\n\nA reachable SQLite path, a Telegram bot token, and a running MediaMTX instance are still required.\n\n## Publishing a stream\n\nThe configured MediaMTX path is `live/stream`:\n\n```text\nrtmp://HOST:1935/live/stream?user=MEDIAMTX_PUBLISH_USER\u0026pass=MEDIAMTX_PUBLISH_PASSWORD\n```\n\nExample:\n\n```text\nrtmp://192.168.1.42:1935/live/stream?user=publisher\u0026pass=secret\n```\n\n## Watching a stream\n\nCreate a link from Telegram, then open the returned URL in a browser:\n\n```text\nhttp://HOST/live/stream/\u003ctoken\u003e\n```\n\nThe watch page:\n\n- validates the token\n- sets a playback cookie\n- loads HLS from `/play/index.m3u8`\n\nIf the link expires or is disabled, playback stops and the page shows a clear error state.\n\n## Development\n\nUseful commands:\n\n```bash\nmake build\nmake check\nmake sqlc\n```\n\nMigrations are embedded into the binary with `go:embed`, while `sqlc` uses the same migration directory on disk\nas the schema source.\n\n## Tech stack\n\n- Go 1.26\n- SQLite\n- Docker Compose\n- [Caddy](https://caddyserver.com/)\n- [MediaMTX](https://github.com/bluenviron/mediamtx)\n- [chi](https://go-chi.io/)\n- [goose](https://pressly.github.io/goose/)\n- [sqlc](https://sqlc.dev/)\n- [go-telegram/bot](https://github.com/go-telegram/bot)\n- [caarlos0/env](https://github.com/caarlos0/env)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhu553in%2Ftempstream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhu553in%2Ftempstream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhu553in%2Ftempstream/lists"}