@kieransimkin/dancemoves 3.1.19 → 3.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +6 -0
- package/README.md +21 -0
- package/docs/child-playback.md +94 -0
- package/docs/playback-sources.md +85 -0
- package/docs/shared-feature-coverage.md +1 -0
- package/lib/build-manifest.json +13 -13
- package/lib/dancemoves.min.js +3 -3
- package/lib/index.cjs +934 -22
- package/lib/index.d.ts +40 -10
- package/lib/index.mjs +934 -22
- package/lib/rudiments.d.ts +4 -2
- package/lib/wordpress.js +3 -3
- package/package.json +1 -1
- package/readme.txt +2 -2
package/lib/index.cjs
CHANGED
|
@@ -24,6 +24,8 @@ __export(index_exports, {
|
|
|
24
24
|
VERSION: () => VERSION,
|
|
25
25
|
createDanceMoves: () => createDanceMoves,
|
|
26
26
|
createMemoryPageStore: () => createMemoryPageStore,
|
|
27
|
+
createPlaybackPublisher: () => createPlaybackPublisher,
|
|
28
|
+
createPlaybackReceiver: () => createPlaybackReceiver,
|
|
27
29
|
fromWordPressMeta: () => fromWordPressMeta,
|
|
28
30
|
validatePageConfig: () => validatePageConfig
|
|
29
31
|
});
|
|
@@ -48,6 +50,7 @@ function install(__dmScope) {
|
|
|
48
50
|
var lyricList = [];
|
|
49
51
|
var lyricRenderer = null;
|
|
50
52
|
var boundAudio = /* @__PURE__ */ new WeakSet();
|
|
53
|
+
var playbackBindings = /* @__PURE__ */ new Map();
|
|
51
54
|
var activeAudio = null;
|
|
52
55
|
var pageClockStarted = window2.performance && typeof window2.performance.now === "function" ? window2.performance.now() : Date.now();
|
|
53
56
|
var referenceDurationSeconds = positiveNumber(rawConfig.masterDurationMilliseconds) / 1e3;
|
|
@@ -137,13 +140,16 @@ function install(__dmScope) {
|
|
|
137
140
|
}
|
|
138
141
|
function currentTick(options) {
|
|
139
142
|
var settings = options || {};
|
|
140
|
-
var audio = settings.audio || (settings.clock === "audio" ? activeAudio : null);
|
|
143
|
+
var audio = playbackAudio(settings.audio) || (settings.clock === "audio" ? activeAudio : null);
|
|
141
144
|
if (audio && !audio.paused && !audio.ended && Number.isFinite(Number(audio.currentTime))) {
|
|
142
145
|
return Number(audio.currentTime) * effectiveBpm(settings.bpm || bpm) * TICKS_PER_BEAT / 60;
|
|
143
146
|
}
|
|
144
147
|
var now = window2.performance && typeof window2.performance.now === "function" ? window2.performance.now() : Date.now();
|
|
145
148
|
return Math.max(0, now - pageClockStarted) * effectiveBpm(settings.bpm || bpm) * TICKS_PER_BEAT / 6e4;
|
|
146
149
|
}
|
|
150
|
+
function playbackAudio(audio) {
|
|
151
|
+
return audio && api && api.playbackSource ? api.playbackSource(audio) : audio;
|
|
152
|
+
}
|
|
147
153
|
function nextIntervalTick(intervalTicks, fromTick, strictlyFuture) {
|
|
148
154
|
var interval = Math.max(1, roundHalfUp(intervalTicks));
|
|
149
155
|
var tick = Math.max(0, Number(fromTick) || 0);
|
|
@@ -200,7 +206,7 @@ function install(__dmScope) {
|
|
|
200
206
|
var pollAudio = function() {
|
|
201
207
|
if (cancelled)
|
|
202
208
|
return;
|
|
203
|
-
var candidate = settings.audio || activeAudio;
|
|
209
|
+
var candidate = playbackAudio(settings.audio) || activeAudio;
|
|
204
210
|
if (!candidate || candidate.paused || candidate.ended) {
|
|
205
211
|
if (sourceAudio && sourceAudio.ended) {
|
|
206
212
|
cancel();
|
|
@@ -762,9 +768,18 @@ function install(__dmScope) {
|
|
|
762
768
|
return Math.abs(duration - referenceDurationSeconds) <= Math.max(0.25, duration / 1e5);
|
|
763
769
|
}
|
|
764
770
|
function bindAudio(audio) {
|
|
771
|
+
if (api.playbackSource)
|
|
772
|
+
audio = api.playbackSource(audio);
|
|
765
773
|
if (boundAudio.has(audio) || !matchesMasterDuration(audio))
|
|
766
774
|
return;
|
|
767
775
|
boundAudio.add(audio);
|
|
776
|
+
var removers = [];
|
|
777
|
+
function listen(target, name, handler) {
|
|
778
|
+
__dmScope.listen(target, name, handler);
|
|
779
|
+
removers.push(function() {
|
|
780
|
+
__dmScope.unlisten(target, name, handler);
|
|
781
|
+
});
|
|
782
|
+
}
|
|
768
783
|
__dmScope.dataset(audio, "danceMovesTiming", "master-length");
|
|
769
784
|
var state = {
|
|
770
785
|
next: firstCueAfter(audio.currentTime || 0),
|
|
@@ -772,7 +787,8 @@ function install(__dmScope) {
|
|
|
772
787
|
last: audio.currentTime || 0,
|
|
773
788
|
seeking: false,
|
|
774
789
|
frame: 0,
|
|
775
|
-
pendingCue: cueAtLanding(audio.currentTime || 0)
|
|
790
|
+
pendingCue: cueAtLanding(audio.currentTime || 0),
|
|
791
|
+
endedPending: false
|
|
776
792
|
};
|
|
777
793
|
function stopFrame() {
|
|
778
794
|
if (state.frame)
|
|
@@ -781,7 +797,7 @@ function install(__dmScope) {
|
|
|
781
797
|
}
|
|
782
798
|
function tick() {
|
|
783
799
|
state.frame = 0;
|
|
784
|
-
if (audio.paused || audio.ended || state.seeking)
|
|
800
|
+
if (audio.paused || audio.ended || state.seeking || document2.hidden)
|
|
785
801
|
return;
|
|
786
802
|
var diagnosticStartedAt = diagnosticsSink ? diagnosticNow() : 0;
|
|
787
803
|
var firedCount = 0;
|
|
@@ -819,8 +835,14 @@ function install(__dmScope) {
|
|
|
819
835
|
}
|
|
820
836
|
function start() {
|
|
821
837
|
stopFrame();
|
|
838
|
+
if (document2.hidden || audio.paused || audio.ended)
|
|
839
|
+
return;
|
|
822
840
|
activeAudio = audio;
|
|
823
841
|
state.last = positiveNumber(audio.currentTime);
|
|
842
|
+
if (state.endedPending) {
|
|
843
|
+
state.pendingCue = cueAtLanding(state.last);
|
|
844
|
+
state.endedPending = false;
|
|
845
|
+
}
|
|
824
846
|
state.next = firstCueAfter(state.last);
|
|
825
847
|
state.lyric = -2;
|
|
826
848
|
if (state.pendingCue) {
|
|
@@ -830,47 +852,70 @@ function install(__dmScope) {
|
|
|
830
852
|
setOwnedPlaybackRate(audio.playbackRate);
|
|
831
853
|
state.frame = window2.requestAnimationFrame(tick);
|
|
832
854
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
855
|
+
listen(audio, "play", start);
|
|
856
|
+
listen(audio, "playing", start);
|
|
857
|
+
listen(audio, "pause", function() {
|
|
836
858
|
stopFrame();
|
|
837
859
|
if (activeAudio === audio)
|
|
838
860
|
activeAudio = null;
|
|
839
861
|
if (lyricRenderer)
|
|
840
862
|
lyricRenderer.hide();
|
|
841
863
|
});
|
|
842
|
-
|
|
864
|
+
listen(audio, "ended", function() {
|
|
843
865
|
stopFrame();
|
|
844
866
|
if (activeAudio === audio)
|
|
845
867
|
activeAudio = null;
|
|
846
868
|
state.last = 0;
|
|
847
869
|
state.next = 0;
|
|
848
870
|
state.lyric = -2;
|
|
849
|
-
state.pendingCue =
|
|
871
|
+
state.pendingCue = null;
|
|
872
|
+
state.endedPending = true;
|
|
850
873
|
if (lyricRenderer)
|
|
851
874
|
lyricRenderer.hide();
|
|
852
875
|
});
|
|
853
|
-
|
|
876
|
+
listen(audio, "seeking", function() {
|
|
854
877
|
state.seeking = true;
|
|
855
878
|
state.pendingCue = null;
|
|
856
879
|
stopFrame();
|
|
857
880
|
});
|
|
858
|
-
|
|
881
|
+
listen(audio, "seeked", function() {
|
|
859
882
|
state.seeking = false;
|
|
860
883
|
state.last = positiveNumber(audio.currentTime);
|
|
861
884
|
state.next = firstCueAfter(state.last);
|
|
862
885
|
state.lyric = -2;
|
|
863
886
|
state.pendingCue = cueAtLanding(state.last);
|
|
887
|
+
playbackBindings.set(audio, function() {
|
|
888
|
+
stopFrame();
|
|
889
|
+
removers.splice(0).forEach(function(remove) {
|
|
890
|
+
remove();
|
|
891
|
+
});
|
|
892
|
+
boundAudio.delete(audio);
|
|
893
|
+
if (activeAudio === audio)
|
|
894
|
+
activeAudio = null;
|
|
895
|
+
playbackBindings.delete(audio);
|
|
896
|
+
});
|
|
864
897
|
if (!audio.paused && !audio.ended)
|
|
865
898
|
start();
|
|
866
899
|
});
|
|
867
|
-
|
|
900
|
+
listen(audio, "ratechange", function() {
|
|
868
901
|
setOwnedPlaybackRate(audio.playbackRate);
|
|
869
902
|
});
|
|
870
|
-
|
|
903
|
+
listen(audio, "timeupdate", function() {
|
|
871
904
|
if (!audio.paused && !state.frame && !state.seeking)
|
|
872
905
|
tick();
|
|
873
906
|
});
|
|
907
|
+
listen(document2, "visibilitychange", function() {
|
|
908
|
+
if (document2.hidden) {
|
|
909
|
+
stopFrame();
|
|
910
|
+
if (lyricRenderer)
|
|
911
|
+
lyricRenderer.hide();
|
|
912
|
+
} else if (!audio.paused && !audio.ended && !state.seeking) {
|
|
913
|
+
state.pendingCue = null;
|
|
914
|
+
start();
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
if (!audio.paused && !audio.ended)
|
|
918
|
+
start();
|
|
874
919
|
}
|
|
875
920
|
function discoverAudio() {
|
|
876
921
|
var audioElements = Array.from(document2.querySelectorAll("audio"));
|
|
@@ -984,6 +1029,16 @@ function install(__dmScope) {
|
|
|
984
1029
|
registerAnimationScope,
|
|
985
1030
|
resetRunningAnimations,
|
|
986
1031
|
discoverAudio,
|
|
1032
|
+
unregisterPlaybackSource: function(source) {
|
|
1033
|
+
var remove = playbackBindings.get(source);
|
|
1034
|
+
if (remove)
|
|
1035
|
+
remove();
|
|
1036
|
+
},
|
|
1037
|
+
registerPlaybackSource: function(source) {
|
|
1038
|
+
if (!referenceDurationSeconds)
|
|
1039
|
+
referenceDurationSeconds = positiveNumber(source.duration);
|
|
1040
|
+
bindAudio(source);
|
|
1041
|
+
},
|
|
987
1042
|
setDiagnosticsSink,
|
|
988
1043
|
diagnosticsEnabled: function() {
|
|
989
1044
|
return diagnosticsAllowed && Boolean(diagnosticsSink);
|
|
@@ -1024,6 +1079,10 @@ function install2(__dmScope) {
|
|
|
1024
1079
|
return document2.querySelector(value);
|
|
1025
1080
|
return fallback || null;
|
|
1026
1081
|
}
|
|
1082
|
+
function playbackElement(value, fallback) {
|
|
1083
|
+
var target = element(value, fallback);
|
|
1084
|
+
return target && motion.playbackSource ? motion.playbackSource(target) : target;
|
|
1085
|
+
}
|
|
1027
1086
|
function media(query) {
|
|
1028
1087
|
return window2.matchMedia(query);
|
|
1029
1088
|
}
|
|
@@ -1149,7 +1208,7 @@ function install2(__dmScope) {
|
|
|
1149
1208
|
function playbackPulse(options) {
|
|
1150
1209
|
options = options || {};
|
|
1151
1210
|
var state = commonState(options, "pulse");
|
|
1152
|
-
var audio =
|
|
1211
|
+
var audio = playbackElement(options.audio, state.root.querySelector("audio"));
|
|
1153
1212
|
if (!audio)
|
|
1154
1213
|
throw new Error("DanceMovesEffects pulse requires an audio element");
|
|
1155
1214
|
var ticks = Math.max(1, Math.round(finite2(options.ticks, 16)));
|
|
@@ -1249,7 +1308,7 @@ function install2(__dmScope) {
|
|
|
1249
1308
|
function cueTimeline(options) {
|
|
1250
1309
|
options = options || {};
|
|
1251
1310
|
var state = commonState(options, "cue-timeline");
|
|
1252
|
-
var audio =
|
|
1311
|
+
var audio = playbackElement(options.audio, state.root.querySelector("audio"));
|
|
1253
1312
|
if (!audio)
|
|
1254
1313
|
throw new Error("DanceMovesEffects cueTimeline requires an audio element");
|
|
1255
1314
|
var cues = (Array.isArray(options.cues) ? options.cues : []).map(function(cue, index) {
|
|
@@ -1410,7 +1469,7 @@ function install2(__dmScope) {
|
|
|
1410
1469
|
function spritePlayback(options) {
|
|
1411
1470
|
options = options || {};
|
|
1412
1471
|
var state = commonState(options, "sprite-playback");
|
|
1413
|
-
var audio =
|
|
1472
|
+
var audio = playbackElement(options.audio, state.root.querySelector("audio"));
|
|
1414
1473
|
var target = element(options.target, state.root);
|
|
1415
1474
|
if (!audio)
|
|
1416
1475
|
throw new Error("DanceMovesEffects spritePlayback requires an audio element");
|
|
@@ -1604,7 +1663,7 @@ function install2(__dmScope) {
|
|
|
1604
1663
|
function lyricStage(options) {
|
|
1605
1664
|
options = options || {};
|
|
1606
1665
|
var state = commonState(options, "lyric-stage");
|
|
1607
|
-
var audio =
|
|
1666
|
+
var audio = playbackElement(options.audio, state.root.querySelector("audio"));
|
|
1608
1667
|
var popover = element(options.popover, document2.querySelector(".dance-moves-lyric-popover"));
|
|
1609
1668
|
if (!audio)
|
|
1610
1669
|
throw new Error("DanceMovesEffects lyricStage requires an audio element");
|
|
@@ -4823,9 +4882,11 @@ function install9(__dmScope) {
|
|
|
4823
4882
|
const clock = options.clock === void 0 ? "page" : options.clock;
|
|
4824
4883
|
if (!["page", "audio", "auto"].includes(clock))
|
|
4825
4884
|
throw new TypeError("clock must be page, audio or auto");
|
|
4826
|
-
|
|
4827
|
-
if (audio &&
|
|
4828
|
-
|
|
4885
|
+
let audio = clock === "page" ? null : element(options.audio, "audio");
|
|
4886
|
+
if (audio && motion.playbackSource)
|
|
4887
|
+
audio = motion.playbackSource(audio);
|
|
4888
|
+
if (audio && !["audio", "video"].includes(String(audio.tagName).toLowerCase()))
|
|
4889
|
+
throw new TypeError("audio must resolve to native media or a shared playback source");
|
|
4829
4890
|
const rate = options.rate === void 0 ? 1 : number(options.rate, "rate");
|
|
4830
4891
|
if (rate <= 0 || rate > 64)
|
|
4831
4892
|
throw new RangeError("rate must be in (0, 64]");
|
|
@@ -5073,7 +5134,7 @@ function install9(__dmScope) {
|
|
|
5073
5134
|
}
|
|
5074
5135
|
if (options.resetOnCue)
|
|
5075
5136
|
disposers.push(motion.onCue(typeof options.resetOnCue === "string" ? options.resetOnCue : "*", (detail) => {
|
|
5076
|
-
if (!detail.audio || !audio || detail.audio === audio)
|
|
5137
|
+
if (!detail.audio || !audio || detail.audio === audio || motion.playbackSource && motion.playbackSource(detail.audio) === motion.playbackSource(audio))
|
|
5077
5138
|
reset();
|
|
5078
5139
|
}, { id: id + ":cue-reset" }));
|
|
5079
5140
|
if (options.offscreen !== false && window2.IntersectionObserver) {
|
|
@@ -5347,6 +5408,8 @@ function createScope(root, config, { legacyGlobals = false, nonce, orientation =
|
|
|
5347
5408
|
}
|
|
5348
5409
|
const api = {
|
|
5349
5410
|
id,
|
|
5411
|
+
root,
|
|
5412
|
+
legacyGlobals,
|
|
5350
5413
|
window,
|
|
5351
5414
|
document,
|
|
5352
5415
|
get disposed() {
|
|
@@ -5949,8 +6012,855 @@ function createMotionRecorder(scope, { durationMilliseconds = 3e4, maxSamples =
|
|
|
5949
6012
|
});
|
|
5950
6013
|
}
|
|
5951
6014
|
|
|
6015
|
+
// .build/modules/playback.mjs
|
|
6016
|
+
var youtubeLoaders = /* @__PURE__ */ new WeakMap();
|
|
6017
|
+
function validatePlaybackMapping(input, masterDuration) {
|
|
6018
|
+
const offset = input.offset ?? 0, duration = input.duration ?? masterDuration, playerStart = input.playerStart ?? 0;
|
|
6019
|
+
for (const [key, value] of Object.entries({ offset, duration, playerStart, masterDuration })) {
|
|
6020
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || (key === "duration" || key === "masterDuration") && value === 0) throw new RangeError(`${key} must be a finite positive duration or nonnegative offset`);
|
|
6021
|
+
}
|
|
6022
|
+
if (offset + duration > masterDuration + 1e-3) throw new RangeError("The clip extends beyond its associated master");
|
|
6023
|
+
return Object.freeze({ offset, duration, playerStart, masterDuration });
|
|
6024
|
+
}
|
|
6025
|
+
function loadYouTubeAPI(host) {
|
|
6026
|
+
if (host.YT?.Player) return Promise.resolve(host.YT);
|
|
6027
|
+
if (youtubeLoaders.has(host)) return youtubeLoaders.get(host);
|
|
6028
|
+
const pending = new Promise((resolve, reject) => {
|
|
6029
|
+
const previous = host.onYouTubeIframeAPIReady;
|
|
6030
|
+
let timeout;
|
|
6031
|
+
const script = host.document.createElement("script");
|
|
6032
|
+
function finish(error) {
|
|
6033
|
+
host.clearTimeout(timeout);
|
|
6034
|
+
if (host.onYouTubeIframeAPIReady === ready) host.onYouTubeIframeAPIReady = previous;
|
|
6035
|
+
script.removeEventListener("error", failed);
|
|
6036
|
+
if (error) {
|
|
6037
|
+
script.remove();
|
|
6038
|
+
youtubeLoaders.delete(host);
|
|
6039
|
+
reject(error);
|
|
6040
|
+
} else resolve(host.YT);
|
|
6041
|
+
}
|
|
6042
|
+
function ready() {
|
|
6043
|
+
try {
|
|
6044
|
+
previous?.();
|
|
6045
|
+
} finally {
|
|
6046
|
+
finish(host.YT?.Player ? null : new Error("YouTube API unavailable"));
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
function failed() {
|
|
6050
|
+
finish(new Error("YouTube API failed to load"));
|
|
6051
|
+
}
|
|
6052
|
+
host.onYouTubeIframeAPIReady = ready;
|
|
6053
|
+
script.src = "https://www.youtube.com/iframe_api";
|
|
6054
|
+
script.addEventListener("error", failed, { once: true });
|
|
6055
|
+
timeout = host.setTimeout(() => finish(new Error("YouTube API timed out")), 2e4);
|
|
6056
|
+
host.document.head.appendChild(script);
|
|
6057
|
+
});
|
|
6058
|
+
youtubeLoaders.set(host, pending);
|
|
6059
|
+
return pending;
|
|
6060
|
+
}
|
|
6061
|
+
function installPlayback(scope, api, host = scope.document.defaultView) {
|
|
6062
|
+
const groups = /* @__PURE__ */ new Map(), transports = /* @__PURE__ */ new WeakSet(), aliases = /* @__PURE__ */ new WeakMap(), controllers = /* @__PURE__ */ new Set(), registered = /* @__PURE__ */ new WeakMap();
|
|
6063
|
+
let disposed = false;
|
|
6064
|
+
function emit(target, type) {
|
|
6065
|
+
target.dispatchEvent(new host.Event(type));
|
|
6066
|
+
}
|
|
6067
|
+
function groupFor(reference) {
|
|
6068
|
+
if (disposed) throw new Error("DanceMoves playback owner is destroyed");
|
|
6069
|
+
const master = reference?.element || reference, declared = reference?.element ? reference.duration : void 0;
|
|
6070
|
+
const isNative = !!master?.addEventListener && ["AUDIO", "VIDEO"].includes(master.tagName);
|
|
6071
|
+
if (!isNative && (!master || typeof master.id !== "string" || !master.id.trim() || master.id.length > 160 || typeof master.duration !== "number" || !Number.isFinite(master.duration) || master.duration <= 0)) throw new TypeError("A native master or identified master duration is required");
|
|
6072
|
+
if (isNative && (master.ownerDocument !== host.document || !scope.legacyGlobals && !scope.root.contains(master))) throw new TypeError("The master must belong to this runtime root");
|
|
6073
|
+
if (groups.has(master)) {
|
|
6074
|
+
const group2 = groups.get(master);
|
|
6075
|
+
group2.setDuration(declared);
|
|
6076
|
+
return group2;
|
|
6077
|
+
}
|
|
6078
|
+
const transport = new host.EventTarget();
|
|
6079
|
+
transports.add(transport);
|
|
6080
|
+
let active = null, lastPaused = true, delegate = null;
|
|
6081
|
+
let declaredDuration = declared || 0;
|
|
6082
|
+
function setDuration(value) {
|
|
6083
|
+
if (value === void 0) return;
|
|
6084
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) throw new RangeError("Declared master duration must be positive and finite");
|
|
6085
|
+
if (declaredDuration && Math.abs(declaredDuration - value) > 1e-3) throw new RangeError("Conflicting master durations");
|
|
6086
|
+
if (isNative && Number(master.duration) > 0 && Math.abs(Number(master.duration) - value) > 0.25) throw new RangeError("Declared master duration does not match its native reference");
|
|
6087
|
+
declaredDuration = value;
|
|
6088
|
+
}
|
|
6089
|
+
setDuration(declared);
|
|
6090
|
+
const duration = () => delegate?.duration || declaredDuration || (Number(master.duration) > 0 && Number.isFinite(Number(master.duration)) ? Number(master.duration) : Number(api.config?.masterDurationMilliseconds || 0) / 1e3);
|
|
6091
|
+
const target = isNative ? master : scope.root;
|
|
6092
|
+
const native = { element: isNative ? master : null, read: () => ({ time: Number(master.currentTime) || 0, paused: isNative ? master.paused : true, ended: master.ended || false, rate: master.playbackRate || 1, seeking: master.seeking || false, error: master.error }), pause: () => master.pause?.(), play: () => master.play?.(), seek: (time) => {
|
|
6093
|
+
if (isNative) master.currentTime = time;
|
|
6094
|
+
}, mapping: null };
|
|
6095
|
+
active = native;
|
|
6096
|
+
function read() {
|
|
6097
|
+
if (delegate) return { time: delegate.currentTime, paused: delegate.paused, ended: delegate.ended, rate: delegate.playbackRate, seeking: delegate.seeking, error: delegate.error };
|
|
6098
|
+
const raw = active.read(), map = active.mapping || { offset: 0, playerStart: 0, duration: duration() };
|
|
6099
|
+
const local = raw.time - map.playerStart, outside = local < -1e-3 || local > map.duration + 1e-3;
|
|
6100
|
+
return { ...raw, time: map.offset + Math.max(0, Math.min(map.duration, local)), paused: raw.paused || outside, ended: raw.ended || local > map.duration + 1e-3 };
|
|
6101
|
+
}
|
|
6102
|
+
Object.defineProperties(transport, {
|
|
6103
|
+
nodeType: { value: 1 },
|
|
6104
|
+
tagName: { get: () => isNative ? master.tagName : "VIDEO" },
|
|
6105
|
+
ownerDocument: { get: () => target.ownerDocument },
|
|
6106
|
+
dataset: { get: () => target.dataset },
|
|
6107
|
+
id: { get: () => master.id },
|
|
6108
|
+
isConnected: { get: () => target.isConnected },
|
|
6109
|
+
currentTime: { get: () => read().time, set: (value) => {
|
|
6110
|
+
if (delegate) {
|
|
6111
|
+
delegate.currentTime = value;
|
|
6112
|
+
return;
|
|
6113
|
+
}
|
|
6114
|
+
const map = active.mapping || { offset: 0, playerStart: 0, duration: duration() };
|
|
6115
|
+
active.seek(map.playerStart + Math.max(0, Math.min(map.duration, Number(value) - map.offset)));
|
|
6116
|
+
} },
|
|
6117
|
+
duration: { get: duration },
|
|
6118
|
+
paused: { get: () => read().paused },
|
|
6119
|
+
ended: { get: () => read().ended },
|
|
6120
|
+
seeking: { get: () => read().seeking || false },
|
|
6121
|
+
playbackRate: { get: () => read().rate },
|
|
6122
|
+
error: { get: () => read().error || null },
|
|
6123
|
+
element: { value: isNative ? master : null },
|
|
6124
|
+
activePlayer: { get: () => delegate ? delegate.activePlayer : active.element },
|
|
6125
|
+
masterId: { get: () => delegate ? delegate.masterId : master.currentSrc || master.src || master.id }
|
|
6126
|
+
});
|
|
6127
|
+
transport.matches = (selector) => target.matches(selector);
|
|
6128
|
+
transport.getAttribute = (name) => target.getAttribute(name);
|
|
6129
|
+
transport.setAttribute = (name, value) => target.setAttribute(name, value);
|
|
6130
|
+
transport.removeAttribute = (name) => target.removeAttribute(name);
|
|
6131
|
+
transport.play = () => delegate ? delegate.play() : active.play();
|
|
6132
|
+
transport.pause = () => delegate ? delegate.pause() : active.pause();
|
|
6133
|
+
function activate(source) {
|
|
6134
|
+
if (active !== source) {
|
|
6135
|
+
const previous = active;
|
|
6136
|
+
active = source;
|
|
6137
|
+
previous.pause();
|
|
6138
|
+
emit(transport, "seeking");
|
|
6139
|
+
emit(transport, "seeked");
|
|
6140
|
+
}
|
|
6141
|
+
}
|
|
6142
|
+
function forward(source, type) {
|
|
6143
|
+
if (type === "play" || type === "playing") activate(source);
|
|
6144
|
+
if (active !== source) return;
|
|
6145
|
+
const paused = read().paused;
|
|
6146
|
+
if (type === "timeupdate" && paused !== lastPaused) emit(transport, paused ? "pause" : "playing");
|
|
6147
|
+
lastPaused = paused;
|
|
6148
|
+
emit(transport, type);
|
|
6149
|
+
}
|
|
6150
|
+
const events = ["loadedmetadata", "durationchange", "play", "playing", "pause", "ended", "seeking", "seeked", "ratechange", "timeupdate", "waiting", "error"];
|
|
6151
|
+
const removers = [];
|
|
6152
|
+
function bindNative(element, mapping) {
|
|
6153
|
+
const source = element === master ? native : { element, mapping, read: () => ({ time: Number(element.currentTime) || 0, paused: element.paused, ended: element.ended, rate: element.playbackRate || 1, seeking: element.seeking, error: element.error }), pause: () => element.pause(), play: () => element.play(), seek: (time) => {
|
|
6154
|
+
element.currentTime = time;
|
|
6155
|
+
} };
|
|
6156
|
+
source.removers = [];
|
|
6157
|
+
for (const type of events) {
|
|
6158
|
+
const listener = () => forward(source, type);
|
|
6159
|
+
scope.listen(element, type, listener);
|
|
6160
|
+
const remove = () => scope.unlisten(element, type, listener);
|
|
6161
|
+
removers.push(remove);
|
|
6162
|
+
source.removers.push(remove);
|
|
6163
|
+
}
|
|
6164
|
+
return source;
|
|
6165
|
+
}
|
|
6166
|
+
if (isNative) bindNative(master, null);
|
|
6167
|
+
const group = {
|
|
6168
|
+
transport,
|
|
6169
|
+
duration,
|
|
6170
|
+
setDuration,
|
|
6171
|
+
activate,
|
|
6172
|
+
forward,
|
|
6173
|
+
bindNative,
|
|
6174
|
+
isActive: (source) => active === source,
|
|
6175
|
+
aliasTo(target2) {
|
|
6176
|
+
removers.splice(0).forEach((remove) => remove());
|
|
6177
|
+
delegate = target2;
|
|
6178
|
+
aliases.set(transport, target2);
|
|
6179
|
+
for (const type of events) {
|
|
6180
|
+
const relay = () => emit(transport, type);
|
|
6181
|
+
scope.listen(target2, type, relay);
|
|
6182
|
+
removers.push(() => scope.unlisten(target2, type, relay));
|
|
6183
|
+
}
|
|
6184
|
+
},
|
|
6185
|
+
reconcile(source) {
|
|
6186
|
+
if (active !== source) return;
|
|
6187
|
+
const paused = read().paused;
|
|
6188
|
+
if (paused !== lastPaused) {
|
|
6189
|
+
lastPaused = paused;
|
|
6190
|
+
emit(transport, paused ? "pause" : "playing");
|
|
6191
|
+
}
|
|
6192
|
+
emit(transport, "timeupdate");
|
|
6193
|
+
},
|
|
6194
|
+
remove(source) {
|
|
6195
|
+
if (active === source) {
|
|
6196
|
+
source.pause();
|
|
6197
|
+
active = native;
|
|
6198
|
+
lastPaused = true;
|
|
6199
|
+
emit(transport, "pause");
|
|
6200
|
+
emit(transport, "seeking");
|
|
6201
|
+
emit(transport, "seeked");
|
|
6202
|
+
}
|
|
6203
|
+
},
|
|
6204
|
+
destroy() {
|
|
6205
|
+
removers.splice(0).forEach((remove) => remove());
|
|
6206
|
+
emit(transport, "pause");
|
|
6207
|
+
}
|
|
6208
|
+
};
|
|
6209
|
+
groups.set(master, group);
|
|
6210
|
+
return group;
|
|
6211
|
+
}
|
|
6212
|
+
function registerEndpoint(options, provider = false) {
|
|
6213
|
+
if (!options || options.masterVerified !== true) throw new TypeError("An explicitly verified master association is required");
|
|
6214
|
+
const group = groupFor(options.master), mapping = validatePlaybackMapping(options, group.duration());
|
|
6215
|
+
const element = options.player;
|
|
6216
|
+
if (!element?.addEventListener || !["AUDIO", "VIDEO"].includes(element.tagName)) throw new TypeError("player must be native audio or video");
|
|
6217
|
+
if (element.ownerDocument !== host.document || !provider && !scope.legacyGlobals && !scope.root.contains(element)) throw new TypeError("The player must belong to this runtime root");
|
|
6218
|
+
if (provider && (!element.removeEventListener || typeof element.play !== "function" || typeof element.pause !== "function")) throw new TypeError("An event-driven playback provider is required");
|
|
6219
|
+
if (provider && typeof host.Node === "function" && element instanceof host.Node) throw new TypeError("Use registerPlayer for native DOM players");
|
|
6220
|
+
if (registered.has(element)) throw new Error("Player already has a playback owner");
|
|
6221
|
+
if (element === options.master || element === group.transport.element) throw new TypeError("The master is already registered");
|
|
6222
|
+
const previousGroup = groups.get(element);
|
|
6223
|
+
if (previousGroup && previousGroup !== group) {
|
|
6224
|
+
if ([...controllers].some((owner) => owner.source === previousGroup.transport)) throw new Error("This player already owns a different master group");
|
|
6225
|
+
api.unregisterPlaybackSource?.(previousGroup.transport);
|
|
6226
|
+
previousGroup.aliasTo(group.transport);
|
|
6227
|
+
for (const [key, value] of groups) if (value === previousGroup) groups.set(key, group);
|
|
6228
|
+
}
|
|
6229
|
+
const source = group.bindNative(element, mapping);
|
|
6230
|
+
let destroyed = false;
|
|
6231
|
+
const controller = { source: group.transport, mapping, teardown() {
|
|
6232
|
+
if (destroyed) return;
|
|
6233
|
+
destroyed = true;
|
|
6234
|
+
source.removers.splice(0).forEach((remove) => remove());
|
|
6235
|
+
group.remove(source);
|
|
6236
|
+
registered.delete(element);
|
|
6237
|
+
controllers.delete(controller);
|
|
6238
|
+
}, snapshot() {
|
|
6239
|
+
return { kind: provider ? "provider" : "native", mapping, active: group.isActive(source), destroyed };
|
|
6240
|
+
} };
|
|
6241
|
+
registered.set(element, controller);
|
|
6242
|
+
if (!element.paused && !element.ended) group.forward(source, "playing");
|
|
6243
|
+
Promise.resolve(api.ready).then(() => {
|
|
6244
|
+
if (!destroyed && !disposed) api.registerPlaybackSource?.(group.transport);
|
|
6245
|
+
});
|
|
6246
|
+
controllers.add(controller);
|
|
6247
|
+
return controller;
|
|
6248
|
+
}
|
|
6249
|
+
const registerPlayer = (options) => registerEndpoint(options);
|
|
6250
|
+
const registerPlaybackProvider = (options) => registerEndpoint(options, true);
|
|
6251
|
+
function registerYouTube(options) {
|
|
6252
|
+
if (!options || options.masterVerified !== true) throw new TypeError("An explicitly verified master association is required");
|
|
6253
|
+
const group = groupFor(options.master), mapping = validatePlaybackMapping(options, group.duration());
|
|
6254
|
+
const iframe = options.iframe;
|
|
6255
|
+
if (iframe?.tagName !== "IFRAME") throw new TypeError("A YouTube iframe is required");
|
|
6256
|
+
if (iframe.ownerDocument !== host.document || !scope.legacyGlobals && !scope.root.contains(iframe)) throw new TypeError("The iframe must belong to this runtime root");
|
|
6257
|
+
if (registered.has(iframe)) throw new Error("Player already has a playback owner");
|
|
6258
|
+
const url2 = new URL(iframe.src, host.location.href);
|
|
6259
|
+
if (!/^https:\/\/(www\.)?youtube(-nocookie)?\.com\/embed\/[A-Za-z0-9_-]{11}(\?|$)/.test(url2.href)) throw new TypeError("Unsupported YouTube embed");
|
|
6260
|
+
url2.searchParams.set("enablejsapi", "1");
|
|
6261
|
+
url2.searchParams.set("origin", host.location.origin);
|
|
6262
|
+
const expectedVideoId = url2.pathname.split("/").at(-1);
|
|
6263
|
+
if (iframe.src !== url2.href) iframe.src = url2.href;
|
|
6264
|
+
let player = null, state = -1, error = null, frame = 0, destroyed = false, lastTime = null, lastWall = null, lastRate = 1, readyTimer = 0, rejectReady = null;
|
|
6265
|
+
const source = {
|
|
6266
|
+
element: iframe,
|
|
6267
|
+
mapping,
|
|
6268
|
+
read: () => ({ time: player?.getCurrentTime?.() || 0, paused: state !== 1, ended: state === 0, rate: player?.getPlaybackRate?.() || 1, error }),
|
|
6269
|
+
pause: () => player?.pauseVideo?.(),
|
|
6270
|
+
play: () => player?.playVideo?.(),
|
|
6271
|
+
seek: (time) => player?.seekTo?.(time, true)
|
|
6272
|
+
};
|
|
6273
|
+
function stop() {
|
|
6274
|
+
if (frame) scope.window.cancelAnimationFrame(frame);
|
|
6275
|
+
frame = 0;
|
|
6276
|
+
lastTime = null;
|
|
6277
|
+
lastWall = null;
|
|
6278
|
+
}
|
|
6279
|
+
function sample(wall) {
|
|
6280
|
+
frame = 0;
|
|
6281
|
+
if (destroyed || state !== 1 || scope.document.hidden || !group.isActive(source)) return;
|
|
6282
|
+
const raw = source.read();
|
|
6283
|
+
if (lastTime !== null && Math.abs(raw.time - lastTime - (wall - lastWall) / 1e3 * raw.rate) > 0.4) {
|
|
6284
|
+
group.forward(source, "seeking");
|
|
6285
|
+
group.forward(source, "seeked");
|
|
6286
|
+
}
|
|
6287
|
+
if (raw.rate !== lastRate) {
|
|
6288
|
+
lastRate = raw.rate;
|
|
6289
|
+
group.forward(source, "ratechange");
|
|
6290
|
+
}
|
|
6291
|
+
lastTime = raw.time;
|
|
6292
|
+
lastWall = wall;
|
|
6293
|
+
group.reconcile(source);
|
|
6294
|
+
frame = scope.window.requestAnimationFrame(sample);
|
|
6295
|
+
}
|
|
6296
|
+
function resume() {
|
|
6297
|
+
stop();
|
|
6298
|
+
if (!destroyed && state === 1 && !scope.document.hidden && group.isActive(source)) frame = scope.window.requestAnimationFrame(sample);
|
|
6299
|
+
}
|
|
6300
|
+
const visibility = () => {
|
|
6301
|
+
if (scope.document.hidden) stop();
|
|
6302
|
+
else {
|
|
6303
|
+
group.forward(source, "seeking");
|
|
6304
|
+
group.forward(source, "seeked");
|
|
6305
|
+
resume();
|
|
6306
|
+
}
|
|
6307
|
+
};
|
|
6308
|
+
const pageHide = () => stop(), pageShow = () => {
|
|
6309
|
+
if (player?.getPlayerState) state = player.getPlayerState();
|
|
6310
|
+
visibility();
|
|
6311
|
+
};
|
|
6312
|
+
scope.listen(scope.document, "visibilitychange", visibility);
|
|
6313
|
+
scope.listen(host, "pagehide", pageHide);
|
|
6314
|
+
scope.listen(host, "pageshow", pageShow);
|
|
6315
|
+
const controller = {
|
|
6316
|
+
source: group.transport,
|
|
6317
|
+
mapping,
|
|
6318
|
+
ready: null,
|
|
6319
|
+
teardown() {
|
|
6320
|
+
if (destroyed) return;
|
|
6321
|
+
destroyed = true;
|
|
6322
|
+
stop();
|
|
6323
|
+
if (readyTimer) scope.window.clearTimeout(readyTimer);
|
|
6324
|
+
readyTimer = 0;
|
|
6325
|
+
rejectReady?.(new Error("YouTube playback owner removed"));
|
|
6326
|
+
rejectReady = null;
|
|
6327
|
+
group.remove(source);
|
|
6328
|
+
scope.unlisten(scope.document, "visibilitychange", visibility);
|
|
6329
|
+
scope.unlisten(host, "pagehide", pageHide);
|
|
6330
|
+
scope.unlisten(host, "pageshow", pageShow);
|
|
6331
|
+
player?.destroy?.();
|
|
6332
|
+
registered.delete(iframe);
|
|
6333
|
+
controllers.delete(controller);
|
|
6334
|
+
},
|
|
6335
|
+
snapshot() {
|
|
6336
|
+
return { kind: "youtube", mapping, state, error, active: group.isActive(source), destroyed, polling: !!frame, time: group.transport.currentTime };
|
|
6337
|
+
}
|
|
6338
|
+
};
|
|
6339
|
+
controllers.add(controller);
|
|
6340
|
+
registered.set(iframe, controller);
|
|
6341
|
+
Promise.resolve(api.ready).then(() => {
|
|
6342
|
+
if (!destroyed && !disposed) api.registerPlaybackSource?.(group.transport);
|
|
6343
|
+
});
|
|
6344
|
+
controller.ready = loadYouTubeAPI(host).then((YT) => {
|
|
6345
|
+
if (destroyed || disposed) return controller;
|
|
6346
|
+
return new Promise((resolve, reject) => {
|
|
6347
|
+
rejectReady = reject;
|
|
6348
|
+
readyTimer = scope.window.setTimeout(() => {
|
|
6349
|
+
readyTimer = 0;
|
|
6350
|
+
error = new Error("YouTube player readiness timed out");
|
|
6351
|
+
rejectReady = null;
|
|
6352
|
+
reject(error);
|
|
6353
|
+
}, 15e3);
|
|
6354
|
+
player = new YT.Player(iframe, { events: {
|
|
6355
|
+
onReady() {
|
|
6356
|
+
if (destroyed) return;
|
|
6357
|
+
if (readyTimer) scope.window.clearTimeout(readyTimer);
|
|
6358
|
+
readyTimer = 0;
|
|
6359
|
+
rejectReady = null;
|
|
6360
|
+
const actual = Number(player.getDuration?.());
|
|
6361
|
+
if (actual > 0 && actual + 0.25 < mapping.playerStart + mapping.duration) {
|
|
6362
|
+
error = new Error("The mapped soundtrack window exceeds the video duration");
|
|
6363
|
+
reject(error);
|
|
6364
|
+
return;
|
|
6365
|
+
}
|
|
6366
|
+
group.forward(source, "loadedmetadata");
|
|
6367
|
+
const initialState = player.getPlayerState?.();
|
|
6368
|
+
if (initialState === 1) controllerState({ data: initialState });
|
|
6369
|
+
resolve(controller);
|
|
6370
|
+
},
|
|
6371
|
+
onStateChange: controllerState,
|
|
6372
|
+
onPlaybackRateChange() {
|
|
6373
|
+
if (!destroyed) group.forward(source, "ratechange");
|
|
6374
|
+
},
|
|
6375
|
+
onError(event) {
|
|
6376
|
+
if (destroyed) return;
|
|
6377
|
+
error = new Error("YouTube playback error " + event.data);
|
|
6378
|
+
state = -1;
|
|
6379
|
+
stop();
|
|
6380
|
+
if (readyTimer) scope.window.clearTimeout(readyTimer);
|
|
6381
|
+
readyTimer = 0;
|
|
6382
|
+
rejectReady = null;
|
|
6383
|
+
group.forward(source, "pause");
|
|
6384
|
+
group.forward(source, "error");
|
|
6385
|
+
reject(error);
|
|
6386
|
+
}
|
|
6387
|
+
} });
|
|
6388
|
+
function controllerState(event) {
|
|
6389
|
+
if (destroyed) return;
|
|
6390
|
+
state = event.data;
|
|
6391
|
+
stop();
|
|
6392
|
+
if (state === 1) {
|
|
6393
|
+
let actualId;
|
|
6394
|
+
try {
|
|
6395
|
+
const actualUrl = new URL(player.getVideoUrl());
|
|
6396
|
+
actualId = actualUrl.searchParams.get("v") || actualUrl.pathname.match(/^\/(?:shorts|embed)\/([A-Za-z0-9_-]{11})\/?$/)?.[1];
|
|
6397
|
+
} catch {
|
|
6398
|
+
}
|
|
6399
|
+
if (actualId !== expectedVideoId) {
|
|
6400
|
+
error = new Error("YouTube switched away from the verified soundtrack asset");
|
|
6401
|
+
state = -1;
|
|
6402
|
+
group.forward(source, "pause");
|
|
6403
|
+
group.forward(source, "error");
|
|
6404
|
+
return;
|
|
6405
|
+
}
|
|
6406
|
+
const actualDuration = Number(player.getDuration?.());
|
|
6407
|
+
if (actualDuration > 0 && actualDuration + 0.25 < mapping.playerStart + mapping.duration) {
|
|
6408
|
+
error = new Error("The mapped soundtrack window exceeds the video duration");
|
|
6409
|
+
state = -1;
|
|
6410
|
+
group.forward(source, "pause");
|
|
6411
|
+
group.forward(source, "error");
|
|
6412
|
+
return;
|
|
6413
|
+
}
|
|
6414
|
+
group.forward(source, "play");
|
|
6415
|
+
group.forward(source, "playing");
|
|
6416
|
+
resume();
|
|
6417
|
+
} else group.forward(source, state === 0 ? "ended" : state === 3 ? "waiting" : "pause");
|
|
6418
|
+
if (state === 3) group.forward(source, "pause");
|
|
6419
|
+
}
|
|
6420
|
+
});
|
|
6421
|
+
});
|
|
6422
|
+
controller.ready.catch(() => {
|
|
6423
|
+
});
|
|
6424
|
+
return controller;
|
|
6425
|
+
}
|
|
6426
|
+
Object.assign(api, { playbackSource: (master) => {
|
|
6427
|
+
let source = transports.has(master) ? master : groupFor(master).transport;
|
|
6428
|
+
while (aliases.has(source)) source = aliases.get(source);
|
|
6429
|
+
return source;
|
|
6430
|
+
}, registerPlayer, registerPlaybackProvider, registerYouTube });
|
|
6431
|
+
scope.onDispose(() => {
|
|
6432
|
+
disposed = true;
|
|
6433
|
+
for (const controller of [...controllers]) controller.teardown();
|
|
6434
|
+
for (const group of new Set(groups.values())) group.destroy();
|
|
6435
|
+
groups.clear();
|
|
6436
|
+
});
|
|
6437
|
+
}
|
|
6438
|
+
|
|
6439
|
+
// .build/modules/child-playback.mjs
|
|
6440
|
+
var PROTOCOL = "dancemoves.child-playback.v1";
|
|
6441
|
+
var EVENTS = /* @__PURE__ */ new Set(["snapshot", "loadedmetadata", "durationchange", "play", "playing", "pause", "ended", "seeking", "seeked", "ratechange", "timeupdate", "waiting", "error"]);
|
|
6442
|
+
var MAX_SECONDS = 86400;
|
|
6443
|
+
var publisherOwners = /* @__PURE__ */ new WeakMap();
|
|
6444
|
+
var receiverOwners = /* @__PURE__ */ new WeakMap();
|
|
6445
|
+
function identity(value, name) {
|
|
6446
|
+
if (typeof value !== "string" || !value.trim() || value.length > 200) throw new TypeError(`${name} must be a nonempty string of at most 200 characters`);
|
|
6447
|
+
return value;
|
|
6448
|
+
}
|
|
6449
|
+
function exactOrigin(value) {
|
|
6450
|
+
const url2 = new URL(value);
|
|
6451
|
+
if (!["http:", "https:"].includes(url2.protocol) || url2.origin !== value) throw new TypeError("An exact HTTP(S) origin is required");
|
|
6452
|
+
return value;
|
|
6453
|
+
}
|
|
6454
|
+
function context(options) {
|
|
6455
|
+
const host = options.window || globalThis.window;
|
|
6456
|
+
if (!host?.document || !host.crypto?.randomUUID) throw new TypeError("A browser Window with crypto.randomUUID is required");
|
|
6457
|
+
return { host, channel: identity(options.channel, "channel"), assetId: identity(options.assetId, "assetId"), origin: exactOrigin(options.origin) };
|
|
6458
|
+
}
|
|
6459
|
+
function validState(value) {
|
|
6460
|
+
return value && typeof value === "object" && typeof value.time === "number" && Number.isFinite(value.time) && value.time >= 0 && typeof value.duration === "number" && Number.isFinite(value.duration) && value.duration > 0 && value.duration <= MAX_SECONDS && value.time <= value.duration + 0.25 && typeof value.rate === "number" && Number.isFinite(value.rate) && value.rate >= 0.0625 && value.rate <= 16 && ["paused", "ended", "seeking", "buffering", "error"].every((key) => typeof value[key] === "boolean");
|
|
6461
|
+
}
|
|
6462
|
+
function packet(data, channel, assetId) {
|
|
6463
|
+
return data && typeof data === "object" && data.protocol === PROTOCOL && data.channel === channel && data.assetId === assetId;
|
|
6464
|
+
}
|
|
6465
|
+
function resources(host) {
|
|
6466
|
+
const removers = [], timers = /* @__PURE__ */ new Set();
|
|
6467
|
+
return {
|
|
6468
|
+
listen(target, type, callback) {
|
|
6469
|
+
target.addEventListener(type, callback);
|
|
6470
|
+
removers.push(() => target.removeEventListener(type, callback));
|
|
6471
|
+
},
|
|
6472
|
+
later(callback, delay) {
|
|
6473
|
+
const id = host.setTimeout(() => {
|
|
6474
|
+
timers.delete(id);
|
|
6475
|
+
callback();
|
|
6476
|
+
}, delay);
|
|
6477
|
+
timers.add(id);
|
|
6478
|
+
return id;
|
|
6479
|
+
},
|
|
6480
|
+
cancel(id) {
|
|
6481
|
+
if (id) {
|
|
6482
|
+
host.clearTimeout(id);
|
|
6483
|
+
timers.delete(id);
|
|
6484
|
+
}
|
|
6485
|
+
},
|
|
6486
|
+
dispose() {
|
|
6487
|
+
removers.splice(0).forEach((remove) => remove());
|
|
6488
|
+
for (const id of timers) host.clearTimeout(id);
|
|
6489
|
+
timers.clear();
|
|
6490
|
+
},
|
|
6491
|
+
snapshot() {
|
|
6492
|
+
return { listeners: removers.length, timers: timers.size };
|
|
6493
|
+
}
|
|
6494
|
+
};
|
|
6495
|
+
}
|
|
6496
|
+
function createPlaybackPublisher(options = {}) {
|
|
6497
|
+
const { host, channel, assetId, origin } = context(options), source = options.source;
|
|
6498
|
+
const target = options.targetWindow || host.parent;
|
|
6499
|
+
if (!source?.addEventListener || !source?.pause || !target?.postMessage || target === host) throw new TypeError("A playback source and distinct target Window are required");
|
|
6500
|
+
const owners = publisherOwners.get(host) || /* @__PURE__ */ new Map(), key = JSON.stringify([origin, channel, assetId]);
|
|
6501
|
+
const routes = owners.get(target) || /* @__PURE__ */ new Set();
|
|
6502
|
+
if (routes.has(key)) throw new Error("Child playback route already has a publisher");
|
|
6503
|
+
const owned = resources(host);
|
|
6504
|
+
let session = null, sequence = 0, commandSequence = 0, timer = 0, destroyed = false, suspended = false, lastPublished = null;
|
|
6505
|
+
const envelope = (type, extra = {}) => ({ protocol: PROTOCOL, channel, assetId, session, type, ...extra });
|
|
6506
|
+
function send(type, extra) {
|
|
6507
|
+
target.postMessage(envelope(type, extra), origin);
|
|
6508
|
+
}
|
|
6509
|
+
function stop() {
|
|
6510
|
+
owned.cancel(timer);
|
|
6511
|
+
timer = 0;
|
|
6512
|
+
}
|
|
6513
|
+
function sample(event = "snapshot") {
|
|
6514
|
+
if (event === "timeupdate" && lastPublished !== null && host.performance.now() - lastPublished < 250) return;
|
|
6515
|
+
stop();
|
|
6516
|
+
if (destroyed || suspended || !session) return;
|
|
6517
|
+
const state = { time: Number(source.currentTime), duration: Number(source.duration), rate: Number(source.playbackRate), paused: !!source.paused, ended: !!source.ended, seeking: !!source.seeking, buffering: event === "waiting", error: !!source.error };
|
|
6518
|
+
if (!validState(state)) return;
|
|
6519
|
+
lastPublished = host.performance.now();
|
|
6520
|
+
send("state", { sequence: ++sequence, event, state });
|
|
6521
|
+
if (!state.paused && !state.ended && !state.error && !state.buffering && !host.document.hidden) timer = owned.later(() => sample(), 250);
|
|
6522
|
+
}
|
|
6523
|
+
function disconnect(reason) {
|
|
6524
|
+
stop();
|
|
6525
|
+
source.pause();
|
|
6526
|
+
if (session) send("disconnect", { reason });
|
|
6527
|
+
session = null;
|
|
6528
|
+
}
|
|
6529
|
+
function message(event) {
|
|
6530
|
+
const data = event.data;
|
|
6531
|
+
if (destroyed || suspended || event.source !== target || event.origin !== origin || !packet(data, channel, assetId)) return;
|
|
6532
|
+
if (data.type === "connect" && typeof data.session === "string" && /^[0-9a-f-]{36}$/i.test(data.session)) {
|
|
6533
|
+
if (session !== data.session) {
|
|
6534
|
+
session = data.session;
|
|
6535
|
+
sequence = 0;
|
|
6536
|
+
commandSequence = 0;
|
|
6537
|
+
lastPublished = null;
|
|
6538
|
+
}
|
|
6539
|
+
sample();
|
|
6540
|
+
return;
|
|
6541
|
+
}
|
|
6542
|
+
if (data.session !== session || !session) return;
|
|
6543
|
+
if (data.type === "disconnect") {
|
|
6544
|
+
disconnect("parent-disconnected");
|
|
6545
|
+
return;
|
|
6546
|
+
}
|
|
6547
|
+
if (data.type !== "command" || !Number.isSafeInteger(data.sequence) || data.sequence <= commandSequence) return;
|
|
6548
|
+
if (!["pause", "seek", "play"].includes(data.command)) return;
|
|
6549
|
+
if (data.command === "seek" && (typeof data.time !== "number" || !Number.isFinite(data.time) || data.time < 0 || data.time > Number(source.duration))) return;
|
|
6550
|
+
commandSequence = data.sequence;
|
|
6551
|
+
const currentSession = session;
|
|
6552
|
+
Promise.resolve().then(() => {
|
|
6553
|
+
if (destroyed || session !== currentSession) return;
|
|
6554
|
+
if (data.command === "pause") source.pause();
|
|
6555
|
+
else if (data.command === "seek") source.currentTime = data.time;
|
|
6556
|
+
else if (options.allowPlayCommands === true) return source.play();
|
|
6557
|
+
else throw new Error("Parent play commands are disabled");
|
|
6558
|
+
}).then(() => {
|
|
6559
|
+
if (!destroyed && session === currentSession) {
|
|
6560
|
+
sample();
|
|
6561
|
+
send("ack", { sequence: data.sequence, ok: true });
|
|
6562
|
+
}
|
|
6563
|
+
}, () => {
|
|
6564
|
+
if (!destroyed && session === currentSession) send("ack", { sequence: data.sequence, ok: false });
|
|
6565
|
+
});
|
|
6566
|
+
}
|
|
6567
|
+
owned.listen(host, "message", message);
|
|
6568
|
+
function requestClose() {
|
|
6569
|
+
if (!destroyed && !suspended && session) send("dismiss", { sequence: ++sequence });
|
|
6570
|
+
}
|
|
6571
|
+
if (options.notifyEscape === true) owned.listen(host.document, "keydown", (event) => {
|
|
6572
|
+
if (event.key === "Escape" && !event.defaultPrevented && !host.document.fullscreenElement) requestClose();
|
|
6573
|
+
});
|
|
6574
|
+
for (const event of EVENTS) if (event !== "snapshot") owned.listen(source, event, () => sample(event));
|
|
6575
|
+
owned.listen(host.document, "visibilitychange", () => {
|
|
6576
|
+
if (host.document.hidden) {
|
|
6577
|
+
stop();
|
|
6578
|
+
if (session) {
|
|
6579
|
+
sample("waiting");
|
|
6580
|
+
stop();
|
|
6581
|
+
}
|
|
6582
|
+
} else sample();
|
|
6583
|
+
});
|
|
6584
|
+
owned.listen(host, "pagehide", () => {
|
|
6585
|
+
suspended = true;
|
|
6586
|
+
disconnect("pagehide");
|
|
6587
|
+
});
|
|
6588
|
+
owned.listen(host, "pageshow", () => {
|
|
6589
|
+
if (!destroyed) {
|
|
6590
|
+
suspended = false;
|
|
6591
|
+
send("available");
|
|
6592
|
+
}
|
|
6593
|
+
});
|
|
6594
|
+
routes.add(key);
|
|
6595
|
+
owners.set(target, routes);
|
|
6596
|
+
publisherOwners.set(host, owners);
|
|
6597
|
+
send("available");
|
|
6598
|
+
return { requestClose, teardown() {
|
|
6599
|
+
if (destroyed) return;
|
|
6600
|
+
disconnect("teardown");
|
|
6601
|
+
destroyed = true;
|
|
6602
|
+
owned.dispose();
|
|
6603
|
+
routes.delete(key);
|
|
6604
|
+
if (!routes.size) owners.delete(target);
|
|
6605
|
+
}, snapshot() {
|
|
6606
|
+
return { kind: "child-publisher", connected: !!session, destroyed, suspended, ...owned.snapshot() };
|
|
6607
|
+
} };
|
|
6608
|
+
}
|
|
6609
|
+
function createPlaybackReceiver(options = {}) {
|
|
6610
|
+
const { host, channel, assetId, origin } = context(options), iframe = options.iframe;
|
|
6611
|
+
if (iframe?.tagName !== "IFRAME" || !iframe.contentWindow) throw new TypeError("An attached iframe is required");
|
|
6612
|
+
if (receiverOwners.has(iframe)) throw new Error("The child frame already has a playback receiver");
|
|
6613
|
+
const staleAfter = options.staleAfterMilliseconds ?? 1500;
|
|
6614
|
+
if (typeof staleAfter !== "number" || !Number.isFinite(staleAfter) || staleAfter < 750 || staleAfter > 1e4) throw new RangeError("staleAfterMilliseconds must be between 750 and 10000");
|
|
6615
|
+
const owned = resources(host), player = new host.EventTarget(), pending = /* @__PURE__ */ new Map();
|
|
6616
|
+
let session = "", sequence = 0, commands = 0, lastWall = 0, timer = 0, connectTimer = 0, destroyed = false, connected = false, status = "connecting";
|
|
6617
|
+
let state = { time: 0, duration: 0, rate: 1, paused: true, ended: false, seeking: false, buffering: false, error: false };
|
|
6618
|
+
let resolveReady, rejectReady, ready, readySettled = false;
|
|
6619
|
+
function prepareReady() {
|
|
6620
|
+
readySettled = false;
|
|
6621
|
+
ready = new Promise((resolve, reject) => {
|
|
6622
|
+
resolveReady = (value) => {
|
|
6623
|
+
readySettled = true;
|
|
6624
|
+
resolve(value);
|
|
6625
|
+
};
|
|
6626
|
+
rejectReady = (error) => {
|
|
6627
|
+
readySettled = true;
|
|
6628
|
+
reject(error);
|
|
6629
|
+
};
|
|
6630
|
+
});
|
|
6631
|
+
ready.catch(() => {
|
|
6632
|
+
});
|
|
6633
|
+
}
|
|
6634
|
+
prepareReady();
|
|
6635
|
+
const emit = (event) => player.dispatchEvent(new host.Event(event));
|
|
6636
|
+
const envelope = (type, extra = {}) => ({ protocol: PROTOCOL, channel, assetId, session, type, ...extra });
|
|
6637
|
+
function send(type, extra) {
|
|
6638
|
+
iframe.contentWindow?.postMessage(envelope(type, extra), origin);
|
|
6639
|
+
}
|
|
6640
|
+
function cancelPending() {
|
|
6641
|
+
for (const request of pending.values()) {
|
|
6642
|
+
owned.cancel(request.timer);
|
|
6643
|
+
request.reject(new Error("Child playback disconnected"));
|
|
6644
|
+
}
|
|
6645
|
+
pending.clear();
|
|
6646
|
+
}
|
|
6647
|
+
function stop(reason) {
|
|
6648
|
+
owned.cancel(timer);
|
|
6649
|
+
owned.cancel(connectTimer);
|
|
6650
|
+
timer = connectTimer = 0;
|
|
6651
|
+
const playing = !player.paused;
|
|
6652
|
+
state = { ...state, time: player.currentTime, paused: true, buffering: false };
|
|
6653
|
+
connected = false;
|
|
6654
|
+
status = reason;
|
|
6655
|
+
cancelPending();
|
|
6656
|
+
if (playing) emit("pause");
|
|
6657
|
+
}
|
|
6658
|
+
function connect() {
|
|
6659
|
+
if (destroyed) return ready;
|
|
6660
|
+
if (readySettled) prepareReady();
|
|
6661
|
+
stop("connecting");
|
|
6662
|
+
session = host.crypto.randomUUID();
|
|
6663
|
+
sequence = 0;
|
|
6664
|
+
send("connect");
|
|
6665
|
+
const started = host.performance.now();
|
|
6666
|
+
const retry = () => {
|
|
6667
|
+
if (destroyed || connected) return;
|
|
6668
|
+
if (host.performance.now() - started >= 1e4) {
|
|
6669
|
+
send("disconnect");
|
|
6670
|
+
stop("unavailable");
|
|
6671
|
+
session = "";
|
|
6672
|
+
rejectReady(new Error("Child playback did not become ready"));
|
|
6673
|
+
return;
|
|
6674
|
+
}
|
|
6675
|
+
send("connect");
|
|
6676
|
+
connectTimer = owned.later(retry, 500);
|
|
6677
|
+
};
|
|
6678
|
+
connectTimer = owned.later(retry, 500);
|
|
6679
|
+
return ready;
|
|
6680
|
+
}
|
|
6681
|
+
function command(name, time) {
|
|
6682
|
+
if (destroyed || !connected) return Promise.reject(new Error("Child playback is unavailable"));
|
|
6683
|
+
if (pending.size >= 16) return Promise.reject(new Error("Too many pending child playback commands"));
|
|
6684
|
+
const id = ++commands;
|
|
6685
|
+
return new Promise((resolve, reject) => {
|
|
6686
|
+
const timeout = owned.later(() => {
|
|
6687
|
+
pending.delete(id);
|
|
6688
|
+
reject(new Error("Child playback command timed out"));
|
|
6689
|
+
}, 2e3);
|
|
6690
|
+
pending.set(id, { resolve, reject, timer: timeout });
|
|
6691
|
+
send("command", { sequence: id, command: name, ...name === "seek" ? { time } : {} });
|
|
6692
|
+
});
|
|
6693
|
+
}
|
|
6694
|
+
Object.defineProperties(player, {
|
|
6695
|
+
nodeType: { value: 1 },
|
|
6696
|
+
tagName: { value: "VIDEO" },
|
|
6697
|
+
ownerDocument: { value: host.document },
|
|
6698
|
+
isConnected: { get: () => !destroyed && iframe.isConnected },
|
|
6699
|
+
currentTime: { get: () => Math.min(state.duration || MAX_SECONDS, state.time + (!player.paused && !state.seeking ? Math.min(500, Math.max(0, host.performance.now() - lastWall)) / 1e3 * state.rate : 0)), set: (value) => {
|
|
6700
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > state.duration) throw new RangeError("Seek must be inside the child duration");
|
|
6701
|
+
command("seek", value).catch(() => {
|
|
6702
|
+
});
|
|
6703
|
+
} },
|
|
6704
|
+
duration: { get: () => state.duration },
|
|
6705
|
+
paused: { get: () => state.paused || state.buffering || state.error || !connected },
|
|
6706
|
+
ended: { get: () => state.ended },
|
|
6707
|
+
seeking: { get: () => state.seeking },
|
|
6708
|
+
playbackRate: { get: () => state.rate },
|
|
6709
|
+
error: { get: () => state.error ? new Error("Child media error") : null }
|
|
6710
|
+
});
|
|
6711
|
+
player.play = () => command("play");
|
|
6712
|
+
player.pause = () => {
|
|
6713
|
+
command("pause").catch(() => {
|
|
6714
|
+
});
|
|
6715
|
+
};
|
|
6716
|
+
function message(event) {
|
|
6717
|
+
const data = event.data;
|
|
6718
|
+
if (destroyed || event.source !== iframe.contentWindow || event.origin !== origin || !packet(data, channel, assetId)) return;
|
|
6719
|
+
if (data.type === "available") {
|
|
6720
|
+
if (!host.document.hidden) {
|
|
6721
|
+
if (connected) send("connect");
|
|
6722
|
+
else connect();
|
|
6723
|
+
}
|
|
6724
|
+
return;
|
|
6725
|
+
}
|
|
6726
|
+
if (data.session !== session) return;
|
|
6727
|
+
if (data.type === "dismiss" && Number.isSafeInteger(data.sequence) && data.sequence > sequence) {
|
|
6728
|
+
sequence = data.sequence;
|
|
6729
|
+
emit("dismiss");
|
|
6730
|
+
return;
|
|
6731
|
+
}
|
|
6732
|
+
if (data.type === "disconnect") {
|
|
6733
|
+
stop("disconnected");
|
|
6734
|
+
session = "";
|
|
6735
|
+
return;
|
|
6736
|
+
}
|
|
6737
|
+
if (data.type === "ack" && Number.isSafeInteger(data.sequence) && typeof data.ok === "boolean") {
|
|
6738
|
+
const request = pending.get(data.sequence);
|
|
6739
|
+
if (request) {
|
|
6740
|
+
owned.cancel(request.timer);
|
|
6741
|
+
pending.delete(data.sequence);
|
|
6742
|
+
data.ok ? request.resolve() : request.reject(new Error("Child playback rejected the command"));
|
|
6743
|
+
}
|
|
6744
|
+
return;
|
|
6745
|
+
}
|
|
6746
|
+
if (data.type !== "state" || !Number.isSafeInteger(data.sequence) || data.sequence <= sequence || !EVENTS.has(data.event) || !validState(data.state)) return;
|
|
6747
|
+
const previous = state, wasConnected = connected, wasPaused = player.paused;
|
|
6748
|
+
sequence = data.sequence;
|
|
6749
|
+
state = { ...data.state };
|
|
6750
|
+
lastWall = host.performance.now();
|
|
6751
|
+
connected = true;
|
|
6752
|
+
status = "connected";
|
|
6753
|
+
owned.cancel(connectTimer);
|
|
6754
|
+
connectTimer = 0;
|
|
6755
|
+
owned.cancel(timer);
|
|
6756
|
+
timer = 0;
|
|
6757
|
+
if (!wasConnected) {
|
|
6758
|
+
emit("loadedmetadata");
|
|
6759
|
+
resolveReady(controller);
|
|
6760
|
+
} else if (previous.duration !== state.duration) emit("durationchange");
|
|
6761
|
+
if (previous.rate !== state.rate) emit("ratechange");
|
|
6762
|
+
if (state.seeking && !previous.seeking) emit("seeking");
|
|
6763
|
+
if (!state.seeking && previous.seeking) emit("seeked");
|
|
6764
|
+
if (!state.seeking && !previous.seeking && wasConnected && Math.abs(state.time - previous.time - (wasPaused ? 0 : (lastWall - previousWall) / 1e3 * previous.rate)) > 0.4) {
|
|
6765
|
+
emit("seeking");
|
|
6766
|
+
emit("seeked");
|
|
6767
|
+
}
|
|
6768
|
+
previousWall = lastWall;
|
|
6769
|
+
if (wasPaused && !player.paused) {
|
|
6770
|
+
emit("play");
|
|
6771
|
+
emit("playing");
|
|
6772
|
+
}
|
|
6773
|
+
if (!wasPaused && player.paused) emit("pause");
|
|
6774
|
+
if (state.ended && !previous.ended) emit("ended");
|
|
6775
|
+
if (data.event === "waiting") emit("waiting");
|
|
6776
|
+
if (state.error && !previous.error) emit("error");
|
|
6777
|
+
emit("timeupdate");
|
|
6778
|
+
if (!player.paused) timer = owned.later(() => {
|
|
6779
|
+
send("disconnect");
|
|
6780
|
+
stop("stale");
|
|
6781
|
+
session = "";
|
|
6782
|
+
emit("waiting");
|
|
6783
|
+
}, staleAfter);
|
|
6784
|
+
}
|
|
6785
|
+
let previousWall = 0;
|
|
6786
|
+
owned.listen(host, "message", message);
|
|
6787
|
+
owned.listen(iframe, "load", connect);
|
|
6788
|
+
owned.listen(host, "pagehide", () => {
|
|
6789
|
+
send("disconnect");
|
|
6790
|
+
stop("suspended");
|
|
6791
|
+
session = "";
|
|
6792
|
+
});
|
|
6793
|
+
owned.listen(host, "pageshow", connect);
|
|
6794
|
+
owned.listen(host.document, "visibilitychange", () => {
|
|
6795
|
+
if (host.document.hidden) {
|
|
6796
|
+
send("command", { sequence: ++commands, command: "pause" });
|
|
6797
|
+
stop("hidden");
|
|
6798
|
+
session = "";
|
|
6799
|
+
} else connect();
|
|
6800
|
+
});
|
|
6801
|
+
const observer = new host.MutationObserver(() => {
|
|
6802
|
+
if (!iframe.isConnected) controller.teardown();
|
|
6803
|
+
});
|
|
6804
|
+
observer.observe(host.document.documentElement, { childList: true, subtree: true });
|
|
6805
|
+
const controller = { player, get ready() {
|
|
6806
|
+
return ready;
|
|
6807
|
+
}, reconnect: connect, teardown() {
|
|
6808
|
+
if (destroyed) return;
|
|
6809
|
+
send("command", { sequence: ++commands, command: "pause" });
|
|
6810
|
+
send("disconnect");
|
|
6811
|
+
stop("destroyed");
|
|
6812
|
+
destroyed = true;
|
|
6813
|
+
session = "";
|
|
6814
|
+
rejectReady(new Error("Child playback owner removed"));
|
|
6815
|
+
observer.disconnect();
|
|
6816
|
+
owned.dispose();
|
|
6817
|
+
receiverOwners.delete(iframe);
|
|
6818
|
+
}, snapshot() {
|
|
6819
|
+
return { kind: "child-receiver", status, connected, destroyed, time: player.currentTime, paused: player.paused, assetId, ...owned.snapshot() };
|
|
6820
|
+
} };
|
|
6821
|
+
receiverOwners.set(iframe, controller);
|
|
6822
|
+
connect();
|
|
6823
|
+
return controller;
|
|
6824
|
+
}
|
|
6825
|
+
function installChildPlayback(scope, api, host) {
|
|
6826
|
+
function own(controller) {
|
|
6827
|
+
const teardown = controller.teardown.bind(controller);
|
|
6828
|
+
const remove = scope.onDispose(() => teardown());
|
|
6829
|
+
controller.teardown = () => {
|
|
6830
|
+
remove();
|
|
6831
|
+
teardown();
|
|
6832
|
+
};
|
|
6833
|
+
return controller;
|
|
6834
|
+
}
|
|
6835
|
+
api.publishPlayback = (options) => {
|
|
6836
|
+
if (api.destroyed) throw new Error("DanceMoves owner is destroyed");
|
|
6837
|
+
return own(createPlaybackPublisher({ ...options, window: host }));
|
|
6838
|
+
};
|
|
6839
|
+
api.receiveChildPlayback = (options) => {
|
|
6840
|
+
if (api.destroyed) throw new Error("DanceMoves owner is destroyed");
|
|
6841
|
+
if (typeof api.registerPlaybackProvider !== "function") throw new Error("The shared playback provider API is required");
|
|
6842
|
+
if (options?.masterVerified !== true) throw new TypeError("An explicitly verified master association is required");
|
|
6843
|
+
const receiver = createPlaybackReceiver({ ...options, window: host });
|
|
6844
|
+
let registration;
|
|
6845
|
+
try {
|
|
6846
|
+
registration = api.registerPlaybackProvider({ ...options, player: receiver.player });
|
|
6847
|
+
} catch (error) {
|
|
6848
|
+
receiver.teardown();
|
|
6849
|
+
throw error;
|
|
6850
|
+
}
|
|
6851
|
+
return own({ source: registration.source, player: receiver.player, get ready() {
|
|
6852
|
+
return receiver.ready;
|
|
6853
|
+
}, mapping: registration.mapping, reconnect: receiver.reconnect, teardown() {
|
|
6854
|
+
receiver.teardown();
|
|
6855
|
+
registration.teardown();
|
|
6856
|
+
}, snapshot() {
|
|
6857
|
+
return { ...receiver.snapshot(), mapping: registration.mapping };
|
|
6858
|
+
} });
|
|
6859
|
+
};
|
|
6860
|
+
}
|
|
6861
|
+
|
|
5952
6862
|
// .build/modules/version.mjs
|
|
5953
|
-
var VERSION = "3.1.
|
|
6863
|
+
var VERSION = "3.1.21";
|
|
5954
6864
|
|
|
5955
6865
|
// .build/modules/index.mjs
|
|
5956
6866
|
var mounted = /* @__PURE__ */ new WeakMap();
|
|
@@ -5985,6 +6895,7 @@ function createDanceMoves(options = {}) {
|
|
|
5985
6895
|
}
|
|
5986
6896
|
try {
|
|
5987
6897
|
runtime_default.core(scope);
|
|
6898
|
+
installPlayback(scope, w.DanceMoves, root.ownerDocument.defaultView);
|
|
5988
6899
|
runtime_default.effects(scope);
|
|
5989
6900
|
runtime_default.orientationCore(scope);
|
|
5990
6901
|
runtime_default.native(scope);
|
|
@@ -6017,6 +6928,7 @@ function createDanceMoves(options = {}) {
|
|
|
6017
6928
|
}
|
|
6018
6929
|
});
|
|
6019
6930
|
Object.defineProperty(api, "destroyed", { get: () => scope.disposed });
|
|
6931
|
+
installChildPlayback(scope, api, ownerDocument.defaultView);
|
|
6020
6932
|
api.ready = Promise.resolve(api.ready).then(() => {
|
|
6021
6933
|
if (!scope.disposed) scope.document.dispatchEvent(new w.CustomEvent("dance-moves-ready", {
|
|
6022
6934
|
bubbles: true,
|