{"id":50430050,"url":"https://github.com/faytranevozter/cctv-bot","last_synced_at":"2026-05-31T13:31:02.355Z","repository":{"id":360930376,"uuid":"1249068125","full_name":"faytranevozter/cctv-bot","owner":"faytranevozter","description":"Telegram CCTV monitor bot for capturing FFmpeg-supported camera stream snapshots and sending them to authorized chats.","archived":false,"fork":false,"pushed_at":"2026-05-28T12:27:30.000Z","size":141,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-28T14:10:10.699Z","etag":null,"topics":["camera-monitoring","cctv","docker","ffmpeg","ghcr","go","golang","hls","rtmp","rtsp","sqlite","surveillance","telegram-bot"],"latest_commit_sha":null,"homepage":"https://github.com/faytranevozter/cctv-bot","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/faytranevozter.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":"SECURITY.md","support":null,"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-05-25T10:14:40.000Z","updated_at":"2026-05-28T12:27:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/faytranevozter/cctv-bot","commit_stats":null,"previous_names":["faytranevozter/cctv-bot"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/faytranevozter/cctv-bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faytranevozter%2Fcctv-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faytranevozter%2Fcctv-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faytranevozter%2Fcctv-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faytranevozter%2Fcctv-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/faytranevozter","download_url":"https://codeload.github.com/faytranevozter/cctv-bot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faytranevozter%2Fcctv-bot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33733754,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"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":["camera-monitoring","cctv","docker","ffmpeg","ghcr","go","golang","hls","rtmp","rtsp","sqlite","surveillance","telegram-bot"],"created_at":"2026-05-31T13:31:02.296Z","updated_at":"2026-05-31T13:31:02.345Z","avatar_url":"https://github.com/faytranevozter.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CCTV Bot\n\nCCTV Bot is a Telegram bot that captures single JPEG frames from FFmpeg-supported camera streams, including RTSP, RTMP, and HLS `.m3u8`, then sends them back to authorized Telegram chats.\n\n## Features\n\n- Capture a frame from a named camera.\n- Capture a camera directly from a managed shortcut command such as `/gamping`.\n- Add, remove, and list cameras from Telegram chat.\n- Persist camera and authorization data in SQLite.\n- Automatically create camera shortcuts when adding cameras when the generated shortcut is valid and available.\n- Automatically register built-in commands and camera shortcuts on startup so users can see them from the chat command menu.\n- Restrict access through superuser-approved chat authorization requests.\n- Mask camera stream credentials in replies and logs where URLs are displayed.\n- Limit concurrent captures to protect the host and cameras.\n- Run locally or in Docker with FFmpeg included in the image.\n\n## Commands\n\nThe bot registers these commands with Telegram on startup:\n\n| Command | Description |\n| --- | --- |\n| `/requestaccess [reason]` | Request access for the current chat. |\n| `/authorized` | Superuser dashboard for pending requests and authorized chats. |\n| `/cameramanage` | Superuser camera management dashboard for adding, renaming, deleting, and shortcut management. |\n| `/snap [name]` | Show a camera picker, or capture a specific camera by name. |\n| `/cameras` | List configured cameras. |\n| `/help` | Show the command reference. |\n\nCamera management is superuser-only and button-based:\n\n```text\n/cameramanage\n```\n\nOnly users listed in `SUPERUSER_IDS` can open the dashboard. It is only available in superuser private chat to avoid leaking camera URLs in groups.\n\nCamera shortcuts are also registered as commands. For example, if camera `Gamping` has shortcut `gamping`, users can run:\n\n```text\n/gamping\n```\n\nIn groups with multiple bots, commands can include this bot's username:\n\n```text\n/cameras@cctipsibot\n/gamping@cctipsibot\n```\n\nCommands targeted at another bot username are ignored.\n\nExamples:\n\n```text\n/cameramanage\n/snap\n/cameras\n/snap \"Front Gate\"\n/front_gate\n```\n\n## Requirements\n\n- Go 1.26 or newer for local builds.\n- FFmpeg available on `PATH`, unless `FFMPEG_BIN` points to another binary.\n- A Telegram bot token from BotFather.\n- One or more Telegram superuser IDs.\n\nThe Docker image installs FFmpeg automatically.\n\n## Configuration\n\nCreate a local environment file from the example:\n\n```sh\nmake env\n```\n\nThen edit `.env` and set the required values.\n\nRequired variables:\n\n| Variable | Description |\n| --- | --- |\n| `TELEGRAM_BOT_TOKEN` | Telegram bot token from BotFather. |\n| `SUPERUSER_IDS` | Comma-separated Telegram user IDs allowed to approve/reject access requests and revoke access. |\n\nOptional variables:\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `AUTHORIZED_CHAT_IDS` | empty | Optional bootstrap list of pre-authorized chat IDs. Runtime approvals are stored in `DB_FILE`. |\n| `DB_FILE` | `cctv_bot.db` | Path to the SQLite database. Docker sets this to `/data/cctv_bot.db`. |\n| `FFMPEG_BIN` | `ffmpeg` | FFmpeg executable path. |\n| `FFMPEG_TIMEOUT_SEC` | `15` | Capture timeout in seconds. |\n| `MAX_CONCURRENT_CAPTURES` | `3` | Maximum capture jobs running at the same time. |\n| `TIMEZONE` | `Asia/Jakarta` | IANA timezone used for snapshot captions, such as `Asia/Jakarta`, `UTC`, or `America/New_York`. |\n\nExample:\n\n```env\nTELEGRAM_BOT_TOKEN=123456:ABC-DEF1234gh\nSUPERUSER_IDS=123456789\nAUTHORIZED_CHAT_IDS=123456789,-1001234567890\nDB_FILE=cctv_bot.db\nFFMPEG_BIN=ffmpeg\nFFMPEG_TIMEOUT_SEC=15\nMAX_CONCURRENT_CAPTURES=3\nTIMEZONE=Asia/Jakarta\n```\n\nSnapshot captions use `TIMEZONE` and include the location's timezone abbreviation, for example `2026-05-29 21:15:00 WIB`.\n\n## Authorization\n\nThe bot no longer uses `ALLOWED_CHAT_IDS`. Access is managed by superusers configured in `SUPERUSER_IDS`.\n\nIn Telegram forum supergroups, commands sent inside a topic are answered in the same topic. Access approval/rejection notifications are also sent back to the topic where `/requestaccess` was used. Authorization is topic-scoped: approving one topic does not authorize other topics in the same supergroup.\n\nUnauthorized chats can request access:\n\n```text\n/requestaccess Need CCTV access for this group\n```\n\nFor groups and supergroups, only a group owner/admin can request access. Private chats can request access directly.\n\nWhen a request is created, each superuser receives a private message with inline buttons:\n\n```text\n[Approve] [Reject]\n```\n\nApproving a request authorizes the chat target and stores it in `DB_FILE`. In forum supergroups, the authorized target is the exact topic where `/requestaccess` was used. Rejecting removes the pending request.\n\nSuperusers can manage access from their private chat:\n\n```text\n/authorized\n```\n\nThe dashboard shows both authorized chats and pending requests. Authorized chats have a manage button that opens a revoke screen. Pending requests have approve/reject buttons.\n\n`AUTHORIZED_CHAT_IDS` bootstraps only general chat access because it does not include Telegram topic IDs. To authorize a specific forum topic, run `/requestaccess` inside that topic. Existing authorized supergroups are migrated to general-topic access only; each additional topic must request access separately.\n\n## Storage\n\nCameras, authorized chats, and pending access requests are stored in SQLite. There is no default camera command; capture from the `/snap` camera picker, by camera name with `/snap \u003cname\u003e`, or by a configured shortcut such as `/gamping`.\n\nWhen a camera is added from `/cameramanage`, the bot tries to create a shortcut automatically from the camera name. The same dashboard can rename cameras, set/remove shortcuts, preview captures, and delete cameras.\n\n| Camera Name | Auto Shortcut |\n| --- | --- |\n| `Gamping` | `/gamping` |\n| `Front Gate` | `/front_gate` |\n| `Kantor-Kiri` | `/kantor_kiri` |\n| `CAM 01` | `/cam_01` |\n\nShortcuts must be 1-32 characters and contain only lowercase letters, numbers, and underscores. Built-in commands such as `/help`, `/snap`, and `/cameras` are reserved and cannot be used as camera shortcuts.\n\nRelevant tables:\n\n```text\ncameras\nauthorized_chats\npending_access_requests\n```\n\nSQLite is opened with WAL mode and a busy timeout so runtime updates can be handled safely by the bot process.\n\nThe `shortcut` field is optional. Existing camera entries without shortcuts still work with `/snap \u003cname\u003e` and can be assigned a shortcut from `/cameramanage`.\n\n## Local Development\n\nInstall dependencies and run the bot:\n\n```sh\nmake env\nmake run\n```\n\nCommon development commands:\n\n```sh\nmake fmt\nmake vet\nmake test\nmake build\n```\n\n`make test` runs:\n\n```sh\ngo test ./... -race -count=1\n```\n\n## Docker\n\nBuild the image:\n\n```sh\nmake docker-build\n```\n\nRun the image with `.env` and a persistent `./data` directory:\n\n```sh\nmake docker-run\n```\n\nThe Docker image sets:\n\n```env\nDB_FILE=/data/cctv_bot.db\n```\n\nThe `./data` directory on the host is mounted to `/data` in the container so camera configuration survives container restarts.\n\n## Security Notes\n\n- Only superusers in `SUPERUSER_IDS` can approve/reject access requests or revoke chat access.\n- Unauthorized chats can only use `/start`, `/help`, and `/requestaccess`.\n- Only superusers can add/remove cameras or manage shortcuts.\n- Do not commit `.env`, real bot tokens, or private camera stream URLs.\n- Camera stream credentials are masked in bot replies and logs where URLs are displayed.\n- The bot uses long polling and does not expose an HTTP port.\n\n## Troubleshooting\n\n### `TELEGRAM_BOT_TOKEN is required`\n\nSet `TELEGRAM_BOT_TOKEN` in `.env` or in the process environment.\n\n### `SUPERUSER_IDS must contain at least one user ID`\n\nSet `SUPERUSER_IDS` to one or more comma-separated Telegram user IDs.\n\n### This chat is not authorized\n\nAsk a group admin to request access:\n\n```text\n/requestaccess Need access for CCTV monitoring\n```\n\nA superuser must approve the request using the inline button sent to their private chat.\n\n### Commands or camera shortcuts do not appear in Telegram\n\nThe bot registers commands on startup and after camera shortcut changes. Restart the bot and check logs for `bot command registration failed`. Telegram clients can also take a short time to refresh the command menu.\n\n### No cameras are configured\n\nAdd one from Telegram using the superuser private dashboard:\n\n```text\n/cameramanage\n```\n\nThe camera is stored in SQLite.\n\n### A shortcut was not created automatically\n\nThe generated shortcut may be invalid, reserved, or already used. Set one manually from `/cameramanage`.\n\n### FFmpeg is not found\n\nInstall FFmpeg or set `FFMPEG_BIN` to the full binary path.\n\n### Capture times out\n\nCheck that the stream URL is reachable from the bot host. If the camera or playlist is slow, increase `FFMPEG_TIMEOUT_SEC`.\n\n## Project Structure\n\n```text\ncctv-bot/\n├── main.go              # Application startup and Telegram bot initialization\n├── bot/\n│   └── bot.go           # Command handlers, command registration data, access checks\n├── auth/\n│   └── store.go         # SQLite-backed authorization store\n├── camera/\n│   ├── capture.go       # FFmpeg frame capture\n│   ├── store.go         # SQLite-backed camera store\n│   └── stream.go        # Camera URL credential masking\n├── config/\n│   └── config.go        # Environment-based configuration loader\n├── docs/\n│   └── brief.md         # Original implementation brief\n├── .env.example         # Example environment configuration\n├── database/            # SQLite connection and schema setup\n├── Dockerfile           # Multi-stage Docker build with FFmpeg runtime\n├── Makefile             # Local development and Docker commands\n└── README.md\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaytranevozter%2Fcctv-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffaytranevozter%2Fcctv-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaytranevozter%2Fcctv-bot/lists"}