UNPKG

react-video-timestone

Version:

A React component library for video timestone functionality

723 lines (722 loc) 21.3 kB
import ue, { useRef as V, useState as le, useEffect as ae, useReducer as se, createContext as ce, useContext as fe, memo as pe, useImperativeHandle as de } from "react"; import './index.css';function me(r) { return r && r.__esModule && Object.prototype.hasOwnProperty.call(r, "default") ? r.default : r; } var M = { exports: {} }, U = {}; /** * @license React * react-jsx-runtime.production.js * * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var ee; function ye() { if (ee) return U; ee = 1; var r = Symbol.for("react.transitional.element"), t = Symbol.for("react.fragment"); function i(c, l, n) { var a = null; if (n !== void 0 && (a = "" + n), l.key !== void 0 && (a = "" + l.key), "key" in l) { n = {}; for (var f in l) f !== "key" && (n[f] = l[f]); } else n = l; return l = n.ref, { $$typeof: r, type: c, key: a, ref: l !== void 0 ? l : null, props: n }; } return U.Fragment = t, U.jsx = i, U.jsxs = i, U; } var G = {}; /** * @license React * react-jsx-runtime.development.js * * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var re; function Ee() { return re || (re = 1, process.env.NODE_ENV !== "production" && function() { function r(e) { if (e == null) return null; if (typeof e == "function") return e.$$typeof === _ ? null : e.displayName || e.name || null; if (typeof e == "string") return e; switch (e) { case d: return "Fragment"; case A: return "Profiler"; case h: return "StrictMode"; case x: return "Suspense"; case k: return "SuspenseList"; case N: return "Activity"; } if (typeof e == "object") switch (typeof e.tag == "number" && console.error( "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue." ), e.$$typeof) { case D: return "Portal"; case Y: return (e.displayName || "Context") + ".Provider"; case T: return (e._context.displayName || "Context") + ".Consumer"; case I: var o = e.render; return e = e.displayName, e || (e = o.displayName || o.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e; case g: return o = e.displayName || null, o !== null ? o : r(e.type) || "Memo"; case b: o = e._payload, e = e._init; try { return r(e(o)); } catch { } } return null; } function t(e) { return "" + e; } function i(e) { try { t(e); var o = !1; } catch { o = !0; } if (o) { o = console; var p = o.error, y = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object"; return p.call( o, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", y ), t(e); } } function c(e) { if (e === d) return "<>"; if (typeof e == "object" && e !== null && e.$$typeof === b) return "<...>"; try { var o = r(e); return o ? "<" + o + ">" : "<...>"; } catch { return "<...>"; } } function l() { var e = j.A; return e === null ? null : e.getOwner(); } function n() { return Error("react-stack-top-frame"); } function a(e) { if (W.call(e, "key")) { var o = Object.getOwnPropertyDescriptor(e, "key").get; if (o && o.isReactWarning) return !1; } return e.key !== void 0; } function f(e, o) { function p() { K || (K = !0, console.error( "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", o )); } p.isReactWarning = !0, Object.defineProperty(e, "key", { get: p, configurable: !0 }); } function u() { var e = r(this.type); return H[e] || (H[e] = !0, console.error( "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release." )), e = this.props.ref, e !== void 0 ? e : null; } function s(e, o, p, y, w, O, $, q) { return p = O.ref, e = { $$typeof: R, type: e, key: o, props: O, _owner: w }, (p !== void 0 ? p : null) !== null ? Object.defineProperty(e, "ref", { enumerable: !1, get: u }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", { configurable: !1, enumerable: !1, writable: !0, value: 0 }), Object.defineProperty(e, "_debugInfo", { configurable: !1, enumerable: !1, writable: !0, value: null }), Object.defineProperty(e, "_debugStack", { configurable: !1, enumerable: !1, writable: !0, value: $ }), Object.defineProperty(e, "_debugTask", { configurable: !1, enumerable: !1, writable: !0, value: q }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e; } function S(e, o, p, y, w, O, $, q) { var E = o.children; if (E !== void 0) if (y) if (C(E)) { for (y = 0; y < E.length; y++) P(E[y]); Object.freeze && Object.freeze(E); } else console.error( "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead." ); else P(E); if (W.call(o, "key")) { E = r(e); var L = Object.keys(o).filter(function(ie) { return ie !== "key"; }); y = 0 < L.length ? "{key: someKey, " + L.join(": ..., ") + ": ...}" : "{key: someKey}", Q[E + y] || (L = 0 < L.length ? "{" + L.join(": ..., ") + ": ...}" : "{}", console.error( `A props object containing a "key" prop is being spread into JSX: let props = %s; <%s {...props} /> React keys must be passed directly to JSX without using spread: let props = %s; <%s key={someKey} {...props} />`, y, E, L, E ), Q[E + y] = !0); } if (E = null, p !== void 0 && (i(p), E = "" + p), a(o) && (i(o.key), E = "" + o.key), "key" in o) { p = {}; for (var B in o) B !== "key" && (p[B] = o[B]); } else p = o; return E && f( p, typeof e == "function" ? e.displayName || e.name || "Unknown" : e ), s( e, E, O, w, l(), p, $, q ); } function P(e) { typeof e == "object" && e !== null && e.$$typeof === R && e._store && (e._store.validated = 1); } var m = ue, R = Symbol.for("react.transitional.element"), D = Symbol.for("react.portal"), d = Symbol.for("react.fragment"), h = Symbol.for("react.strict_mode"), A = Symbol.for("react.profiler"), T = Symbol.for("react.consumer"), Y = Symbol.for("react.context"), I = Symbol.for("react.forward_ref"), x = Symbol.for("react.suspense"), k = Symbol.for("react.suspense_list"), g = Symbol.for("react.memo"), b = Symbol.for("react.lazy"), N = Symbol.for("react.activity"), _ = Symbol.for("react.client.reference"), j = m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, W = Object.prototype.hasOwnProperty, C = Array.isArray, F = console.createTask ? console.createTask : function() { return null; }; m = { react_stack_bottom_frame: function(e) { return e(); } }; var K, H = {}, X = m.react_stack_bottom_frame.bind( m, n )(), Z = F(c(n)), Q = {}; G.Fragment = d, G.jsx = function(e, o, p, y, w) { var O = 1e4 > j.recentlyCreatedOwnerStacks++; return S( e, o, p, !1, y, w, O ? Error("react-stack-top-frame") : X, O ? F(c(e)) : Z ); }, G.jsxs = function(e, o, p, y, w) { var O = 1e4 > j.recentlyCreatedOwnerStacks++; return S( e, o, p, !0, y, w, O ? Error("react-stack-top-frame") : X, O ? F(c(e)) : Z ); }; }()), G; } var te; function Re() { return te || (te = 1, process.env.NODE_ENV === "production" ? M.exports = ye() : M.exports = Ee()), M.exports; } var v = Re(), z = { exports: {} }; /*! Copyright (c) 2018 Jed Watson. Licensed under the MIT License (MIT), see http://jedwatson.github.io/classnames */ var ne; function Ae() { return ne || (ne = 1, function(r) { (function() { var t = {}.hasOwnProperty; function i() { for (var n = "", a = 0; a < arguments.length; a++) { var f = arguments[a]; f && (n = l(n, c(f))); } return n; } function c(n) { if (typeof n == "string" || typeof n == "number") return n; if (typeof n != "object") return ""; if (Array.isArray(n)) return i.apply(null, n); if (n.toString !== Object.prototype.toString && !n.toString.toString().includes("[native code]")) return n.toString(); var a = ""; for (var f in n) t.call(n, f) && n[f] && (a = l(a, f)); return a; } function l(n, a) { return a ? n ? n + " " + a : n + a : n; } r.exports ? (i.default = i, r.exports = i) : window.classNames = i; })(); }(z)), z.exports; } var Se = Ae(); const Te = /* @__PURE__ */ me(Se), ve = (r, t) => { const i = (c) => c === "FORWARD" ? "BACKWARD" : "FORWARD"; switch (r.playerState) { case "INIT": return t.type === "LOADING" ? { ...r, markers: t.payload, playerState: t.type } : r; case "LOADING": return t.type === "LOADING_PROGRESS" ? { ...r, playerState: t.type } : t.type === "READY" ? { ...r, playerState: t.type } : r; case "LOADING_PROGRESS": return t.type === "READY" ? { ...r, playerState: t.type, loadedVideoUrls: t.payload } : t.type === "LOADING_PROGRESS" ? { ...r, loadingProgress: t.payload } : { ...r }; case "READY": return t.type === "PLAYING" ? { ...r, playerState: t.type } : r; case "PLAYING": return t.type === "PAUSED" ? { ...r, playerState: t.type } : t.type === "ENDED" ? { ...r, playerState: t.type } : t.type === "TIMELINE_ENDED" ? { ...r, playerState: t.type } : t.type === "REVERSE" ? { ...r, playDirection: i(r.playDirection) } : r; case "PAUSED": return t.type === "PLAYING" ? { ...r, playerState: t.type } : t.type === "REVERSE" ? { ...r, playDirection: i(r.playDirection) } : r; case "ENDED": return t.type === "PLAYING" ? { ...r, playIndex: r.playDirection === "FORWARD" ? r.playIndex < r.loadedVideoUrls.length - 1 ? r.playIndex + 1 : 0 : r.playIndex > 0 ? r.playIndex - 1 : 0, playerState: t.type } : t.type === "REVERSE" ? { ...r, playDirection: i(r.playDirection) } : r; case "TIMELINE_ENDED": return t.type === "PLAYING" ? { ...r, playerState: t.type } : t.type === "REVERSE" ? { ...r, playDirection: i(r.playDirection) } : r; default: return r; } }, be = ({ videoRef: r, onEnded: t, speed: i = 1, videoCount: c, playIndex: l }) => { const n = 33.333333333333336, a = V(null), f = V("FORWARD"), u = V(0), s = V(null), [S, P] = le([]); function m() { let A = null; if (!r.current) throw new Error("videoRef 가 존재하지 않습니다."); u.current = r.current.currentTime; function T() { a.current && (cancelAnimationFrame(a.current), a.current = null); } function Y({ markers: x, prevCurrentTime: k, newCurrentTime: g }) { if (!x || x.length === 0) return; s.current && Math.abs(u.current - g) > 0.2 && (s.current = null); const b = x.find((N) => { if (typeof N?.videoIndex < "u" && l !== N.videoIndex) return null; const _ = f.current === "FORWARD", j = N.direction || "BOTH"; if (j === "FORWARD" && !_ || j === "BACKWARD" && _) return null; const W = Number(k.toFixed(2)), C = Number(N.time.toFixed(2)), F = Number(g.toFixed(2)); return _ && C > W && C <= F || !_ && F <= C && C < W ? N : null; }); b && s.current !== b.label && (b.action === "PAUSE" && (b.triggerPause?.(), T()), b.callback?.(), s.current = b.label); } function I(x) { const k = f.current === "FORWARD"; if (!r.current) throw new Error("videoRef 가 존재하지 않습니다."); if (A === null) { A = x, a.current = requestAnimationFrame(I); return; } const g = x - A; if (g >= n) { const b = g / 1e3 * i; A = x; const N = r.current.currentTime, _ = k ? r.current.currentTime + b : r.current.currentTime - b; r.current.currentTime = _, Y({ markers: S, prevCurrentTime: N, newCurrentTime: _ }), (k ? r.current.duration > _ : 0 < _) ? a.current = requestAnimationFrame(I) : a.current && (T(), t && t({ isTimelineEnded: k ? l === c - 1 : l === 0 })); } else a.current = requestAnimationFrame(I); } a.current = requestAnimationFrame(I); } function R() { a.current && (cancelAnimationFrame(a.current), a.current = null); } function D() { f.current = f.current === "FORWARD" ? "BACKWARD" : "FORWARD"; } function d({ time: A, autoPlay: T = !1 }) { r.current && (R(), r.current.currentTime = A, T && m()); } function h(A) { P((T) => [...T, ...A]); } return ae(() => () => { a.current && (cancelAnimationFrame(a.current), a.current = null); }, []), { play: m, pause: R, reverse: D, seekTo: d, addMarkers: h }; }, De = (r, t) => r?.map((i) => ({ ...i, triggerPause: () => { t({ type: "PAUSED" }); } })) || []; async function _e(r) { return (await Promise.all( r.map((c) => fetch(c, { method: "HEAD" })) )).map((c) => c.headers.get("content-length")).reduce((c, l) => c + Number(l), 0); } const Ne = async ({ urls: r, onProgress: t, onReady: i }) => { let c = 0; const l = await _e(r), n = r.map(() => 0), a = await Promise.all( r.map(async (s, S) => await f(s, S)) ); async function f(s, S) { const m = await fetch(s, { method: "GET" }); return await new Response( new ReadableStream({ start(D) { const d = m.body?.getReader(); h(); function h() { d?.read().then(({ done: A, value: T }) => { if (A) { D.close(); return; } n[S] = (n?.[S] ?? 0) + (T?.byteLength ?? 0), c = n.reduce((Y, I) => Y + I, 0) / l * 100, t && t(c), D.enqueue(T), h(); }); } } }), { status: 200, headers: { "Content-Type": "video/mp4" } } ).blob(); } const u = a.map((s) => URL.createObjectURL(s)); return i && i(u), { blobUrls: u, cleanup: () => { u.forEach((s) => URL.revokeObjectURL(s)); } }; }, Oe = ({ ref: r, markers: t, videoUrls: i, speed: c, onLoading: l, onReady: n, onLoaded: a, onStateChange: f }) => { const [u, s] = se(ve, { loadingProgress: 0, loadedVideoUrls: [], playerState: "INIT", playDirection: "FORWARD", playIndex: 0, markers: [] }), { play: S, pause: P, seekTo: m, reverse: R, addMarkers: D } = be({ videoRef: r, speed: c, playIndex: u.playIndex, videoCount: u.loadedVideoUrls.length, onEnded: ({ isTimelineEnded: d }) => s({ type: d ? "TIMELINE_ENDED" : "ENDED" }) }); return ae(() => { u.playerState === "INIT" && (s({ type: "LOADING", ...t && { payload: t } }), t && D(De(t, s))), u.playerState === "LOADING" && Ne({ urls: i, onProgress: (d) => { s({ type: "LOADING_PROGRESS", payload: d }), l && l(d); } }).then(({ blobUrls: d }) => { s({ type: "READY", payload: d }), a?.(); }).catch((d) => { s({ type: "ERROR", payload: d }); }), u.playerState === "READY" && n && n(), u.playerState === "PLAYING" && S(), u.playerState === "PAUSED" && P(), u.playerState === "ENDED" && (u.playDirection === "FORWARD" && u.playIndex < u.loadedVideoUrls.length - 1 && s({ type: "PLAYING" }), u.playIndex > 0 && s({ type: "PLAYING" })), f?.({ isPlaying: u.playerState === "PLAYING", isRewind: u.playDirection === "BACKWARD", playerState: u.playerState, currentTime: r.current?.currentTime }); }, [u.playerState]), { state: u, play: () => { u.playDirection === "BACKWARD" && (s({ type: "REVERSE" }), R()), s({ type: "PLAYING" }); }, pause: () => s({ type: "PAUSED" }), reverse: () => s({ type: "REVERSE" }), rewind: () => { u.playDirection === "FORWARD" && (s({ type: "REVERSE" }), R()), s({ type: "PLAYING" }); }, seekTo: m, moveToFirstFrame: () => { u.playDirection === "BACKWARD" && u.playerState === "PLAYING" && m({ time: r.current.duration, autoPlay: !0 }); } }; }, oe = ce(null); var Pe = "_1spdh1z0", he = "_1spdh1z1", xe = "_1spdh1z2", J = "_1spdh1z3"; function Ie({ onPlay: r, onPause: t, onRewind: i }) { const c = fe(oe); return /* @__PURE__ */ v.jsxs("div", { className: Pe, children: [ /* @__PURE__ */ v.jsx("p", { className: xe, children: c?.playDirection }), /* @__PURE__ */ v.jsxs("div", { className: he, children: [ /* @__PURE__ */ v.jsx("button", { className: J, type: "button", onClick: r, children: "Play" }), /* @__PURE__ */ v.jsx( "button", { className: J, type: "button", onClick: t, children: "Pause" } ), /* @__PURE__ */ v.jsx( "button", { className: J, type: "button", onClick: i, children: "Rewind" } ) ] }) ] }); } var we = "_10oingv0", ke = "_10oingv1", ge = "_10oingv2"; const je = pe( function({ ref: t, url: i, loop: c, poster: l, onLoadedData: n }) { return /* @__PURE__ */ v.jsxs("div", { className: we, children: [ /* @__PURE__ */ v.jsx( "video", { className: ke, src: i, ref: t, loop: c, onLoadedData: n, muted: !0, playsInline: !0, preload: "metadata", poster: l }, i ), l && /* @__PURE__ */ v.jsx( "div", { className: ge, style: { backgroundImage: `url(${l})` } } ) ] }); }, (r, t) => r.url === t.url && r.poster === t.poster ); var Ce = "_14pkj7w0", Fe = "_14pkj7w1"; function Ye({ speed: r, className: t, videoUrls: i, markers: c, controls: l, posters: n, onLoading: a, onLoaded: f, onReady: u, onStateChange: s, fullScreen: S, ref: P }) { const m = V(null), { state: R, play: D, pause: d, rewind: h, seekTo: A, moveToFirstFrame: T } = Oe({ ref: m, speed: r, videoUrls: i, markers: c, onLoading: a, onLoaded: f, onReady: u, onStateChange: s }); return de(P, () => ({ videoElement: m.current || void 0, play: D, pause: d, rewind: h, seekTo: A })), /* @__PURE__ */ v.jsx( "div", { className: Te( Ce, S && Fe, t ), children: /* @__PURE__ */ v.jsxs(oe.Provider, { value: R, children: [ /* @__PURE__ */ v.jsx( je, { poster: n && n[R.playIndex], ref: m, url: R.loadedVideoUrls[R.playIndex] || "", onLoadedData: () => T() } ), l && /* @__PURE__ */ v.jsx(Ie, { onPlay: D, onPause: d, onRewind: h }) ] }) } ); } const We = { FORWARD: "FORWARD", BACKWARD: "BACKWARD", BOTH: "BOTH" }, Ue = { CONTINUE: "CONTINUE", PAUSE: "PAUSE" }; export { Ue as MARKER_ACTION, We as MARKER_DIRECTION, Ie as VideoControl, Ye as VideoTimestone, De as setupMarkers };