vue3-ytframe
Version:
A Vue3 YouTube Iframe API Wrapper Component
351 lines (350 loc) • 8.04 kB
JavaScript
import { createElementBlock as e, defineComponent as t, onBeforeUnmount as n, onMounted as r, openBlock as i, ref as a, watch as o } from "vue";
//#region lib/constants.ts
var s = /^[a-zA-Z0-9_-]{11}$/, c = /^(www\.|m\.)/, l = /^\/(?:embed|shorts|live|v)\/([a-zA-Z0-9_-]{11})/, u = "https://www.youtube.com/iframe_api";
function d(e, t) {
let n, r = (...r) => {
n && clearTimeout(n), n = setTimeout(() => {
n = void 0, e(...r);
}, t);
};
return r.cancel = () => {
n && clearTimeout(n), n = void 0;
}, r;
}
function f(e) {
if (!e || typeof e != "string") return null;
let t;
try {
t = new URL(e.trim());
} catch {
return null;
}
if (t.protocol !== "http:" && t.protocol !== "https:") return null;
let n = t.hostname.replace(c, ""), r = t.pathname;
if (n === "youtu.be") {
let e = r.slice(1).split("/")[0];
return s.test(e) ? e : null;
}
if (n === "youtube.com" || n === "youtube-nocookie.com") {
if (r === "/watch") {
let e = t.searchParams.get("v");
return e && s.test(e) ? e : null;
}
let e = l.exec(r);
if (e) return e[1];
}
return null;
}
//#endregion
//#region lib/VueYtframe.vue?vue&type=script&setup=true&lang.ts
var p = ["id"], m = /* @__PURE__ */ t({
__name: "VueYtframe",
props: {
videoId: { default: null },
videoUrl: { default: null },
width: { default: "100%" },
height: { default: "100%" },
playerVars: { default: () => ({}) }
},
emits: [
"ready",
"playing",
"paused",
"ended",
"stateChange",
"playbackQualityChange",
"playbackRateChange",
"error",
"apiChange"
],
setup(t, { expose: s, emit: c }) {
let l = t, m = c, h = a(null), g = a(""), _ = a(!1), v, y = d(x, 300), b = d(ee, 500);
o([() => l.width, () => l.height], ([e, t]) => {
h.value && h.value.setSize(Number(e), Number(t));
}), o(() => l.videoId, (e) => y(e)), o(() => l.videoUrl, (e) => b(e));
function x(e) {
C(), !(!_.value || !e) && S(e);
}
function ee(e) {
if (C(), !_.value || !e) return;
let t = f(e);
t && S(t);
}
function S(e) {
if (!h.value) {
O();
return;
}
let t = {
videoId: e,
startSeconds: l.playerVars?.start || 0,
endSeconds: l.playerVars?.end || void 0
};
l.playerVars?.autoplay === 1 ? h.value.loadVideoById(t) : h.value.cueVideoById(t);
}
function C() {
let { videoId: e, videoUrl: t } = l;
if (!e && !t) {
_.value = !1;
return;
}
if (!e && t && !f(t)) {
_.value = !1, `${t}`;
return;
}
_.value = !0;
}
let w = 0;
function T() {
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? `ytframe-${crypto.randomUUID()}` : `ytframe-${(++w).toString(36)}`;
}
r(() => {
g.value = T(), C(), E(), D().then(() => {
_.value && O();
}).catch((e) => (e.message, void 0));
}), n(() => {
y.cancel(), b.cancel(), v && clearTimeout(v), h.value &&= (h.value.destroy(), null);
});
function E() {
if (window.YT && window.YT.Player || document.querySelector("script[src=\"https://www.youtube.com/iframe_api\"]")) return;
let e = document.createElement("script");
e.src = u, document.head.appendChild(e);
}
function D() {
return new Promise((e, t) => {
let n = Date.now(), r = () => {
if (window.YT && window.YT.Player) {
e();
return;
}
if (Date.now() - n > 1e4) {
t(/* @__PURE__ */ Error("YouTube Iframe API failed to load within timeout."));
return;
}
v = setTimeout(r, 100);
};
r();
});
}
function O() {
let e = document.getElementById(g.value);
if (!e) return;
let t = l.videoId || f(l.videoUrl) || void 0;
h.value = new window.YT.Player(e, {
height: l.height,
width: l.width,
videoId: t,
playerVars: l.playerVars,
events: {
onReady: (e) => m("ready", e.target),
onStateChange: k,
onPlaybackQualityChange: (e) => m("playbackQualityChange", e.target),
onPlaybackRateChange: (e) => m("playbackRateChange", e.target),
onError: (e) => m("error", e.target),
onApiChange: (e) => m("apiChange", e.target)
}
});
}
function k(e) {
switch (e.data) {
case window.YT.PlayerState.PLAYING:
m("playing", e.target);
break;
case window.YT.PlayerState.PAUSED:
m("paused", e.target);
break;
case window.YT.PlayerState.ENDED:
m("ended", e.target);
break;
}
m("stateChange", e.target);
}
function A() {
if (!h.value) throw Error("[vue3-ytframe] Player is not ready. Wait for the 'ready' event before calling player methods.");
return h.value;
}
function j() {
A().playVideo();
}
function M() {
A().pauseVideo();
}
function N() {
A().stopVideo();
}
function P(e, t) {
A().seekTo(e, t);
}
function F() {
A().nextVideo();
}
function I() {
A().previousVideo();
}
function L(e) {
A().playVideoAt(e);
}
function R() {
A().mute();
}
function z() {
A().unMute();
}
function B() {
return A().isMuted();
}
function V(e) {
A().setVolume(e);
}
function H() {
return A().getVolume();
}
function U(e, t) {
A().setSize(e, t);
}
function W(e) {
A().setLoop(e);
}
function G(e) {
A().setShuffle(e);
}
function te() {
return A().getDuration();
}
function K() {
return A().getCurrentTime();
}
function q() {
return A().getVideoEmbedCode();
}
function J() {
return A().getVideoUrl();
}
function Y() {
return A().getVideoLoadedFraction();
}
function X() {
return A().getPlayerState();
}
function Z() {
return A().getPlaybackRate();
}
function Q(e) {
A().setPlaybackRate(e);
}
function ne() {
return A().getAvailablePlaybackRates();
}
function re() {
return A().getOptions();
}
function ie(e, t) {
return A().getOption(e, t);
}
function ae(e, t, n) {
A().setOption(e, t, n);
}
function oe() {
return A().getSphericalProperties();
}
function $(e) {
A().setSphericalProperties(e);
}
function se() {
return A().getPlaylist();
}
function ce() {
return A().getPlaylistIndex();
}
function le() {
return A().getIframe();
}
function ue() {
h.value &&= (h.value.destroy(), null);
}
function de({ videoId: e, startSeconds: t, endSeconds: n }) {
A().loadVideoById({
videoId: e,
startSeconds: t,
endSeconds: n
});
}
function fe({ videoId: e, startSeconds: t, endSeconds: n }) {
A().cueVideoById({
videoId: e,
startSeconds: t,
endSeconds: n
});
}
function pe({ mediaContentUrl: e, startSeconds: t, endSeconds: n }) {
A().loadVideoByUrl({
mediaContentUrl: e,
startSeconds: t,
endSeconds: n
});
}
function me({ mediaContentUrl: e, startSeconds: t, endSeconds: n }) {
A().cueVideoByUrl({
mediaContentUrl: e,
startSeconds: t,
endSeconds: n
});
}
function he(e, t, n) {
A().cuePlaylist(e, t, n);
}
function ge(e, t, n) {
A().loadPlaylist(e, t, n);
}
return s({
player: h,
playVideo: j,
pauseVideo: M,
stopVideo: N,
seekTo: P,
nextVideo: F,
previousVideo: I,
playVideoAt: L,
mute: R,
unMute: z,
isMuted: B,
setVolume: V,
getVolume: H,
setSize: U,
setShuffle: G,
setLoop: W,
getDuration: te,
getCurrentTime: K,
getVideoEmbedCode: q,
getVideoUrl: J,
getVideoLoadedFraction: Y,
getPlayerState: X,
getPlaybackRate: Z,
setPlaybackRate: Q,
getAvailablePlaybackRates: ne,
getOptions: re,
getAnOption: ie,
setAnOption: ae,
getSphericalProperties: oe,
setSphericalProperties: $,
getPlaylist: se,
getPlaylistIndex: ce,
getIframe: le,
destroy: ue,
loadVideoById: de,
cueVideoById: fe,
loadVideoByUrl: pe,
cueVideoByUrl: me,
cuePlaylist: he,
loadPlaylist: ge,
getVideoIdFromYoutubeURL: f
}), (t, n) => (i(), e("div", {
id: g.value,
ref: "youtube"
}, null, 8, p));
}
}), h = { install(e) {
e.component("VueYtframe", m);
} };
//#endregion
export { m as VueYtframe, h as default, f as getVideoIdFromYoutubeURL };