async def play_url(self, url, **kwargs): """Play media from an URL on the device. Note: This method will not yield until the media has finished playing. The Apple TV requires the request to stay open during the entire play duration. """ if not self.service: raise exceptions.NotSupportedError("AirPlay service is not available") server = None if os.path.exists(url): _LOGGER.debug("URL %s is a local file, setting up web server", url) server_address = net.get_local_address_reaching(self.config.address) server = StaticFileWebServer(url, server_address) await server.start() url = server.file_address # This creates a new ClientSession every time something is played. # It is not recommended by aiohttp, but it is the only way not having # a dangling connection laying around. So it will have to do for now. session = await net.create_session(self.loop) try: player = await self._player(session) position = int(kwargs.get("position", 0)) self._play_task = asyncio.ensure_future(player.play_url(url, position)) return await self._play_task finally: self._play_task = None await session.close() if server: await server.close()
async def _start_mrp_proxy(loop, args, zconf: Zeroconf): def proxy_factory(): try: proxy = MrpAppleTVProxy(loop, args.remote_ip, args.remote_port, args.credentials) asyncio.ensure_future( proxy.start(), loop=loop, ) except Exception: _LOGGER.exception("failed to start proxy") raise else: return proxy if args.local_ip is None: args.local_ip = str( net.get_local_address_reaching(IPv4Address(args.remote_ip))) _LOGGER.debug("Binding to local address %s", args.local_ip) if not (args.remote_port or args.name): resp = await mdns.unicast(loop, args.remote_ip, ["_mediaremotetv._tcp.local"]) if not args.remote_port: args.remote_port = resp.services[0].port if not args.name: args.name = resp.services[0].name + " Proxy" if not args.name: args.name = DEVICE_NAME # Setup server used to publish a fake MRP server server = await loop.create_server(proxy_factory, "0.0.0.0") port = server.sockets[0].getsockname()[1] _LOGGER.info("Started MRP server at port %d", port) unpublisher = await publish_mrp_service(zconf, args.local_ip, port, args.name) print("Press ENTER to quit") await loop.run_in_executor(None, sys.stdin.readline) return unpublisher
async def _start_mrp_proxy(loop, args, zconf): def proxy_factory(): try: proxy = MrpAppleTVProxy(loop) asyncio.ensure_future( proxy.start(args.remote_ip, args.remote_port, args.credentials), loop=loop, ) except Exception: _LOGGER.exception("failed to start proxy") return proxy if args.local_ip is None: args.local_ip = str( net.get_local_address_reaching(IPv4Address(args.remote_ip))) _LOGGER.debug("Binding to local address %s", args.local_ip) if not (args.remote_port or args.name): resp = await udns.request(loop, args.remote_ip, ["_mediaremotetv._tcp.local"]) if not args.remote_port: args.remote_port = _get_property(resp, udns.QTYPE_SRV, "port") if not args.name: args.name = ( _get_property(resp, udns.QTYPE_TXT, b"Name").decode("utf-8") + " Proxy") if not args.name: args.name = DEVICE_NAME # Setup server used to publish a fake MRP server server = await loop.create_server(proxy_factory, "0.0.0.0") port = server.sockets[0].getsockname()[1] _LOGGER.info("Started MRP server at port %d", port) service = await publish_mrp_service(zconf, args.local_ip, port, args.name) print("Press ENTER to quit") await loop.run_in_executor(None, sys.stdin.readline) return service
async def request( loop: asyncio.AbstractEventLoop, address: str, services: List[str], port: int = 5353, timeout: int = 4, ): """Send request for services to a host.""" if not net.get_local_address_reaching(IPv4Address(address)): raise exceptions.NonLocalSubnetError( f"address {address} is not in any local subnet") transport, protocol = await loop.create_datagram_endpoint( lambda: UnicastDnsSdClientProtocol(services, address, timeout), remote_addr=(address, port), ) try: return await cast(UnicastDnsSdClientProtocol, protocol).get_response() finally: transport.close()
async def play_url(self, url: str, **kwargs) -> None: """Play media from an URL on the device. Note: This method will not yield until the media has finished playing. The Apple TV requires the request to stay open during the entire play duration. """ if not self.service: raise exceptions.NotSupportedError( "AirPlay service is not available") server: Optional[StaticFileWebServer] = None if os.path.exists(url): _LOGGER.debug("URL %s is a local file, setting up web server", url) server_address = net.get_local_address_reaching( self.config.address) server = StaticFileWebServer(url, str(server_address)) await server.start() url = server.file_address connection: Optional[HttpConnection] = None try: # Connect and verify connection to set up encryption connection = await http_connect(str(self.config.address), self.service.port) await verify_connection(self._credentials, connection) player = AirPlayPlayer(connection) position = int(kwargs.get("position", 0)) self._play_task = asyncio.ensure_future( player.play_url(url, position)) return await self._play_task finally: self._play_task = None if connection: connection.close() if server: await server.close()
async def _start_companion_proxy(loop, args, zconf): def proxy_factory(): try: proxy = CompanionAppleTVProxy(loop, args.remote_ip, args.remote_port, args.credentials) asyncio.ensure_future( proxy.start(), loop=loop, ) except Exception: _LOGGER.exception("failed to start proxy") raise else: return proxy if args.local_ip is None: args.local_ip = str( net.get_local_address_reaching(IPv4Address(args.remote_ip))) _LOGGER.debug("Binding to local address %s", args.local_ip) if not args.remote_port: resp = await mdns.unicast(loop, args.remote_ip, ["_companion-link._tcp.local"]) if not args.remote_port: args.remote_port = resp.services[0].port server = await loop.create_server(proxy_factory, "0.0.0.0") port = server.sockets[0].getsockname()[1] _LOGGER.info("Started Companion server at port %d", port) unpublisher = await publish_companion_service(zconf, args.local_ip, port) print("Press ENTER to quit") await loop.run_in_executor(None, sys.stdin.readline) return unpublisher