{"id":17933976,"url":"https://github.com/graphaelli/zat","last_synced_at":"2025-08-27T13:19:55.411Z","repository":{"id":46651346,"uuid":"227686026","full_name":"graphaelli/zat","owner":"graphaelli","description":"Zoom Archive Tool","archived":false,"fork":false,"pushed_at":"2022-10-02T17:43:58.000Z","size":73,"stargazers_count":26,"open_issues_count":5,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-30T00:07:33.927Z","etag":null,"topics":["google","google-drive","zoom"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphaelli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-12T19:59:37.000Z","updated_at":"2024-06-24T07:17:56.000Z","dependencies_parsed_at":"2022-08-29T21:20:10.907Z","dependency_job_id":null,"html_url":"https://github.com/graphaelli/zat","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/graphaelli/zat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphaelli%2Fzat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphaelli%2Fzat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphaelli%2Fzat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphaelli%2Fzat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphaelli","download_url":"https://codeload.github.com/graphaelli/zat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphaelli%2Fzat/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267399953,"owners_count":24081173,"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","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"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":["google","google-drive","zoom"],"created_at":"2024-10-28T21:42:36.039Z","updated_at":"2025-07-27T18:03:34.091Z","avatar_url":"https://github.com/graphaelli.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zoom Archive Tool\n\nCopies Zoom recordings to Google Drive.\n\n## Why\n\n* Improve discoverability of Zoom recordings\n* Preserve recordings when Zoom user leaves the org\n* Reduce cost of long term retention (maybe)\n\n## How\n\n`zat` requires `go` to build - 1.13+ is recommended, for proper error formatting, but will work with older versions.\n\n```\n$ go build .\n$ ./zat\n```\n\n`zat` should start without any configuration but isn't very useful without credentials - see below for setup.\n\n`zat` will persist tokens to disk at `google.creds.json` and `zat.creds.json` - be sure to guard those files carefully as permissions are necessarily wide.\n\nOnce tokens have been obtained, `zat -no-server` will perform only archival duties and then exit.\n\n`zat` always attempts to archive, to only start the web server use: `-since 0s`.\n\n### Credentials\n\n* Obtain Google credentials\n  * [Create an Oauth Client ID credential](https://console.cloud.google.com/apis/credentials)\n    * You may need to create a project, or use a dev project you have access to. If the project doesn't have OAuth consent screen info, you'll need to add that as well.\n      * Choose \"internal\" user type, give it a name similar to the project name, and add your contact email\n    * Choose \"Web application\" as the client ID type\n    * Set Authorized redirect URIs to `http://localhost:8080/oauth/google`\n  * Save credentials to `google.config.json` (GCP Console \u003e API \u0026 Services \u003e Credentials \u003e Download JSON)\n\n* Obtain Zoom credentials\n  * [Create an Oauth Application](https://marketplace.zoom.us/develop/create)\n    * User-managed\n    * No need to publish\n    * Set name, descriptions, and contact information\n    * Add the `recording:read` scope \n    * Set redirect URI to `http://127.0.0.1.ip.es.io:8080/oauth/zoom` and also add it to Whitelisted URLs\n    * \n  * Save credentials to `zoom.config.json` with content:\n    ```json\n    {\n      \"id\":             \"your-id\",\n      \"secret\":         \"your-secret\",\n      \"oauth_redirect\": \"http://127.0.0.1.ip.es.io:8080/oauth/zoom\"\n    }\n    ```\n* [Optional] Obtain Slack credentials\n  * [Create an App](https://api.slack.com/apps?new_app=1)\n    * Add Permissions \u003e Scopes \u003e Bot Token Scopes \u003e Add An Oauth Scope granting: `channels:read`, `chat:write`, `chat:write.public`\n  * Save the Bot User OAuth Access Token (under OAuth \u0026 Permissions) to `slack.config.json` with content:\n    ```json\n    {\n      \"token\":             \"your-token\"\n    }\n    ```\n\nOnce the credentials are in place, re-run `zat` and use the web server at http://localhost:8080/ to login to both Google and Zoom to create the `*.creds.json` files zat will use for the next run.\n\n### Configuration\n\n* Configure zat\n\nCreate zat.yml like:\n\n```yaml\n- name: UI Weekly\n  google: DpB3XhhzV87LfEeLrM-nCopTtHDWxqVGH\n  zoom: 023-456-789\n- name: Team Weekly\n  google: DpB3XhhzV87LfEeLrM-nCopTtHDWxqVGH\n  zoom: 123-456-789\n```\n\nWhere `google` is the folder ID to store recordings into, and `zoom` is the meeting id (hyphens or no hyphens, not spaces).\n\n#### Google\n\nThe google configuration is the ID of the folder where the recordings will be stored.\n\n`cmd/google/findfolders` can assist in tracking down folders and IDs like:\n\n```\n$ go build ./cmd/google/findfolders\n$ ./findfolders -query 'name = \"bar\"'\nfoo                                                          DpB3XhhzV87LfEeLrM-nCopTtHDWxqVGH https://drive.google.com/drive/folders/DpB3XhhzV87LfEeLrM-nCopTtHDWxqVGH\n$ ./findfolders -query '\"DpB3XhhzV87LfEeLrM-nCopTtHDWxqVGH\" in parents and name = \"Meetings\"'\nMeetings                                                     ycMAKmDuzwobv6eBf9-PLupEGJJ6BtyoJ https://drive.google.com/drive/folders/ycMAKmDuzwobv6eBf9-PLupEGJJ6BtyoJ\n```\n\nYou'll likely get an \"Access Not Configured\" error for new projects. Follow the URL in the error to ensure the project is enabled for Google Drive API access, then wait a few minutes before retrying.\n\nzat provides a web interface with similar functionality, eg [http://localhost:8080/google?q=name contains \"Team weekly\"](http://localhost:8080/google?q=name%20contains%20%27Team%20weekly%27).\n\n#### Zoom\n\nThe zoom configuration is the meeting ID - the dashes are optional.\n\n`cmd/zoom/listrecordings` can assist in tracking down meeting IDs like:\n\n```\n$ go build ./cmd/zoom/listrecordings\n$ ./listrecordings -since 96h\n2019/11/25 12:22:54 listrecordings.go:41: 2 recordings found\n2019-11-21 945106202 UI Weekly\n\taudio_transcript https://zoom.us/recording/download/wwww\n\tshared_screen_with_speaker_view https://zoom.us/recording/download/xxxx\n\tchat_file https://zoom.us/recording/download/yyyy\n\taudio_only https://zoom.us/recording/download/zzzz\n\ttimeline https://zoom.us/recording/download/11111111-1111-1111-1111-111111111111\n2019-11-21 906290321 Team Weekly\n\taudio_transcript https://zoom.us/recording/download/aaaa\n\tshared_screen_with_speaker_view https://zoom.us/recording/download/bbbb\n\tchat_file https://zoom.us/recording/download/cccc\n\taudio_only https://zoom.us/recording/download/dddd\n\ttimeline https://zoom.us/recording/download/22222222-2222-2222-2222-222222222222\n```\n\nzat provides a web interface with similar functionality at http://localhost:8080/zoom.\n\n#### Slack\n\nThe slack configuration is the ID of the channel where the message should be sent.\n\n`cmd/slack/listchannels` can assist in tracking down channel IDs like:\n\n```\n$ go build ./cmd/slack/listchannels\n$ ./listchannels\nCAAAAAAAA general\nCAAAAAAAB zat\n```\n\nOne method for finding private channel IDs is to open Slack in a web browser and look at `$$('.p-channel_sidebar__static_list__item')` elements.\nThe application's bot user will need to be invited to the private channel to post messages there.\n\n`cmd/slack/chat` can assist in verifying permissions are correct.\n\n#### Scheduling\n\nOn macOS pre-10.15 (Catalina) and Linux, `cron` is sufficient, eg:\n\n```\n0 8,10,15,22 * * * zat -no-server -config-dir ~/path/to/zat/config/dir\n```\n\nOn macOS 10.15+, new security restrictions make `cron` less attractive.\n\nInstead use `launchd`.\nA sample configuration is included under `contrib/`.\nLoad it with:\n```\nlaunchctl load contrib/zat.plist\n```\n\nIf prompted the first time the job runs, grant `zat` access to the config directory.\n\n## Also\n\n* Zoom doesn't look back farther than 30 days when `-since` is \u003e 30 days. - [#16](https://github.com/graphaelli/zat/issues/16)\n* [#34](https://github.com/graphaelli/zat/issues/34) introduced the `-t` option to limit the file types archived by zat.  You might consider running `zat` with `-t mp4,chat` as the rest of the files aren't that interesting.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphaelli%2Fzat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphaelli%2Fzat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphaelli%2Fzat/lists"}