{"id":15655647,"url":"https://github.com/torxed/chromecast","last_synced_at":"2026-02-01T23:02:29.523Z","repository":{"id":150500683,"uuid":"298898418","full_name":"Torxed/chromecast","owner":"Torxed","description":"As vanilla as it gets, cast a YouTube (or custom) video to a Chromecast","archived":false,"fork":false,"pushed_at":"2020-09-27T16:44:32.000Z","size":310,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-17T22:43:23.202Z","etag":null,"topics":["cast","chromecast","custom","mp4","python","vanilla","youtube"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Torxed.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-26T20:58:12.000Z","updated_at":"2024-01-29T03:26:58.000Z","dependencies_parsed_at":"2023-04-25T05:48:22.875Z","dependency_job_id":null,"html_url":"https://github.com/Torxed/chromecast","commit_stats":{"total_commits":24,"total_committers":1,"mean_commits":24.0,"dds":0.0,"last_synced_commit":"e6d5afa720b93b30d24e63219d5005f5d2f56713"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Torxed/chromecast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Torxed%2Fchromecast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Torxed%2Fchromecast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Torxed%2Fchromecast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Torxed%2Fchromecast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Torxed","download_url":"https://codeload.github.com/Torxed/chromecast/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Torxed%2Fchromecast/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28993749,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T22:01:47.507Z","status":"ssl_error","status_checked_at":"2026-02-01T21:58:37.335Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cast","chromecast","custom","mp4","python","vanilla","youtube"],"created_at":"2024-10-03T13:00:13.254Z","updated_at":"2026-02-01T23:02:29.507Z","avatar_url":"https://github.com/Torxed.png","language":"Python","readme":"# chromecast\nAs vanilla as it gets, cast a youtube *(or custom)* video to a chromecast without any dependencies *(No Google or Google-ProtoBuf libs required)*\n\n- [Dependencies](#dependencies)\n- [Usage](#usage)\n- [Note on ProtoBuf, chromecast and alternatives](#note-on-protobuf-chromecast-and-alternatives)\n  * [Protobuf in general](#protobuf-in-general)\n    + [`INT` variables](#int-variables-with-a-field-id-of-5)\n    + [`string` variables](#string-example-with-a-payload-and-field-id-of-3)\n  * [Chromecast specifics](#chromecast-specifics)\n    + [protocol_version](#protocol_version)\n    + [source_id](#source_id)\n    + [destination_id](#destination_id)\n    + [namespace](#namespace)\n    + [payload_type](#payload_type)\n    + [payload_utf8](#payload_utf8)\n- [Honorable mentions](#honorable-mentions)\n\n# Dependencies\n\nNone! this script is written in pure vanilla Python 3+.\n\n# Usage\n\n    python chromecast.py \u003cip to chromecast\u003e \u003cYouTube video id\u003e\n\nFor instance:\n\n    python chromecast.py 192.168.0.10 ZTidn2dBYbY\n\nOr feed a custom mp4 URL to the script *(Currently mp4 is a hardcoded header until I figure something out)*:\n\n    python chromecast.py 192.168.0.10 http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\n\n*Note:* To find your chromecasts, you can use `avahi-browse -tr _googlecast._tcp` or `nmap --open -sS -Pn -n -p 8009 192.168.0.0/24` *(Replace the subnet with your own and look for `8009/tcp open`)*.\n\n# Note on ProtoBuf, chromecast and alternatives\n\nTwo things. The first being - just use [pychromecast](https://github.com/home-assistant-libs/pychromecast) or [casttube](https://github.com/ur1katz/casttube). They're more fully fledged.\u003cbr\u003e\n\nSecondly, Google heavily uses their open protocol called [protobuf](https://developers.google.com/protocol-buffers/docs/encoding).\u003cbr\u003e\nIt's essentially just a `struct` -\u003e `bytes` serializer. I've included a very crude serializer \u0026 de-serializer for sending and reading protobuf streams. A quick overview of how that works would be:\n\n## Protobuf in general\n\n    Variable type overview:\n    | \u003cfield ID\u003e | \u003cVariable Type\u003e | \u003cVariable Data\u003e |\n\nBelow are two examples describing the most common variables found in a chromecast session.\n\n### `INT` variables with a field ID of 5:\n\n\t| 00101 | 000 | 0001 1000 |\n\nThe value of this integer would be `24`, and it's up to the developer to define what field `5` should be.\u003cbr\u003e\nIn chromecast world, that's `payload_type`, so that would normally have a int value of `0` for `utf8` string payload.\n\n### `string` example with a payload and field ID of 3:\n\n\t| 00011 | 010 | 0001 0011 | {\"type\": \"CONNECT\"}\n\nThe field ID *(`00011`)* is 3. And the variable type *(`010`)* is `string`.\u003cbr\u003e\nThe length of the string is the next byte, which in this case is 19 *(`0001 0011`)*.\n\nThe payload is `{\"type\": \"CONNECT\"}`. That's the basics of ProtoBuf.\n\n## Chromecast specifics\n\nChromecast has a set of fields that needs to be defined in a ProtoBuf format.\u003cbr\u003e\nThose fields are:\n\n * protocol_version `::int`\n * source_id `::str`\n * destination_id `::str`\n * namespace `::str`\n * payload_type `::int`\n * payload_utf8 `::str`\n\nAnd the order is very important. Because the field_id is in the data stream and they need to come in a certain order to match on both sides.\n\nThe names however can be anything, but the type - meaning - and order is important.\u003cbr\u003e\nBut the names are just for your convenience and you can decide to name them whatever you want.\n\n### protocol_version\n\nProtocol version just tells chromecast which protocol to talk. Currently that's `v2.1.0` which is represented by the int `0`. So a lonely ZERO (0) defines that.\n\n### source_id\n\nSource ID is the sender *(or caster's)* id. This can *probably (!?)* be anything you want.\u003cbr\u003e\nBut in reality the magic keyword of `sender-0` seams to do the trick.\n\n### destination_id\n\nThis field changes depending on what casting-state you're in.\u003cbr\u003e\nIt starts off with the magic keyword of `receiver-0` but once an application has been launched,\nthis should be changed to whatever the instance-id is of that application - letting the chromecast know you're talking to the application and not the chromecast.\n\nThere's also a magic keyword `Tr@n$p0rt-0` which feels like an odd design choice. But is used by the chromecast to send heartbeat information in the shape of `{\"type\":\"PING\"}` with the sender and receiver-id's being `Tr@n$p0rt-0`. Not sure why, seams like an odd implementation thing.\n\n### namespace\n\nNamespace is the URN *(or URI/URL if you're more familiar with those terms)* in which you want to call or talk to. Lets say you want to talk to the YouTube app, you need a namespace URN of: `urn:x-cast:com.google.youtube.mdx` in order to let the chromecast know you want to talk to the YouTube app. All applications have their own URN's, and I don't know how you can find those other than [finding URN's in other libraries](https://github.com/home-assistant-libs/pychromecast/blob/0c1d904ab15b91922c8ac45cb7e6641201910578/pychromecast/controllers/plex.py#L178) or listening for the `namespaces` response when launching an app *(which requires you to know an app ID to launch)*.\n\n### payload_type\n\nThe payload type can be two different types, either `bytes` or `utf8` strings. I think chromecast supports both. But sticking to `utf8` strings are quite simple and works for most cases talking to the youtube and the generic media app heh. So keep the type `0` for `utf8` strings *(`1` for `bytes` payloads as a reference)*.\n\n### payload_utf8\n\nThe payload contains the actual data being sent back and fourth for parsing.\u003cbr\u003e\nFor instance, the `{\"type\": \"CONNECT\"}` payload is meant to connect a session to the chromecast or an app on the chromecast.\n\n`{\"type\": \"PING\"}` is another common one that should be replied with `{\"type\": \"PONG\"}`.\nThe different data payloads, in which order they come/should be sent can be seen in this very crude flowchart:\n\n![flowchart](flowchart.png)\n\n# Honorable mentions\n\n * [Perth Linux User Group](http://plug.org.au/)'s [talk from 2016](https://docs.google.com/presentation/d/1X1BdFunVnLkF7L0BgevH2zzkcSe0_gtdTJ_pMdEuakQ/htmlpresent).\n * [pychromecast](https://github.com/home-assistant-libs/pychromecast) Which had a lot of `URN`'s that could be re-used.\n * [casttube](https://github.com/ur1katz/casttube) Which had all the YouTube Web-API's to manage a YouTube lounge.\n * Google for making the [ProtoBuf](https://developers.google.com/protocol-buffers/docs/encoding) protocol very open and easy to deconstruct.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftorxed%2Fchromecast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftorxed%2Fchromecast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftorxed%2Fchromecast/lists"}