{"id":13467591,"url":"https://github.com/kastldratza/zoomrec","last_synced_at":"2025-03-26T03:30:48.531Z","repository":{"id":37284385,"uuid":"315728393","full_name":"kastldratza/zoomrec","owner":"kastldratza","description":"Record Zoom meetings automatically in headless docker container with Python and FFmpeg","archived":false,"fork":false,"pushed_at":"2025-02-09T07:37:08.000Z","size":31447,"stargazers_count":279,"open_issues_count":2,"forks_count":69,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-09T08:25:55.128Z","etag":null,"topics":["automation","csv","docker","ffmpeg","headless","meetings","python-script","python3","recording","screencapture","screencast","ubuntu","vnc","xfce","zoom","zoom-meetings","zoom-recorder","zoomrecorder"],"latest_commit_sha":null,"homepage":"","language":"Python","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/kastldratza.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"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},"funding":{"github":"kastldratza"}},"created_at":"2020-11-24T19:08:37.000Z","updated_at":"2025-02-05T01:13:27.000Z","dependencies_parsed_at":"2023-01-31T00:01:25.051Z","dependency_job_id":"44a2f9dc-c71a-48de-8ce8-7431f2aeb528","html_url":"https://github.com/kastldratza/zoomrec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kastldratza%2Fzoomrec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kastldratza%2Fzoomrec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kastldratza%2Fzoomrec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kastldratza%2Fzoomrec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kastldratza","download_url":"https://codeload.github.com/kastldratza/zoomrec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245584473,"owners_count":20639554,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","csv","docker","ffmpeg","headless","meetings","python-script","python3","recording","screencapture","screencast","ubuntu","vnc","xfce","zoom","zoom-meetings","zoom-recorder","zoomrecorder"],"created_at":"2024-07-31T15:00:58.283Z","updated_at":"2025-03-26T03:30:48.487Z","avatar_url":"https://github.com/kastldratza.png","language":"Python","funding_links":["https://github.com/sponsors/kastldratza"],"categories":["Python","automation"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n    zoomrec\t\n\u003c/h1\u003e\n\n\u003ch4 align=\"center\"\u003e\n\tA all-in-one solution to automatically join and record Zoom meetings.\n\u003c/h4\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://github.com/kastldratza/zoomrec/actions/workflows/docker-publish.yml\"\u003e\u003cimg src=\"https://github.com/kastldratza/zoomrec/actions/workflows/docker-publish.yml/badge.svg\" alt=\"GitHub Workflow Status\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://github.com/kastldratza/zoomrec/actions/workflows/codeql.yml\"\u003e\u003cimg src=\"https://github.com/kastldratza/zoomrec/actions/workflows/codeql.yml/badge.svg\" alt=\"GitHub Workflow Status\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://github.com/kastldratza/zoomrec/actions/workflows/snyk.yml\"\u003e\u003cimg src=\"https://github.com/kastldratza/zoomrec/actions/workflows/snyk.yml/badge.svg\" alt=\"GitHub Workflow Status\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://github.com/kastldratza/zoomrec/actions/workflows/snyk-container-analysis.yml\"\u003e\u003cimg src=\"https://github.com/kastldratza/zoomrec/actions/workflows/snyk-container-analysis.yml/badge.svg\" alt=\"GitHub Workflow Status\"\u003e\u003c/a\u003e\n    \u003cbr\u003e\n    \u003cimg alt=\"Docker Pulls\" src=\"https://img.shields.io/docker/pulls/kastldratza/zoomrec\"\u003e\n    \u003cimg alt=\"Docker Image Size (tag)\" src=\"https://img.shields.io/docker/image-size/kastldratza/zoomrec/latest\"\u003e\n    \u003cimg alt=\"Github Stars\" src=\"https://img.shields.io/github/stars/kastldratza/zoomrec.svg\"\u003e\n\u003c/p\u003e\n\n---\n\n- **Python3** - _Script to automatically join Zoom meetings and control FFmpeg_\n- **FFmpeg** - _Triggered by python script to start/stop screen recording_\n- **Docker** - _Headless VNC Container based on Ubuntu 20.04 with Xfce window manager and TigerVNC_\n- **Telegram** - _Get notified about your recordings_\n\n---\n\nJoin with ID and Passcode           |  Join with URL\n:-------------------------:|:-------------------------:\n![](doc/demo/join-meeting-id.gif)  |  ![](doc/demo/join-meeting-url.gif)\n\n---\n\n## Installation\n\nThe entire mechanism runs in a Docker container. So all you need to do is install Docker and use the image from\nRegistry.\n\n### Requirements\n\n- Docker - [https://docs.docker.com/get-docker/]()\n\n### Docker Registry\n\nDocker images are build and pushed automatically to [**Docker\nHub**](https://hub.docker.com/repository/docker/kastldratza/zoomrec) and [**GitHub Container\nRegistry**](https://github.com/kastldratza/zoomrec/pkgs/container/zoomrec).\n\nSo you can choose and use one of them:\n\n- ```ghcr.io/kastldratza/zoomrec:master```\n- ```kastldratza/zoomrec:latest```\n\n*For my examples in this README I used* ```kastldratza/zoomrec:latest```\n\n---\n\n## Usage\n\n- Container saves recordings at **/home/zoomrec/recordings**\n- The current directory is used to mount **recordings**-Folder, but can be changed if needed\n    - Please check use of paths on different operating systems!\n    - Please check permissions for used directory!\n- Container stops when Python script is terminated\n- Zoomrec uses a CSV file with entries of Zoom meetings to record them\n    - The csv can be passed as seen below (mount as volume or add to docker image)\n- To \"say\" something after joining a meeting:\n    - ***paplay*** (*pulseaudio-utils*) is used to play a sound to a specified microphone output, which is mapped to a\n      microphone input at startup.\n    - ***paplay*** is triggered and plays a random file from **/home/zoomrec/audio**\n    - Nothing will be played if directory:\n        - does not contain **.wav** files\n        - is not mounted properly\n\n### CSV structure\n\nCSV must be formatted as in example/meetings.csv\n\n- Delimiter must be a semicolon \"**;**\"\n- Only meetings with flag \"**record = true**\" are joined and recorded\n- \"**description**\" is used for filename when recording\n- \"**duration**\" in minutes (+5 minutes to the end)\n\nweekday | time | duration | id | password | description | record\n-------- | -------- | -------- | -------- | -------- | -------- | --------\nmonday | 09:55 | 60 | 111111111111 | 741699 | Important_Meeting | true\nmonday | 14:00 | 90 | 222222222222 | 321523 | Unimportant_Meeting | false\ntuesday| 17:00 | 90 | https://zoom.us/j/123456789?pwd=abc || Meeting_with_URL | true\n\n### VNC\n\nYou can connect to zoomrec via vnc and see what is happening.\n\n#### Connect (default)\n\nHostname | Port | Password\n-------- | -------- | --------\nlocalhost   | 5901   | zoomrec\n\n### Telegram\nZoomrec can notify you via Telegram about starting and ending a recording or if joining a meeting failed. All you need is a bot token and a chat id of a Telegram channel.\n\nAt first [create a new telegram bot](https://core.telegram.org/bots#6-botfather) to get the bot token. After that create a new channel and add the bot with sufficient permissions to write messages in that channel. Finally [get the chat id of your channel](https://gist.github.com/mraaroncruz/e76d19f7d61d59419002db54030ebe35) and look below how to pass your Telegram details to Zoomrec.\n\n### Preparation\n\nTo have access to the recordings, a volume is mounted, so you need to create a folder that container users can access.\n\n**[ IMPORTANT ]**\n\n#### Create folders and set permissions (on Host)\n\n```\nmkdir -p recordings/screenshots\nchown -R 1000:1000 recordings\n\nmkdir -p audio\nchown -R 1000:1000 audio\n```\n\n### Flags\n\n#### Set timezone (default: Europe/Berlin)\n\n```\ndocker run -d --restart unless-stopped \\\n  -e TZ=Europe/Berlin \\\n  -v $(pwd)/recordings:/home/zoomrec/recordings \\\n  -v $(pwd)/example/audio:/home/zoomrec/audio \\\n  -v $(pwd)/example/meetings.csv:/home/zoomrec/meetings.csv:ro \\\n  -p 5901:5901 \\\n  --security-opt seccomp:unconfined \\\nkastldratza/zoomrec:latest\n```\n\n#### Set debugging flag (default: False)\n\n- screenshot on error\n- record joining\n- do not exit container on error\n\n```\ndocker run -d --restart unless-stopped \\\n  -e DEBUG=True \\\n  -v $(pwd)/recordings:/home/zoomrec/recordings \\\n  -v $(pwd)/example/audio:/home/zoomrec/audio \\\n  -v $(pwd)/example/meetings.csv:/home/zoomrec/meetings.csv:ro \\\n  -p 5901:5901 \\\n  --security-opt seccomp:unconfined \\\nkastldratza/zoomrec:latest\n```\n#### Set Telegram details\n```\ndocker run -d --restart unless-stopped \\\n  -e TELEGRAM_BOT_TOKEN=\"YOUR_BOT_TOKEN\" \\\n  -e TELEGRAM_CHAT_ID=\"-100_YOUR_CHAT_ID\" \\\n  -v $(pwd)/recordings:/home/zoomrec/recordings \\\n  -v $(pwd)/example/audio:/home/zoomrec/audio \\\n  -v $(pwd)/example/meetings.csv:/home/zoomrec/meetings.csv:ro \\\n  -p 5901:5901 \\\n  --security-opt seccomp:unconfined \\\nkastldratza/zoomrec:latest\n```\n#### Set Zoom display name \n```\ndocker run -d --restart unless-stopped \\\n  -e DISPLAY_NAME=\"zoomrec\" \\\n  -v $(pwd)/recordings:/home/zoomrec/recordings \\\n  -v $(pwd)/example/audio:/home/zoomrec/audio \\\n  -v $(pwd)/example/meetings.csv:/home/zoomrec/meetings.csv:ro \\\n  -p 5901:5901 \\\n  --security-opt seccomp:unconfined \\\nkastldratza/zoomrec:latest\n```\n### Windows / _cmd_\n\n```cmd\ndocker run -d --restart unless-stopped \\\n  -v %cd%\\recordings:/home/zoomrec/recordings \\\n  -v %cd%\\example\\audio:/home/zoomrec/audio \\\n  -v %cd%\\example\\meetings.csv:/home/zoomrec/meetings.csv:ro \\\n  -p 5901:5901 \\\n  --security-opt seccomp:unconfined \\\nkastldratza/zoomrec:latest\n```\n\n### Windows / _PowerShell_\n\n```powershell\ndocker run -d --restart unless-stopped `\n  -v ${PWD}/recordings:/home/zoomrec/recordings `\n  -v ${PWD}/example/audio:/home/zoomrec/audio `\n  -v ${PWD}/example/meetings.csv:/home/zoomrec/meetings.csv:ro `\n  -p 5901:5901 `\n  --security-opt seccomp:unconfined `\nkastldratza/zoomrec:latest\n```\n\n### Linux / macOS\n\n```bash\ndocker run -d --restart unless-stopped \\\n  -v $(pwd)/recordings:/home/zoomrec/recordings \\\n  -v $(pwd)/example/audio:/home/zoomrec/audio \\\n  -v $(pwd)/example/meetings.csv:/home/zoomrec/meetings.csv:ro \\\n  -p 5901:5901 \\\n  --security-opt seccomp:unconfined \\\nkastldratza/zoomrec:latest\n```\n\n## Customization example\n\n### Add meetings.csv to image\n\n```bash\n# Switch to example directory\ncd example\n\n# Build new image by customized Dockerfile\ndocker build -t kastldratza/zoomrec-custom:latest .\n\n# Run image without mounting meetings.csv and audio directory\n# Linux\ndocker run -d --restart unless-stopped -v $(pwd)/recordings:/home/zoomrec/recordings -p 5901:5901 --security-opt seccomp:unconfined kastldratza/zoomrec-custom:latest\n\n# Windows / PowerShell\ndocker run -d --restart unless-stopped -v ${PWD}/recordings:/home/zoomrec/recordings -p 5901:5901 --security-opt seccomp:unconfined kastldratza/zoomrec-custom:latest\n\n# Windows / cmd\ndocker run -d --restart unless-stopped -v %cd%\\recordings:/home/zoomrec/recordings -p 5901:5901 --security-opt seccomp:unconfined kastldratza/zoomrec-custom:latest\n```\n\n---\n\n## Supported actions\n\n- [x] Show when the next meeting starts\n- [x] _Join a Meeting_ from csv with id and password\n- [x] Wrong error: _Invalid meeting ID_ / **Leave**\n- [x] _Join with Computer Audio_\n- [x] _Please wait for the host to start this meeting._\n- [x] _Please wait, the meeting host will let you in soon._\n- [x] _Enter Full Screen_\n- [x] Switch to _Speaker View_\n- [x] Continuously check: _This meeting is being recorded_ / **Continue**\n- [x] Continuously check: _Hide Video Panel_\n- [x] Continuously check: _This meeting has been ended by host_\n- [x] Quit ffmpeg gracefully on abort\n- [x] _Host is sharing poll results_\n- [x] _This meeting is for authorized attendees only_ / **Leave meeting**\n- [x] Play sound after joining a meeting\n- [x] _Join a Meeting_ from csv with url\n\n---\n\n## Roadmap\n\n- [ ] Refactoring\n- [ ] Create terraform stack to deploy in AWS\n- [ ] _Join a Meeting_ from calendar\n- [ ] _Sign In_ to existing Zoom account\n- [ ] _Join Breakout Room_\n- [ ] Support to record Google Meet, MS Teams, Cisco WebEx calls too\n- [ ] Ability to monitor recordings sessions in various containers\n\n---\n\n## Testing\n\nCreate unittests for different use cases:\n\n- [ ] Join meeting\n- [ ] Start / Stop ffmpeg and check if file was created\n- [ ] ...\n\n---\n\n## Support\n\nFeel free. However, if you want to support me and my work, I have some crypto addresses here.\n\nname | address |\n------------ | ------------- |\nBitcoin (BTC) | \u003cdetails\u003e\u003csummary\u003eshow\u003c/summary\u003e\u003cp\u003e\u003cimg src=\"doc/support/bitcoin.png\" width=\"150\" /\u003e \u003cbr\u003e ```bc1qz2n26d4gq8qjdge9ueeluqut5p0rmv5wjmvnus``` \u003c/p\u003e\u003c/details\u003e\nEthereum (ETH) | \u003cdetails\u003e\u003csummary\u003eshow\u003c/summary\u003e\u003cp\u003e\u003cimg src=\"doc/support/ethereum.png\" width=\"150\" /\u003e \u003cbr\u003e ```0x984dBf7fb4ab489E33ca004552259484041AeF88``` \u003c/p\u003e\u003c/details\u003e\nDogecoin (DOGE) | \u003cdetails\u003e\u003csummary\u003eshow\u003c/summary\u003e\u003cp\u003e\u003cimg src=\"doc/support/dogecoin.png\" width=\"150\" /\u003e \u003cbr\u003e ```DHBCESbBPqER83h5E2j6cw6H1QZW8qHtYd``` \u003c/p\u003e\u003c/details\u003e\nCardano (ADA) | \u003cdetails\u003e\u003csummary\u003eshow\u003c/summary\u003e\u003cp\u003e\u003cimg src=\"doc/support/cardano.png\" width=\"150\" /\u003e \u003cbr\u003e ```addr1q90phcf0qzkx9da8vghtaa04a68gwpat37gvss963r9xfsj7r0sj7q9vv2m6wc3whm6ltm5wsur6hrusepqt4zx2vnpqz307az``` \u003c/p\u003e\u003c/details\u003e\n\n---\n\n## Contributing\n\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkastldratza%2Fzoomrec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkastldratza%2Fzoomrec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkastldratza%2Fzoomrec/lists"}