{"id":51654194,"url":"https://github.com/cca/panopto-archive","last_synced_at":"2026-07-14T07:33:42.386Z","repository":{"id":357472655,"uuid":"1233300418","full_name":"cca/panopto-archive","owner":"cca","description":"Archive Panopto sessions in bulk","archived":false,"fork":false,"pushed_at":"2026-07-13T21:19:11.000Z","size":146,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-13T23:11:42.277Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cca.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T20:09:40.000Z","updated_at":"2026-07-13T21:19:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cca/panopto-archive","commit_stats":null,"previous_names":["cca/panopto-archive"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cca/panopto-archive","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cca%2Fpanopto-archive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cca%2Fpanopto-archive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cca%2Fpanopto-archive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cca%2Fpanopto-archive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cca","download_url":"https://codeload.github.com/cca/panopto-archive/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cca%2Fpanopto-archive/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35451878,"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-07-14T02:00:06.603Z","response_time":114,"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":[],"created_at":"2026-07-14T07:33:41.295Z","updated_at":"2026-07-14T07:33:42.376Z","avatar_url":"https://github.com/cca.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Archive Panopto Sessions\n\nPanopto provides no way to bulk download sessions. This is a simple command-line tool for downloading sessions and their corresponding metadata. We want to:\n\n- ✅ Traverse the Panopto folder hierarchy starting at a given point\n- (TODO) Filter through sessions according to criteria (e.g. an option to not download private sessions)\n- ✅ Download video \u0026 caption files\n- ❌ Confirm videos transferred successfully using content hashes\n- ❓ Push the video files to cloud storage\n- ✅ Retain the video metadata alongside the sessions\n- ✅ Mirror the Panopto folder hierarchy in cloud storage\n\n## Setup\n\n### Create an OAuth2 Client\n\n- Panopto admin goes to System \u003e [OAuth2 Clients](https://ccarts.hosted.panopto.com/Panopto/Pages/Admin/OauthClients/List.aspx#)\n- **New** \u003e make it a  server-side client\\*\n- CORS URL: `http://localhost` \u0026 Redirect URL: `http://localhost:9127/redirect`\n- Copy the client ID and secret into the `.env` file (see example.env)\n\n\\* This fake server-side weirdness is how the Panopto OAuth2 example was designed and could be avoided by rewriting it.\n\n###\n\n```sh\nuv sync\n# test (no downloads) with \"CCA Departments\" folder ID\nuv run panochive --test c117dc01-bc96-4eca-a53a-ace50173fb6e\n```\n\n`mise` is also used to autoload the `.env` file and manage the python version, but these could be done manually, e.g. `export SERVER=ccarts.hosted.panopto.com` etc...\n\n## Usage\n\n```sh\n# download Panopto folder to local \"dest\" folder (data by default)\nuv run panochive de58c934-a306-4aea-95c8-b45601224869 --dest path/to/dest\n# recursively download everything in a portion of the folder hierarchy\nuv run panochive -r de58c934-a306-4aea-95c8-b45601224869\n```\n\n### Skip Folders\n\nWhile recursing through the folder hierarchy, the `--skip-list` option or `SKIP_LIST` env var takes a JSON file containing an array of folder names or UUIDs to skip. We can skip specific folders we know we do not want to dwownload, e.g. due to privacy (\"Faculty Affairs \u0026 Records\") or copyright concerns (\"Catalog Media\").\n\n### Copy to S3\n\nThere is light wrapper around `aws s3 sync`, see `uv run sync --help` for details. In general, prefer using this tool rather than running aws commands manually to have some assurance and a consistent storage class. Set the name of the AWS bucket as an `AWS_ARCHIVE_BUCKET` env var. Examples:\n\n```sh\nuv run sync ./data Libraries --dry-run # see s3 paths before uploading\nuv run sync ./data \"CCA Departments\" # sync to s3://BUCKET/CCA Departments/...\nuv run sync ./data --quiet # no awscli output\n```\n\n### Copy to GCP\n\nGenerally, prefer using the archive S3 bucket above, but if for some reason we want to use GCP.\n\nOnce downloaded, we can copy the files from their \"dest\" (data) folder to GCP using `gcloud storage cp`. Make sure to preserve the Panopto folder hierarchy, e.g. if you download ROOT/Libraries/CAPL Archive then the folder locally will be data/CAPL Archive. If you copy that to GCP, put it where it belongs under \"Libraries\", not in the bucket's root.\n\n```sh\nuv run panochive FOLDER_ID\ngcloud storage cp --recursive \"data/CAPL Archive\" \"gs://panopto_archive/Libraries\"\n```\n\n## Development\n\n```sh\nuv run pytest src/panochive/tests # test\nuv run ruff format src/panochive # formatting\nuv run ruff check src/panochive # type checking and linting\n```\n\n## License\n\nECL-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcca%2Fpanopto-archive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcca%2Fpanopto-archive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcca%2Fpanopto-archive/lists"}