/*! * artplayer-plugin-chromecast.js v1.1.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ function loadScript(src) { return new Promise((resolve, reject) => { const script = document.createElement("script"); script.src = src; script.onload = resolve; script.onerror = reject; document.body.appendChild(script); }); } function getMimeType(url) { const extension = url.split("?")[0].split("#")[0].split(".").pop().toLowerCase(); const mimeTypes = { mp4: "video/mp4", webm: "video/webm", ogg: "video/ogg", ogv: "video/ogg", mp3: "audio/mp3", wav: "audio/wav", flv: "video/x-flv", mov: "video/quicktime", avi: "video/x-msvideo", wmv: "video/x-ms-wmv", mpd: "application/dash+xml", m3u8: "application/x-mpegURL" }; return mimeTypes[extension] || "application/octet-stream"; } function artplayerPluginChromecast(option) { const DEFAULT_ICON = ``; const DEFAULT_SDK = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"; let isCastInitialized = false; let castSession = null; let castState = null; const updateCastButton = (state) => { const button = document.querySelector(".art-icon-cast"); if (button) { switch (state) { case "connected": button.style.color = "red"; break; case "connecting": case "disconnecting": button.style.color = "orange"; break; case "disconnected": default: button.style.color = "white"; break; } } }; const initializeCastApi = () => { return new Promise((resolve, reject) => { window.__onGCastApiAvailable = (isAvailable) => { if (isAvailable) { const context = window.cast.framework.CastContext.getInstance(); context.setOptions({ receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, autoJoinPolicy: window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED }); context.addEventListener( window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED, (event) => { const SessionState = window.cast.framework.SessionState; castState = event.sessionState; castSession = event.session; switch (event.sessionState) { case SessionState.NO_SESSION: option.onStateChange?.("disconnected"); updateCastButton("disconnected"); break; case SessionState.SESSION_STARTING: option.onStateChange?.("connecting"); updateCastButton("connecting"); break; case SessionState.SESSION_STARTED: option.onStateChange?.("connected"); updateCastButton("connected"); break; case SessionState.SESSION_ENDING: option.onStateChange?.("disconnecting"); updateCastButton("disconnecting"); break; case SessionState.SESSION_RESUMED: option.onStateChange?.("connected"); updateCastButton("connected"); break; } } ); context.addEventListener(window.cast.framework.CastContextEventType.CAST_STATE_CHANGED, (event) => { const CastState = window.cast.framework.CastState; switch (event.castState) { case CastState.NO_DEVICES_AVAILABLE: option.onCastAvailable?.(false); break; case CastState.NOT_CONNECTED: option.onCastAvailable?.(true); break; case CastState.CONNECTING: case CastState.CONNECTED: option.onCastAvailable?.(true); break; } }); isCastInitialized = true; resolve(); } else { reject(new Error("Cast API is not available")); } }; if (!window.chrome || !window.chrome.cast) { loadScript(option.sdk || DEFAULT_SDK).catch(reject); } }); }; const castVideo = (art, session) => { const url = option.url || art.option.url; const mediaInfo = new window.chrome.cast.media.MediaInfo(url, option.mimeType || getMimeType(url)); const request = new window.chrome.cast.media.LoadRequest(mediaInfo); session.loadMedia(request).then(() => { art.notice.show = "Casting started"; option.onCastStart?.(); }).catch((error) => { art.notice.show = "Error casting media"; option.onError?.(error); throw error; }); }; return async (art) => { art.controls.add({ name: "chromecast", position: "right", tooltip: "Chromecast", html: `${option.icon || DEFAULT_ICON}`, click: async () => { if (!isCastInitialized) { try { await initializeCastApi(); } catch (error) { art.notice.show = "Failed to initialize Cast API"; option.onError?.(error); throw error; } } const context = window.cast.framework.CastContext.getInstance(); if (castSession) { castVideo(art, castSession); } else { try { const session = await context.requestSession(); castVideo(art, session); } catch (error) { art.notice.show = "Error connecting to cast session"; option.onError?.(error); throw error; } } } }); return { name: "artplayerPluginChromecast", getCastState: () => castState, isCasting: () => castSession !== null }; }; } export { artplayerPluginChromecast as default };