(function (root, factory) { const CastService = factory(); if (typeof module === 'object' && module.exports) module.exports = CastService; if (root) root.CastService = CastService; })(typeof globalThis !== 'undefined' ? globalThis : this, function () { class CastService { constructor(video) { this.video = video || null; this.listeners = new Set(); this.availabilityWatchId = null; this.state = { status: 'unsupported', available: false, type: 'unsupported', error: '' }; this.handleRemoteConnect = () => this.setState({ status: 'connected', available: true }); this.handleRemoteDisconnect = () => this.setState({ status: 'available', available: true }); this.handleAirPlayAvailability = event => this.setState({ status: event?.availability === 'available' ? 'available' : 'unavailable', available: event?.availability === 'available', type: 'airplay' }); this.handleAirPlayState = () => this.setState({ status: this.video?.webkitCurrentPlaybackTargetIsWireless ? 'connected' : 'available', available: true, type: 'airplay' }); this.attachStateEvents(); } attachStateEvents() { this.video?.remote?.addEventListener?.('connect', this.handleRemoteConnect); this.video?.remote?.addEventListener?.('disconnect', this.handleRemoteDisconnect); this.video?.addEventListener?.('webkitplaybacktargetavailabilitychanged', this.handleAirPlayAvailability); this.video?.addEventListener?.('webkitcurrentplaybacktargetiswirelesschanged', this.handleAirPlayState); } setState(update) { this.state = { ...this.state, ...update }; this.listeners.forEach(listener => listener({ ...this.state })); } subscribe(listener) { if (typeof listener !== 'function') return () => {}; this.listeners.add(listener); listener({ ...this.state }); return () => this.listeners.delete(listener); } async watchAvailability() { const remote = this.video?.remote; if (remote && typeof remote.watchAvailability === 'function') { this.setState({ status: 'unavailable', available: false, type: 'remote-playback', error: '' }); try { this.availabilityWatchId = await remote.watchAvailability(available => { this.setState({ status: available ? 'available' : 'unavailable', available: Boolean(available), type: 'remote-playback', error: '' }); }); return this.state; } catch (error) { if (typeof this.video?.webkitShowPlaybackTargetPicker !== 'function') { this.setState({ status: 'unavailable', available: false, type: 'remote-playback', error: error?.message || '' }); return this.state; } } } if (typeof this.video?.webkitShowPlaybackTargetPicker === 'function') { this.setState({ status: 'available', available: true, type: 'airplay', error: '' }); return this.state; } this.setState({ status: 'unsupported', available: false, type: 'unsupported', error: '' }); return this.state; } async prompt() { if (this.state.type === 'remote-playback' && typeof this.video?.remote?.prompt === 'function') { this.setState({ status: 'connecting', error: '' }); try { await this.video.remote.prompt(); const connected = this.video.remote.state === 'connected'; this.setState({ status: connected ? 'connected' : (this.state.available ? 'available' : 'unavailable') }); return true; } catch (error) { this.setState({ status: this.state.available ? 'available' : 'unavailable', error: error?.message || 'Unable to open device picker.' }); throw error; } } if (this.state.type === 'airplay' && typeof this.video?.webkitShowPlaybackTargetPicker === 'function') { this.video.webkitShowPlaybackTargetPicker(); return true; } return false; } destroy() { if (this.availabilityWatchId !== null) { this.video?.remote?.cancelWatchAvailability?.(this.availabilityWatchId).catch?.(() => {}); } this.video?.remote?.removeEventListener?.('connect', this.handleRemoteConnect); this.video?.remote?.removeEventListener?.('disconnect', this.handleRemoteDisconnect); this.video?.removeEventListener?.('webkitplaybacktargetavailabilitychanged', this.handleAirPlayAvailability); this.video?.removeEventListener?.('webkitcurrentplaybacktargetiswirelesschanged', this.handleAirPlayState); this.listeners.clear(); } } return CastService; });