@kodezen/player 1.0.2 → 1.0.4
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 +21 -1
- package/dist/index.cjs +244 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -3
- package/dist/index.d.ts +17 -3
- package/dist/index.js +244 -19
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +248 -21
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +248 -21
- package/dist/react/index.js.map +1 -1
- package/dist/styles.css +100 -9
- package/dist/{types-TFltFgey.d.cts → types-30yBj4ll.d.cts} +20 -1
- package/dist/{types-TFltFgey.d.ts → types-30yBj4ll.d.ts} +20 -1
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -96,8 +96,7 @@ var Html5Provider = class {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
play() {
|
|
99
|
-
void this.video.play().catch(() =>
|
|
100
|
-
});
|
|
99
|
+
void this.video.play().catch(() => this.emitter.emit("pause"));
|
|
101
100
|
}
|
|
102
101
|
pause() {
|
|
103
102
|
this.video.pause();
|
|
@@ -379,8 +378,8 @@ var VimeoProvider = class {
|
|
|
379
378
|
this.emitter.emit("ready");
|
|
380
379
|
}
|
|
381
380
|
play() {
|
|
382
|
-
var _a, _b;
|
|
383
|
-
|
|
381
|
+
var _a, _b, _c, _d;
|
|
382
|
+
(_d = (_c = (_b = (_a = this.player) == null ? void 0 : _a.play) == null ? void 0 : _b.call(_a)) == null ? void 0 : _c.catch) == null ? void 0 : _d.call(_c, () => this.emitter.emit("pause"));
|
|
384
383
|
}
|
|
385
384
|
pause() {
|
|
386
385
|
var _a, _b;
|
|
@@ -450,13 +449,124 @@ function createProvider(source) {
|
|
|
450
449
|
}
|
|
451
450
|
}
|
|
452
451
|
|
|
452
|
+
// src/core/Captions.ts
|
|
453
|
+
var TIMING = /^\s*((?:\d+:)?\d{1,2}:\d{2}[.,]\d{1,3})\s+-->\s+((?:\d+:)?\d{1,2}:\d{2}[.,]\d{1,3})/;
|
|
454
|
+
var ENTITIES = {
|
|
455
|
+
amp: "&",
|
|
456
|
+
lt: "<",
|
|
457
|
+
gt: ">",
|
|
458
|
+
quot: '"',
|
|
459
|
+
apos: "'",
|
|
460
|
+
nbsp: "\xA0",
|
|
461
|
+
lrm: "\u200E",
|
|
462
|
+
rlm: "\u200F"
|
|
463
|
+
};
|
|
464
|
+
function toSeconds(stamp) {
|
|
465
|
+
const [clock = "", fraction = "0"] = stamp.replace(",", ".").split(".");
|
|
466
|
+
const seconds = clock.split(":").reduce((total, part) => total * 60 + Number(part), 0);
|
|
467
|
+
return seconds + Number(`0.${fraction}`);
|
|
468
|
+
}
|
|
469
|
+
function plainText(text) {
|
|
470
|
+
return text.replace(/<[^>]*>/g, "").replace(/&(amp|lt|gt|quot|apos|nbsp|lrm|rlm);/g, (_, name) => {
|
|
471
|
+
var _a;
|
|
472
|
+
return (_a = ENTITIES[name]) != null ? _a : "";
|
|
473
|
+
}).replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code)));
|
|
474
|
+
}
|
|
475
|
+
function parseVtt(input) {
|
|
476
|
+
var _a;
|
|
477
|
+
const cues = [];
|
|
478
|
+
const blocks = input.replace(/^/, "").replace(/\r\n?/g, "\n").split(/\n{2,}/);
|
|
479
|
+
for (const block of blocks) {
|
|
480
|
+
const lines = block.split("\n");
|
|
481
|
+
const timingAt = lines.findIndex((line) => line.includes("-->"));
|
|
482
|
+
const timing = TIMING.exec((_a = lines[timingAt]) != null ? _a : "");
|
|
483
|
+
if (!(timing == null ? void 0 : timing[1]) || !timing[2]) continue;
|
|
484
|
+
const text = plainText(lines.slice(timingAt + 1).join("\n")).trim();
|
|
485
|
+
if (!text) continue;
|
|
486
|
+
cues.push({ start: toSeconds(timing[1]), end: toSeconds(timing[2]), text });
|
|
487
|
+
}
|
|
488
|
+
return cues.sort((a, b) => a.start - b.start);
|
|
489
|
+
}
|
|
490
|
+
var Captions = class {
|
|
491
|
+
/** `onChange` fires when the active track or track availability changes. */
|
|
492
|
+
constructor(tracks, onChange) {
|
|
493
|
+
this.onChange = onChange;
|
|
494
|
+
this.active = -1;
|
|
495
|
+
this.time = 0;
|
|
496
|
+
this.abort = new AbortController();
|
|
497
|
+
this.el = document.createElement("div");
|
|
498
|
+
this.el.className = "kzp-captions";
|
|
499
|
+
this.el.setAttribute("aria-live", "off");
|
|
500
|
+
this.text = document.createElement("span");
|
|
501
|
+
this.text.className = "kzp-captions-text";
|
|
502
|
+
this.text.hidden = true;
|
|
503
|
+
this.el.appendChild(this.text);
|
|
504
|
+
this.tracks = tracks.map((info) => ({ info, cues: null, failed: false }));
|
|
505
|
+
const preferred = tracks.findIndex((t) => t.default);
|
|
506
|
+
this.tracks.forEach((track, index) => {
|
|
507
|
+
void this.load(track).then(() => {
|
|
508
|
+
if (index === preferred && this.active === -1 && track.cues) this.select(index);
|
|
509
|
+
else this.onChange();
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
async load(track) {
|
|
514
|
+
try {
|
|
515
|
+
const res = await fetch(track.info.src, { signal: this.abort.signal, credentials: "same-origin" });
|
|
516
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
517
|
+
track.cues = parseVtt(await res.text());
|
|
518
|
+
} catch (err) {
|
|
519
|
+
if (this.abort.signal.aborted) return;
|
|
520
|
+
track.failed = true;
|
|
521
|
+
console.warn(`@kodezen/player: could not load captions from ${track.info.src}`, err);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/** Labels for the menu, one per track (falls back to the language, then a number). */
|
|
525
|
+
labels() {
|
|
526
|
+
return this.tracks.map((t, i) => t.info.label || t.info.srclang || `Track ${i + 1}`);
|
|
527
|
+
}
|
|
528
|
+
/** Whether each track loaded (a failed track is hidden from the controls). */
|
|
529
|
+
available() {
|
|
530
|
+
return this.tracks.map((t) => !t.failed);
|
|
531
|
+
}
|
|
532
|
+
getActive() {
|
|
533
|
+
return this.active;
|
|
534
|
+
}
|
|
535
|
+
/** Show track `index`, or turn captions off with -1. */
|
|
536
|
+
select(index) {
|
|
537
|
+
var _a;
|
|
538
|
+
const track = this.tracks[index];
|
|
539
|
+
this.active = track && !track.failed ? index : -1;
|
|
540
|
+
this.el.lang = (_a = track == null ? void 0 : track.info.srclang) != null ? _a : "";
|
|
541
|
+
this.render();
|
|
542
|
+
this.onChange();
|
|
543
|
+
}
|
|
544
|
+
/** Called with the playhead position on every tick and after a seek. */
|
|
545
|
+
update(time) {
|
|
546
|
+
this.time = time;
|
|
547
|
+
this.render();
|
|
548
|
+
}
|
|
549
|
+
render() {
|
|
550
|
+
var _a, _b;
|
|
551
|
+
const cues = (_b = (_a = this.tracks[this.active]) == null ? void 0 : _a.cues) != null ? _b : [];
|
|
552
|
+
const text = cues.filter((cue) => this.time >= cue.start && this.time < cue.end).map((cue) => cue.text).join("\n");
|
|
553
|
+
if (text !== this.text.textContent) this.text.textContent = text;
|
|
554
|
+
this.text.hidden = !text;
|
|
555
|
+
}
|
|
556
|
+
destroy() {
|
|
557
|
+
this.abort.abort();
|
|
558
|
+
this.el.remove();
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
|
|
453
562
|
// src/core/Controls.ts
|
|
454
563
|
var ICONS = {
|
|
455
564
|
play: '<path d="M8 5v14l11-7z"/>',
|
|
456
565
|
pause: '<path d="M6 5h4v14H6zM14 5h4v14h-4z"/>',
|
|
457
566
|
volume: '<path d="M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4v8a4.5 4.5 0 0 0 2.5-4z"/>',
|
|
458
567
|
muted: '<path d="M3 10v4h4l5 5V5L7 10H3zm13 2 3 3 1-1-3-3 3-3-1-1-3 3-3-3-1 1 3 3-3 3 1 1z"/>',
|
|
459
|
-
full: '<path d="M4 4h6v2H6v4H4V4zm10 0h6v6h-2V6h-4V4zM4 14h2v4h4v2H4v-6zm14 0h2v6h-6v-2h4v-4z"/>'
|
|
568
|
+
full: '<path d="M4 4h6v2H6v4H4V4zm10 0h6v6h-2V6h-4V4zM4 14h2v4h4v2H4v-6zm14 0h2v6h-6v-2h4v-4z"/>',
|
|
569
|
+
captions: '<path d="M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1z"/>'
|
|
460
570
|
};
|
|
461
571
|
function icon(paths) {
|
|
462
572
|
return `<svg viewBox="0 0 24 24" aria-hidden="true">${paths}</svg>`;
|
|
@@ -476,20 +586,34 @@ var DEFAULT_CONFIG = {
|
|
|
476
586
|
time: true,
|
|
477
587
|
volume: true,
|
|
478
588
|
speed: true,
|
|
589
|
+
captions: true,
|
|
479
590
|
fullscreen: true
|
|
480
591
|
};
|
|
481
592
|
var Controls = class {
|
|
482
593
|
constructor(cb, opts) {
|
|
483
594
|
this.cb = cb;
|
|
595
|
+
this.ccActive = -1;
|
|
596
|
+
// Icons currently drawn, so update() only rewrites a button's SVG when it
|
|
597
|
+
// actually changes (see update()).
|
|
598
|
+
this.playIcon = "";
|
|
599
|
+
this.volIcon = "";
|
|
484
600
|
this.scrubbing = false;
|
|
601
|
+
this.rate = 0;
|
|
602
|
+
this.onOutsideClick = (e) => {
|
|
603
|
+
if (this.el.contains(e.target)) return;
|
|
604
|
+
if (this.speedMenu) this.speedMenu.hidden = true;
|
|
605
|
+
if (this.ccMenu) this.ccMenu.hidden = true;
|
|
606
|
+
};
|
|
485
607
|
this.seekableMax = Infinity;
|
|
608
|
+
var _a;
|
|
486
609
|
this.config = { ...DEFAULT_CONFIG, ...opts.config };
|
|
487
610
|
this.lockSeek = opts.lockSeek;
|
|
488
611
|
this.el = document.createElement("div");
|
|
489
612
|
this.el.className = "kzp-controls";
|
|
490
|
-
this.build(opts.speeds);
|
|
613
|
+
this.build(opts.speeds, (_a = opts.captionLabels) != null ? _a : []);
|
|
614
|
+
document.addEventListener("click", this.onOutsideClick);
|
|
491
615
|
}
|
|
492
|
-
build(speeds) {
|
|
616
|
+
build(speeds, captionLabels) {
|
|
493
617
|
if (this.config.playPause) {
|
|
494
618
|
this.playBtn = this.button("kzp-play", "Play", ICONS.play);
|
|
495
619
|
this.playBtn.addEventListener("click", () => this.cb.onToggle());
|
|
@@ -566,16 +690,72 @@ var Controls = class {
|
|
|
566
690
|
}
|
|
567
691
|
this.speedBtn.addEventListener("click", () => {
|
|
568
692
|
this.speedMenu.hidden = !this.speedMenu.hidden;
|
|
693
|
+
if (this.ccMenu) this.ccMenu.hidden = true;
|
|
569
694
|
});
|
|
570
695
|
wrap.append(this.speedBtn, this.speedMenu);
|
|
571
696
|
this.el.appendChild(wrap);
|
|
572
697
|
}
|
|
698
|
+
if (this.config.captions && captionLabels.length) {
|
|
699
|
+
this.buildCaptions(captionLabels);
|
|
700
|
+
}
|
|
573
701
|
if (this.config.fullscreen) {
|
|
574
702
|
const btn = this.button("kzp-full", "Fullscreen", ICONS.full);
|
|
575
703
|
btn.addEventListener("click", () => this.cb.onFullscreen());
|
|
576
704
|
this.el.appendChild(btn);
|
|
577
705
|
}
|
|
578
706
|
}
|
|
707
|
+
/**
|
|
708
|
+
* One track: the CC button toggles it. Several: it opens a menu (Off + each
|
|
709
|
+
* track), styled like the speed menu. Sits left of the speed control.
|
|
710
|
+
*/
|
|
711
|
+
buildCaptions(labels) {
|
|
712
|
+
const wrap = document.createElement("div");
|
|
713
|
+
wrap.className = "kzp-cc";
|
|
714
|
+
this.ccBtn = this.button("kzp-cc-btn", "Subtitles/closed captions", ICONS.captions);
|
|
715
|
+
this.ccBtn.setAttribute("aria-pressed", "false");
|
|
716
|
+
wrap.appendChild(this.ccBtn);
|
|
717
|
+
if (labels.length === 1) {
|
|
718
|
+
this.ccBtn.addEventListener("click", () => this.cb.onCaptions(this.ccActive === -1 ? 0 : -1));
|
|
719
|
+
} else {
|
|
720
|
+
this.ccMenu = document.createElement("div");
|
|
721
|
+
this.ccMenu.className = "kzp-speed-menu kzp-cc-menu";
|
|
722
|
+
this.ccMenu.hidden = true;
|
|
723
|
+
const items = [{ index: -1, label: "Off" }, ...labels.map((label, index) => ({ index, label }))];
|
|
724
|
+
for (const { index, label } of items) {
|
|
725
|
+
const item = document.createElement("button");
|
|
726
|
+
item.type = "button";
|
|
727
|
+
item.textContent = label;
|
|
728
|
+
item.dataset.track = String(index);
|
|
729
|
+
item.addEventListener("click", () => {
|
|
730
|
+
this.cb.onCaptions(index);
|
|
731
|
+
this.ccMenu.hidden = true;
|
|
732
|
+
});
|
|
733
|
+
this.ccMenu.appendChild(item);
|
|
734
|
+
}
|
|
735
|
+
this.ccBtn.addEventListener("click", () => {
|
|
736
|
+
this.ccMenu.hidden = !this.ccMenu.hidden;
|
|
737
|
+
if (this.speedMenu) this.speedMenu.hidden = true;
|
|
738
|
+
});
|
|
739
|
+
wrap.appendChild(this.ccMenu);
|
|
740
|
+
}
|
|
741
|
+
this.ccWrap = wrap;
|
|
742
|
+
const speed = this.el.querySelector(".kzp-speed");
|
|
743
|
+
this.el.insertBefore(wrap, speed);
|
|
744
|
+
}
|
|
745
|
+
/** Reflect the active caption track, and hide tracks (or the whole control) that failed to load. */
|
|
746
|
+
setCaptions(active, available) {
|
|
747
|
+
var _a;
|
|
748
|
+
this.ccActive = active;
|
|
749
|
+
if (!this.ccBtn || !this.ccWrap) return;
|
|
750
|
+
this.ccWrap.hidden = !available.some(Boolean);
|
|
751
|
+
this.ccBtn.classList.toggle("kzp-cc-btn--on", active !== -1);
|
|
752
|
+
this.ccBtn.setAttribute("aria-pressed", String(active !== -1));
|
|
753
|
+
(_a = this.ccMenu) == null ? void 0 : _a.querySelectorAll("button").forEach((item) => {
|
|
754
|
+
const index = Number(item.dataset.track);
|
|
755
|
+
item.hidden = index !== -1 && !available[index];
|
|
756
|
+
item.classList.toggle("kzp-menu-item--active", index === active);
|
|
757
|
+
});
|
|
758
|
+
}
|
|
579
759
|
button(cls, label, svg) {
|
|
580
760
|
const b = document.createElement("button");
|
|
581
761
|
b.type = "button";
|
|
@@ -592,9 +772,14 @@ var Controls = class {
|
|
|
592
772
|
}
|
|
593
773
|
/** Push the latest state into the DOM. Called on every player timeupdate. */
|
|
594
774
|
update(state, extras) {
|
|
775
|
+
var _a;
|
|
595
776
|
if (this.playBtn) {
|
|
596
|
-
|
|
597
|
-
|
|
777
|
+
const next = state.playing ? ICONS.pause : ICONS.play;
|
|
778
|
+
if (next !== this.playIcon) {
|
|
779
|
+
this.playIcon = next;
|
|
780
|
+
this.playBtn.innerHTML = icon(next);
|
|
781
|
+
this.playBtn.setAttribute("aria-label", state.playing ? "Pause" : "Play");
|
|
782
|
+
}
|
|
598
783
|
}
|
|
599
784
|
if (this.scrubber) {
|
|
600
785
|
this.seekableMax = this.lockSeek ? state.furthest : Infinity;
|
|
@@ -605,14 +790,25 @@ var Controls = class {
|
|
|
605
790
|
this.timeEl.textContent = `${fmt(state.current)} / ${fmt(state.duration)}`;
|
|
606
791
|
}
|
|
607
792
|
if (this.volBtn) {
|
|
608
|
-
|
|
793
|
+
const next = extras.muted || extras.volume === 0 ? ICONS.muted : ICONS.volume;
|
|
794
|
+
if (next !== this.volIcon) {
|
|
795
|
+
this.volIcon = next;
|
|
796
|
+
this.volBtn.innerHTML = icon(next);
|
|
797
|
+
}
|
|
609
798
|
}
|
|
610
799
|
if (this.volRange && document.activeElement !== this.volRange) {
|
|
611
800
|
this.volRange.value = String(extras.muted ? 0 : extras.volume);
|
|
612
801
|
}
|
|
613
|
-
if (this.speedBtn
|
|
802
|
+
if (this.speedBtn && extras.rate !== this.rate) {
|
|
803
|
+
this.rate = extras.rate;
|
|
804
|
+
this.speedBtn.textContent = `${extras.rate}x`;
|
|
805
|
+
(_a = this.speedMenu) == null ? void 0 : _a.querySelectorAll("button").forEach((item) => {
|
|
806
|
+
item.classList.toggle("kzp-menu-item--active", Number(item.dataset.rate) === extras.rate);
|
|
807
|
+
});
|
|
808
|
+
}
|
|
614
809
|
}
|
|
615
810
|
destroy() {
|
|
811
|
+
document.removeEventListener("click", this.onOutsideClick);
|
|
616
812
|
this.el.remove();
|
|
617
813
|
}
|
|
618
814
|
};
|
|
@@ -625,13 +821,14 @@ var Player = class {
|
|
|
625
821
|
this.container = container;
|
|
626
822
|
this.options = options;
|
|
627
823
|
this.emitter = new Emitter();
|
|
824
|
+
this.captions = null;
|
|
628
825
|
this.furthest = 0;
|
|
629
826
|
this.lastTick = 0;
|
|
630
827
|
this.duration = 0;
|
|
631
828
|
this.playing = false;
|
|
632
829
|
this.ready = false;
|
|
633
830
|
this.disposers = [];
|
|
634
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
831
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
635
832
|
const speeds = (_a = options.speeds) != null ? _a : DEFAULT_SPEEDS;
|
|
636
833
|
this.root = document.createElement("div");
|
|
637
834
|
this.root.className = "kzp" + (options.className ? ` ${options.className}` : "");
|
|
@@ -646,6 +843,10 @@ var Player = class {
|
|
|
646
843
|
this.stage.appendChild(hitLayer);
|
|
647
844
|
this.provider = createProvider(options.source);
|
|
648
845
|
const caps = this.provider.capabilities;
|
|
846
|
+
if ((_b = options.tracks) == null ? void 0 : _b.length) {
|
|
847
|
+
this.captions = new Captions(options.tracks, () => this.syncCaptions());
|
|
848
|
+
this.root.appendChild(this.captions.el);
|
|
849
|
+
}
|
|
649
850
|
this.controls = new Controls(
|
|
650
851
|
{
|
|
651
852
|
onToggle: () => this.toggle(),
|
|
@@ -663,17 +864,22 @@ var Player = class {
|
|
|
663
864
|
this.provider.setRate(r);
|
|
664
865
|
this.render();
|
|
665
866
|
},
|
|
867
|
+
onCaptions: (index) => {
|
|
868
|
+
var _a2;
|
|
869
|
+
return (_a2 = this.captions) == null ? void 0 : _a2.select(index);
|
|
870
|
+
},
|
|
666
871
|
onFullscreen: () => this.toggleFullscreen()
|
|
667
872
|
},
|
|
668
873
|
{
|
|
669
874
|
config: {
|
|
670
875
|
...options.controls,
|
|
671
|
-
seek: ((
|
|
672
|
-
speed: ((
|
|
673
|
-
volume: ((
|
|
876
|
+
seek: ((_d = (_c = options.controls) == null ? void 0 : _c.seek) != null ? _d : true) && caps.seekable,
|
|
877
|
+
speed: ((_f = (_e = options.controls) == null ? void 0 : _e.speed) != null ? _f : true) && caps.rate,
|
|
878
|
+
volume: ((_h = (_g = options.controls) == null ? void 0 : _g.volume) != null ? _h : true) && caps.volume
|
|
674
879
|
},
|
|
675
880
|
speeds,
|
|
676
|
-
lockSeek: !!options.lockSeek
|
|
881
|
+
lockSeek: !!options.lockSeek,
|
|
882
|
+
captionLabels: (_i = this.captions) == null ? void 0 : _i.labels()
|
|
677
883
|
}
|
|
678
884
|
);
|
|
679
885
|
this.root.appendChild(this.controls.el);
|
|
@@ -726,6 +932,7 @@ var Player = class {
|
|
|
726
932
|
this.render();
|
|
727
933
|
}
|
|
728
934
|
onTimeUpdate(current) {
|
|
935
|
+
var _a;
|
|
729
936
|
const advance = current - this.lastTick;
|
|
730
937
|
if (advance > 0 && advance <= NATURAL_ADVANCE_MAX && current > this.furthest) {
|
|
731
938
|
this.furthest = current;
|
|
@@ -733,9 +940,14 @@ var Player = class {
|
|
|
733
940
|
this.provider.seek(this.furthest);
|
|
734
941
|
}
|
|
735
942
|
this.lastTick = current;
|
|
943
|
+
(_a = this.captions) == null ? void 0 : _a.update(current);
|
|
736
944
|
this.emitter.emit("timeupdate", this.snapshot());
|
|
737
945
|
this.render();
|
|
738
946
|
}
|
|
947
|
+
syncCaptions() {
|
|
948
|
+
if (!this.captions) return;
|
|
949
|
+
this.controls.setCaptions(this.captions.getActive(), this.captions.available());
|
|
950
|
+
}
|
|
739
951
|
snapshot() {
|
|
740
952
|
const current = this.provider.getCurrentTime();
|
|
741
953
|
const duration = this.duration || this.provider.getDuration();
|
|
@@ -758,21 +970,32 @@ var Player = class {
|
|
|
758
970
|
}
|
|
759
971
|
}
|
|
760
972
|
// ---- Public API ----
|
|
973
|
+
// play()/pause() record the intent at once instead of waiting for the
|
|
974
|
+
// provider to confirm: YouTube only reports PLAYING after buffering, and
|
|
975
|
+
// until then a second click read "not playing" and called play() again
|
|
976
|
+
// (a no-op) instead of pausing. The provider's play/pause/ended events
|
|
977
|
+
// still correct it, e.g. when the browser blocks playback.
|
|
761
978
|
play() {
|
|
979
|
+
this.playing = true;
|
|
762
980
|
this.provider.play();
|
|
981
|
+
this.render();
|
|
763
982
|
}
|
|
764
983
|
pause() {
|
|
984
|
+
this.playing = false;
|
|
765
985
|
this.provider.pause();
|
|
986
|
+
this.render();
|
|
766
987
|
}
|
|
767
988
|
toggle() {
|
|
768
|
-
if (this.
|
|
769
|
-
else this.
|
|
989
|
+
if (this.playing) this.pause();
|
|
990
|
+
else this.play();
|
|
770
991
|
}
|
|
771
992
|
seek(seconds) {
|
|
993
|
+
var _a;
|
|
772
994
|
if (!this.provider.capabilities.seekable) return;
|
|
773
995
|
const target = this.options.lockSeek && seconds > this.furthest ? this.furthest : Math.max(0, seconds);
|
|
774
996
|
this.provider.seek(target);
|
|
775
997
|
this.lastTick = target;
|
|
998
|
+
(_a = this.captions) == null ? void 0 : _a.update(target);
|
|
776
999
|
this.render();
|
|
777
1000
|
}
|
|
778
1001
|
setLockSeek(locked) {
|
|
@@ -791,9 +1014,11 @@ var Player = class {
|
|
|
791
1014
|
this.emitter.off(event, cb);
|
|
792
1015
|
}
|
|
793
1016
|
destroy() {
|
|
1017
|
+
var _a;
|
|
794
1018
|
for (const dispose of this.disposers) dispose();
|
|
795
1019
|
this.disposers = [];
|
|
796
1020
|
this.provider.destroy();
|
|
1021
|
+
(_a = this.captions) == null ? void 0 : _a.destroy();
|
|
797
1022
|
this.controls.destroy();
|
|
798
1023
|
this.emitter.clear();
|
|
799
1024
|
this.root.remove();
|
|
@@ -806,7 +1031,7 @@ function createPlayer(container, options) {
|
|
|
806
1031
|
}
|
|
807
1032
|
var KodezenPlayer = forwardRef(
|
|
808
1033
|
function KodezenPlayer2(props, ref) {
|
|
809
|
-
var _a, _b;
|
|
1034
|
+
var _a, _b, _c;
|
|
810
1035
|
const hostRef = useRef(null);
|
|
811
1036
|
const playerRef = useRef(null);
|
|
812
1037
|
const propsRef = useRef(props);
|
|
@@ -856,7 +1081,8 @@ var KodezenPlayer = forwardRef(
|
|
|
856
1081
|
return (_a2 = playerRef.current) == null ? void 0 : _a2.destroy();
|
|
857
1082
|
}
|
|
858
1083
|
}));
|
|
859
|
-
const
|
|
1084
|
+
const trackKey = ((_a = props.tracks) != null ? _a : []).map((t) => t.src).join(",");
|
|
1085
|
+
const sourceKey = `${props.source.type}|${(_b = props.source.url) != null ? _b : ""}|${(_c = props.source.id) != null ? _c : ""}|${trackKey}`;
|
|
860
1086
|
useEffect(() => {
|
|
861
1087
|
if (!hostRef.current) return;
|
|
862
1088
|
const p = propsRef.current;
|
|
@@ -868,7 +1094,8 @@ var KodezenPlayer = forwardRef(
|
|
|
868
1094
|
muted: p.muted,
|
|
869
1095
|
speeds: p.speeds,
|
|
870
1096
|
controls: p.controls,
|
|
871
|
-
className: p.className
|
|
1097
|
+
className: p.className,
|
|
1098
|
+
tracks: p.tracks
|
|
872
1099
|
});
|
|
873
1100
|
playerRef.current = player;
|
|
874
1101
|
const offs = [
|