@scarlett-player/embed 1.5.0 → 1.6.0
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/README.md +1 -1
- package/dist/embed.audio.js +304 -4
- package/dist/embed.audio.js.map +1 -1
- package/dist/embed.audio.umd.cjs +1 -1
- package/dist/embed.audio.umd.cjs.map +1 -1
- package/dist/embed.js +488 -56
- package/dist/embed.js.map +1 -1
- package/dist/embed.umd.cjs +1 -1
- package/dist/embed.umd.cjs.map +1 -1
- package/dist/embed.video.js +119 -3
- package/dist/embed.video.js.map +1 -1
- package/dist/embed.video.umd.cjs +1 -1
- package/dist/embed.video.umd.cjs.map +1 -1
- package/dist/hls2.js +12 -0
- package/dist/hls2.js.map +1 -0
- package/iframe.html +1 -1
- package/package.json +10 -10
package/dist/embed.video.js
CHANGED
|
@@ -180,8 +180,8 @@ class StateManager {
|
|
|
180
180
|
* Register a state key at runtime, for state a plugin owns.
|
|
181
181
|
*
|
|
182
182
|
* Core cannot know every plugin's keys, and {@link get} deliberately throws
|
|
183
|
-
* for unregistered ones
|
|
184
|
-
* keeping
|
|
183
|
+
* for unregistered ones - that throw is a useful typo-catcher and is worth
|
|
184
|
+
* keeping - so a plugin declares its keys before first use.
|
|
185
185
|
*
|
|
186
186
|
* Idempotent by design: re-defining an existing key leaves the current value
|
|
187
187
|
* untouched. Plugins commonly re-run setup after a source change, and that
|
|
@@ -1259,7 +1259,7 @@ class PluginAPI {
|
|
|
1259
1259
|
/**
|
|
1260
1260
|
* Register a state key this plugin owns, before first use.
|
|
1261
1261
|
*
|
|
1262
|
-
* Idempotent
|
|
1262
|
+
* Idempotent - re-defining an existing key keeps its current value.
|
|
1263
1263
|
* See {@link IPluginAPI.defineState}.
|
|
1264
1264
|
*
|
|
1265
1265
|
* @param key - State property key
|
|
@@ -3635,6 +3635,25 @@ var styles = `
|
|
|
3635
3635
|
border-radius: inherit;
|
|
3636
3636
|
}
|
|
3637
3637
|
|
|
3638
|
+
/* Chapter markers */
|
|
3639
|
+
.sp-progress__markers {
|
|
3640
|
+
position: absolute;
|
|
3641
|
+
top: 0;
|
|
3642
|
+
left: 0;
|
|
3643
|
+
width: 100%;
|
|
3644
|
+
height: 100%;
|
|
3645
|
+
pointer-events: none;
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
.sp-progress__marker {
|
|
3649
|
+
position: absolute;
|
|
3650
|
+
top: 0;
|
|
3651
|
+
width: 2px;
|
|
3652
|
+
height: 100%;
|
|
3653
|
+
margin-left: -1px;
|
|
3654
|
+
background: rgba(0, 0, 0, 0.65);
|
|
3655
|
+
}
|
|
3656
|
+
|
|
3638
3657
|
.sp-progress__handle {
|
|
3639
3658
|
position: absolute;
|
|
3640
3659
|
top: 50%;
|
|
@@ -3694,6 +3713,16 @@ var styles = `
|
|
|
3694
3713
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
3695
3714
|
}
|
|
3696
3715
|
|
|
3716
|
+
.sp-progress__tooltip-chapter {
|
|
3717
|
+
display: block;
|
|
3718
|
+
max-width: 220px;
|
|
3719
|
+
overflow: hidden;
|
|
3720
|
+
color: rgba(255, 255, 255, 0.75);
|
|
3721
|
+
font-weight: 400;
|
|
3722
|
+
font-variant-numeric: normal;
|
|
3723
|
+
text-overflow: ellipsis;
|
|
3724
|
+
}
|
|
3725
|
+
|
|
3697
3726
|
@media (hover: hover) {
|
|
3698
3727
|
.sp-progress-wrapper:hover .sp-progress__tooltip {
|
|
3699
3728
|
opacity: 1;
|
|
@@ -4531,6 +4560,8 @@ var ProgressBar = class {
|
|
|
4531
4560
|
this.lastSeekTime = 0;
|
|
4532
4561
|
this.seekThrottleMs = 100;
|
|
4533
4562
|
this.wasPlayingBeforeDrag = false;
|
|
4563
|
+
this.renderedChapters = null;
|
|
4564
|
+
this.renderedDuration = 0;
|
|
4534
4565
|
this.onMouseDown = (e) => {
|
|
4535
4566
|
e.preventDefault();
|
|
4536
4567
|
const video = getVideo(this.api.container);
|
|
@@ -4665,12 +4696,14 @@ var ProgressBar = class {
|
|
|
4665
4696
|
const track = createElement("div", { className: "sp-progress__track" });
|
|
4666
4697
|
this.buffered = createElement("div", { className: "sp-progress__buffered" });
|
|
4667
4698
|
this.filled = createElement("div", { className: "sp-progress__filled" });
|
|
4699
|
+
this.markers = createElement("div", { className: "sp-progress__markers" });
|
|
4668
4700
|
this.handle = createElement("div", { className: "sp-progress__handle" });
|
|
4669
4701
|
this.tooltip = createElement("div", { className: "sp-progress__tooltip" });
|
|
4670
4702
|
this.tooltip.textContent = "0:00";
|
|
4671
4703
|
this.thumbnailPreview = new ThumbnailPreview();
|
|
4672
4704
|
track.appendChild(this.buffered);
|
|
4673
4705
|
track.appendChild(this.filled);
|
|
4706
|
+
track.appendChild(this.markers);
|
|
4674
4707
|
track.appendChild(this.handle);
|
|
4675
4708
|
this.el.appendChild(track);
|
|
4676
4709
|
this.el.appendChild(this.thumbnailPreview.getElement());
|
|
@@ -4720,6 +4753,7 @@ var ProgressBar = class {
|
|
|
4720
4753
|
this.thumbnailPreview.setConfig(thumbnails);
|
|
4721
4754
|
}
|
|
4722
4755
|
this.el.classList.toggle("sp-progress--live", !!live);
|
|
4756
|
+
this.updateMarkers(duration, live, seekableRange);
|
|
4723
4757
|
if (live && seekableRange) {
|
|
4724
4758
|
const rangeLength = seekableRange.end - seekableRange.start;
|
|
4725
4759
|
if (rangeLength > 0) {
|
|
@@ -4752,6 +4786,70 @@ var ProgressBar = class {
|
|
|
4752
4786
|
this.el.setAttribute("aria-valuetext", formatTime(currentTime));
|
|
4753
4787
|
}
|
|
4754
4788
|
}
|
|
4789
|
+
/**
|
|
4790
|
+
* Label of the chapter containing a point on the timeline.
|
|
4791
|
+
*
|
|
4792
|
+
* Mirrors the chapters plugin's own lookup: a start time belongs to its
|
|
4793
|
+
* chapter, an end time belongs to the next one, and a point in a gap between
|
|
4794
|
+
* sparse chapters belongs to neither.
|
|
4795
|
+
*
|
|
4796
|
+
* @param time - Position in seconds
|
|
4797
|
+
* @returns The chapter label, or null when the point is outside every chapter
|
|
4798
|
+
*/
|
|
4799
|
+
chapterLabelAt(time) {
|
|
4800
|
+
const chapters = this.api.getState("chapters") ?? [];
|
|
4801
|
+
for (let i = chapters.length - 1; i >= 0; i--) {
|
|
4802
|
+
const chapter = chapters[i];
|
|
4803
|
+
if (time < chapter.time) continue;
|
|
4804
|
+
const next = chapters[i + 1];
|
|
4805
|
+
const end = chapter.endTime ?? (next ? next.time : Infinity);
|
|
4806
|
+
return time < end ? chapter.label : null;
|
|
4807
|
+
}
|
|
4808
|
+
return null;
|
|
4809
|
+
}
|
|
4810
|
+
/**
|
|
4811
|
+
* Paint chapter dividers along the track.
|
|
4812
|
+
*
|
|
4813
|
+
* Reads the `chapters` state that core owns, so this works whether the list
|
|
4814
|
+
* came from the chapters plugin or the host set it directly, and renders
|
|
4815
|
+
* nothing at all when there are none.
|
|
4816
|
+
*
|
|
4817
|
+
* Rebuilds only when the list or the duration actually changed. `update()`
|
|
4818
|
+
* runs on every time update, and rebuilding a dozen nodes 4 times a second
|
|
4819
|
+
* would churn the DOM for no reason.
|
|
4820
|
+
*
|
|
4821
|
+
* @param duration - Media duration in seconds
|
|
4822
|
+
* @param live - Whether the media is live
|
|
4823
|
+
* @param seekableRange - DVR window, when the media is live
|
|
4824
|
+
*/
|
|
4825
|
+
updateMarkers(duration, live, seekableRange) {
|
|
4826
|
+
const chapters = this.api.getState("chapters") ?? [];
|
|
4827
|
+
const range = live ? seekableRange ? seekableRange.end - seekableRange.start : 0 : duration;
|
|
4828
|
+
if (chapters.length === 0 || range <= 0) {
|
|
4829
|
+
if (this.renderedChapters !== null) {
|
|
4830
|
+
this.markers.textContent = "";
|
|
4831
|
+
this.renderedChapters = null;
|
|
4832
|
+
this.renderedDuration = 0;
|
|
4833
|
+
}
|
|
4834
|
+
return;
|
|
4835
|
+
}
|
|
4836
|
+
if (chapters === this.renderedChapters && range === this.renderedDuration) {
|
|
4837
|
+
return;
|
|
4838
|
+
}
|
|
4839
|
+
const origin = live && seekableRange ? seekableRange.start : 0;
|
|
4840
|
+
this.markers.textContent = "";
|
|
4841
|
+
for (const chapter of chapters) {
|
|
4842
|
+
if (chapter.time <= origin) continue;
|
|
4843
|
+
const percent = (chapter.time - origin) / range * 100;
|
|
4844
|
+
if (percent <= 0 || percent >= 100) continue;
|
|
4845
|
+
const marker = createElement("div", { className: "sp-progress__marker" });
|
|
4846
|
+
marker.style.left = `${percent}%`;
|
|
4847
|
+
marker.title = chapter.label;
|
|
4848
|
+
this.markers.appendChild(marker);
|
|
4849
|
+
}
|
|
4850
|
+
this.renderedChapters = chapters;
|
|
4851
|
+
this.renderedDuration = range;
|
|
4852
|
+
}
|
|
4755
4853
|
getTimeFromPosition(clientX) {
|
|
4756
4854
|
const rect = this.el.getBoundingClientRect();
|
|
4757
4855
|
const percent = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
@@ -4776,6 +4874,12 @@ var ProgressBar = class {
|
|
|
4776
4874
|
} else {
|
|
4777
4875
|
this.tooltip.textContent = formatTime(time);
|
|
4778
4876
|
}
|
|
4877
|
+
const chapterLabel = this.chapterLabelAt(time);
|
|
4878
|
+
if (chapterLabel) {
|
|
4879
|
+
const label = createElement("span", { className: "sp-progress__tooltip-chapter" });
|
|
4880
|
+
label.textContent = chapterLabel;
|
|
4881
|
+
this.tooltip.appendChild(label);
|
|
4882
|
+
}
|
|
4779
4883
|
this.tooltip.style.left = `${percent * 100}%`;
|
|
4780
4884
|
if (this.thumbnailPreview.isConfigured()) {
|
|
4781
4885
|
this.thumbnailPreview.show(time, percent);
|
|
@@ -6187,7 +6291,15 @@ function uiPlugin(config = {}) {
|
|
|
6187
6291
|
}
|
|
6188
6292
|
hideTimeout = setTimeout(hideControls, hideDelay);
|
|
6189
6293
|
};
|
|
6294
|
+
let last_pointer_type = null;
|
|
6295
|
+
const handlePointerActivity = (event) => {
|
|
6296
|
+
last_pointer_type = event.pointerType;
|
|
6297
|
+
};
|
|
6190
6298
|
const handleInteraction = () => {
|
|
6299
|
+
if (last_pointer_type === "touch") {
|
|
6300
|
+
const gestures = api?.getPlugin("gestures");
|
|
6301
|
+
if (gestures?.ownsTapInteraction()) return;
|
|
6302
|
+
}
|
|
6191
6303
|
showControls();
|
|
6192
6304
|
};
|
|
6193
6305
|
const handleMouseLeave = () => {
|
|
@@ -6321,6 +6433,8 @@ function uiPlugin(config = {}) {
|
|
|
6321
6433
|
api.logger.debug(`Control "${id}" registered after init, rebuilding control bar`);
|
|
6322
6434
|
rebuildControlBar();
|
|
6323
6435
|
});
|
|
6436
|
+
container.addEventListener("pointerdown", handlePointerActivity, { passive: true });
|
|
6437
|
+
container.addEventListener("pointermove", handlePointerActivity, { passive: true });
|
|
6324
6438
|
container.addEventListener("mousemove", handleInteraction);
|
|
6325
6439
|
container.addEventListener("mouseenter", handleInteraction);
|
|
6326
6440
|
container.addEventListener("mouseleave", handleMouseLeave);
|
|
@@ -6358,6 +6472,8 @@ function uiPlugin(config = {}) {
|
|
|
6358
6472
|
recoveredUnsubscribe?.();
|
|
6359
6473
|
recoveredUnsubscribe = null;
|
|
6360
6474
|
if (api?.container) {
|
|
6475
|
+
api.container.removeEventListener("pointerdown", handlePointerActivity);
|
|
6476
|
+
api.container.removeEventListener("pointermove", handlePointerActivity);
|
|
6361
6477
|
api.container.removeEventListener("mousemove", handleInteraction);
|
|
6362
6478
|
api.container.removeEventListener("mouseenter", handleInteraction);
|
|
6363
6479
|
api.container.removeEventListener("mouseleave", handleMouseLeave);
|