/*!
* 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
};