Created
December 2, 2019 02:55
-
-
Save cetaSYN/5945118a152b6132fc3eba969c2a5206 to your computer and use it in GitHub Desktop.
Casts a YouTube video to multiple Google Cast devices within a multicast domain.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
#################################################################################### | |
# allcast_cli.py # | |
# Casts a specified YouTube video to Google Cast devices within a subdomain. [CLI] # | |
#################################################################################### | |
from zeroconf import ServiceBrowser, Zeroconf | |
from time import sleep | |
from argparse import ArgumentParser | |
import re | |
import requests | |
from ipaddress import IPv4Address | |
parser = ArgumentParser(description='Cast a YouTube video to all specified Chromecast devices.') | |
parser.add_argument('video', help='YouTube video to be played. ex: E8y3eDUMb4Q') | |
parser.add_argument('--filter', '-f', | |
help='Regular expression (regex), to filter names to cast to (based upon mDNS txt fn)') | |
parser.add_argument('--duration', '-d', type=int, | |
help='Duration to continue scanning for castable devices and pushing the video. 0=Forever') | |
parser.add_argument('--sync', '-s', action='store_true', | |
help='Cast to all discovered devices simultaneously ' | |
'when duration expires, instead of upon-discovery.') | |
args = parser.parse_args() | |
# Make sure duration is greater than 0, with a default value of 10 | |
if not args.duration: | |
args.duration = 10 | |
if args.duration < 0: | |
parser.error('Duration must be 0 or greater.') | |
# Make sure that if syncing is enabled, there is a duration set greater than 0 | |
if args.sync: | |
if args.duration == 0: | |
parser.error('Cannot use sync option when duration is 0.') | |
# If we're using regex filters, make sure they're valid and compile them | |
if args.filter: | |
try: | |
filter_regex = re.compile(args.filter) | |
except re.error: | |
parser.error('Filter regex is invalid.') | |
class ServiceListener(object): | |
# Called when a service is discovered | |
def add_service(self, zeroconf, type, name): | |
info = zeroconf.get_service_info(type, name) | |
# fn: Device's human name | |
fn = str(info.properties[b'fn']) | |
# rs: Content currently casted by device | |
# rs = str(info.properties[b'rs']) | |
if not args.filter or (args.filter and filter_regex.search(fn)): | |
if not args.sync: | |
cast_to_device(name, info) | |
else: | |
save_to_cast_list(name, info) | |
else: | |
print(u"Ignoring {0} ({1}) -- {2}".format(name, IPv4Address(info.address), fn[2:-1])) | |
# Cast to a specified device | |
def cast_to_device(name, info): | |
fn = str(info.properties[b'fn']) | |
print(u"Casting to {0} ({1}) -- {2}".format(name, IPv4Address(info.address), fn[2:-1])) | |
data = {'v': args.video} | |
r = requests.post("http://{0}:8008/apps/YouTube".format(IPv4Address(info.address)), data=data) | |
# If response code falls in the 200 block, it's successful. Otherwise, print an error code. | |
if 200 > r.status_code >= 300: | |
print("{0} - {1}".format(r.status_code, r.reason)) | |
# Save a device to a list for syncronized casting | |
def save_to_cast_list(name, info): | |
fn = str(info.properties[b'fn']) | |
print(u"Saving {0} ({1}) -- {2}".format(name, IPv4Address(info.address), fn[2:-1])) | |
cast_list.append((name, info)) | |
# Start of main processing | |
cast_list = list() | |
zeroconf = Zeroconf() | |
ServiceBrowser(zeroconf, "_googlecast._tcp.local.", ServiceListener()) | |
if args.duration > 0: | |
sleep(args.duration) | |
else: | |
input("Press Enter to exit.\n") | |
# If synchronizing, cast to all saved devices before closing | |
if args.sync: | |
for name, info in cast_list: | |
cast_to_device(name, info) | |
print('Closing...') | |
zeroconf.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Written to help pseudo-sync a video to all TVs in an office in early 2018.