@edm-webplayer/webplayer-angular 0.1.57 → 0.1.59

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.
@@ -83,6 +83,7 @@ class PlyrPlayerComponent {
83
83
  overlayBlockAll = false;
84
84
  endedPosterOverlay;
85
85
  interactionUnmuteCleanup;
86
+ endedLoggedOnPause = false;
86
87
  pendingStartTime;
87
88
  onResize = () => {
88
89
  this.updateRecommendationBlockerSafeZone();
@@ -503,6 +504,20 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join("\n")}
503
504
  }
504
505
  return percent >= 0.8;
505
506
  }
507
+ shouldEmitEndedOnPause() {
508
+ if (!this.isIOSDevice()) {
509
+ return false;
510
+ }
511
+ if (this.endedLoggedOnPause) {
512
+ return false;
513
+ }
514
+ const duration = this.plyr?.duration;
515
+ if (!Number.isFinite(duration) || !duration || duration <= 0) {
516
+ return false;
517
+ }
518
+ const current = this.plyr?.currentTime || 0;
519
+ return current / duration >= 0.8;
520
+ }
506
521
  wantsAutoplay() {
507
522
  return !!(this.config?.autoplay || this.config?.is_live);
508
523
  }
@@ -888,7 +903,8 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join("\n")}
888
903
  const onPause = () => {
889
904
  clearHideTimeout();
890
905
  showControls();
891
- if (this.isIOSDevice()) {
906
+ if (this.shouldEmitEndedOnPause()) {
907
+ this.endedLoggedOnPause = true;
892
908
  console.log("event: ended");
893
909
  }
894
910
  };
@@ -1019,21 +1035,23 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join("\n")}
1019
1035
  if (captionsLanguage) {
1020
1036
  youtubePlayerVars.playerVars.cc_load_policy = 1;
1021
1037
  }
1038
+ const defaultControls = [
1039
+ "play-large",
1040
+ "play",
1041
+ "progress",
1042
+ "current-time",
1043
+ "duration",
1044
+ "mute",
1045
+ "volume",
1046
+ "captions",
1047
+ "settings",
1048
+ "pip",
1049
+ "airplay",
1050
+ "fullscreen",
1051
+ ];
1052
+ const liveControls = ["play-large", "play", "mute", "airplay", "fullscreen"];
1022
1053
  const plyrOptions = {
1023
- controls: [
1024
- "play-large",
1025
- "play",
1026
- "progress",
1027
- "current-time",
1028
- "duration",
1029
- "mute",
1030
- "volume",
1031
- "captions",
1032
- "settings",
1033
- "pip",
1034
- "airplay",
1035
- "fullscreen",
1036
- ],
1054
+ controls: this.config?.is_live ? liveControls : defaultControls,
1037
1055
  fullscreen: {
1038
1056
  enabled: true,
1039
1057
  fallback: true,
@@ -1067,6 +1085,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join("\n")}
1067
1085
  this.observeMenuChanges();
1068
1086
  this.playbackEnded = false;
1069
1087
  this.overlayBlockAll = false;
1088
+ this.endedLoggedOnPause = false;
1070
1089
  window.removeEventListener("resize", this.onResize);
1071
1090
  window.addEventListener("resize", this.onResize);
1072
1091
  this.bindProgressEvents();
@@ -1147,6 +1166,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join("\n")}
1147
1166
  this.playbackEnded = true;
1148
1167
  this.overlayBlockAll = true;
1149
1168
  this.updateRecommendationBlockerSafeZone();
1169
+ this.endedLoggedOnPause = true;
1150
1170
  console.log("event: ended");
1151
1171
  parent.postMessage("event: ended", "*");
1152
1172
  this.postCastEvent({
@@ -1240,7 +1260,7 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join("\n")}
1240
1260
  if (this.config.mirror) {
1241
1261
  setTimeout(() => {
1242
1262
  document
1243
- .querySelector(`.plyr__video-embed iframe`) // eslint-disable-line
1263
+ .querySelector(`.plyr__video-embed iframe`)
1244
1264
  ?.classList.add("mirror");
1245
1265
  }, 1000);
1246
1266
  }
@@ -1463,6 +1483,7 @@ class VimeoPlayerComponent {
1463
1483
  plyr;
1464
1484
  startTimeApplied = false;
1465
1485
  pendingStartTime;
1486
+ endedLoggedOnPause = false;
1466
1487
  onCastMessage = (event) => {
1467
1488
  let data = event.data;
1468
1489
  if (typeof data === 'string') {
@@ -1511,6 +1532,7 @@ class VimeoPlayerComponent {
1511
1532
  this.plyr?.destroy();
1512
1533
  this.startTimeApplied = false;
1513
1534
  this.pendingStartTime = undefined;
1535
+ this.endedLoggedOnPause = false;
1514
1536
  this.endedOverlayVisible = false;
1515
1537
  const shouldAutoplay = !!(this.config?.autoplay && !this.isIOSDevice());
1516
1538
  const startMuted = shouldAutoplay;
@@ -1572,23 +1594,9 @@ class VimeoPlayerComponent {
1572
1594
  return;
1573
1595
  let durationPosted = false;
1574
1596
  const onTimeUpdate = () => {
1597
+ this.tryApplyPendingStartTime();
1575
1598
  const current = this.plyr.currentTime || 0;
1576
1599
  const duration = this.plyr.duration || 0;
1577
- if (!this.startTimeApplied && typeof this.pendingStartTime === 'number') {
1578
- const diff = Math.abs(current - this.pendingStartTime);
1579
- const tolerance = 0.35;
1580
- if (diff > tolerance) {
1581
- try {
1582
- this.plyr.currentTime = this.pendingStartTime;
1583
- }
1584
- catch { }
1585
- return;
1586
- }
1587
- else {
1588
- this.startTimeApplied = true;
1589
- this.pendingStartTime = undefined;
1590
- }
1591
- }
1592
1600
  if (!durationPosted && duration > 0) {
1593
1601
  durationPosted = true;
1594
1602
  console.log('event: duration ' + duration);
@@ -1613,10 +1621,17 @@ class VimeoPlayerComponent {
1613
1621
  parent.postMessage('duration:' + duration, '*');
1614
1622
  }
1615
1623
  parent.postMessage('playerIsReadyToPlay', '*');
1624
+ this.postCastEvent({
1625
+ event: 'ready',
1626
+ duration,
1627
+ currentTime: this.plyr.currentTime || 0,
1628
+ });
1616
1629
  this.ready.emit();
1617
1630
  });
1618
1631
  const reapplyStartTime = () => {
1619
- this.applySavedStartTime(true);
1632
+ if (typeof this.pendingStartTime === 'number' || !this.startTimeApplied) {
1633
+ this.applySavedStartTime(true);
1634
+ }
1620
1635
  if (this.startTimeApplied) {
1621
1636
  this.plyr?.off?.('loadedmetadata', reapplyStartTime);
1622
1637
  this.plyr?.off?.('durationchange', reapplyStartTime);
@@ -1626,9 +1641,18 @@ class VimeoPlayerComponent {
1626
1641
  this.plyr.on('loadedmetadata', reapplyStartTime);
1627
1642
  this.plyr.on('durationchange', reapplyStartTime);
1628
1643
  this.plyr.on('play', () => {
1644
+ if (this.ensureStartTimeBeforePlayback()) {
1645
+ return;
1646
+ }
1647
+ this.endedLoggedOnPause = false;
1648
+ this.tryApplyPendingStartTime();
1629
1649
  this.endedOverlayVisible = false;
1630
1650
  this.progressService.ended$.next();
1631
1651
  console.log('event: playing_video');
1652
+ if (this.config?.is_live) {
1653
+ console.log('event: playing_live');
1654
+ parent.postMessage('event: playing_live', '*');
1655
+ }
1632
1656
  parent.postMessage('playing_video', '*');
1633
1657
  this.postCastEvent({
1634
1658
  event: 'play',
@@ -1637,6 +1661,7 @@ class VimeoPlayerComponent {
1637
1661
  onTimeUpdate();
1638
1662
  });
1639
1663
  this.plyr.on('pause', () => {
1664
+ this.endedOverlayVisible = false;
1640
1665
  console.log('event: pause');
1641
1666
  parent.postMessage('paused_video', '*');
1642
1667
  this.postCastEvent({
@@ -1644,17 +1669,13 @@ class VimeoPlayerComponent {
1644
1669
  currentTime: this.plyr.currentTime || 0,
1645
1670
  });
1646
1671
  onTimeUpdate();
1672
+ if (this.shouldEmitEndedOnPause()) {
1673
+ this.handleEnded(true);
1674
+ }
1647
1675
  });
1648
1676
  this.plyr.on('ended', () => {
1649
- this.endedOverlayVisible = true;
1650
- console.log('event: ended');
1651
- parent.postMessage('event: ended', '*');
1652
- this.postCastEvent({
1653
- event: 'ended',
1654
- currentTime: this.plyr.currentTime || 0,
1655
- });
1656
1677
  onTimeUpdate();
1657
- this.progressService.ended$.next();
1678
+ this.handleEnded();
1658
1679
  });
1659
1680
  this.plyr.on('enterfullscreen', () => {
1660
1681
  console.log('event: enterfullscreen');
@@ -1668,6 +1689,9 @@ class VimeoPlayerComponent {
1668
1689
  });
1669
1690
  }
1670
1691
  resolveStartTime(last_time, last_percent, duration) {
1692
+ if (this.shouldResetProgressToBeginning()) {
1693
+ return 0;
1694
+ }
1671
1695
  const dur = Number(duration) || 0;
1672
1696
  if (dur <= 0) {
1673
1697
  if (last_time && Number(last_time) > 0) {
@@ -1687,6 +1711,24 @@ class VimeoPlayerComponent {
1687
1711
  }
1688
1712
  return 0;
1689
1713
  }
1714
+ shouldResetProgressToBeginning() {
1715
+ const seenFlag = this.config?.seen;
1716
+ if (seenFlag === true || seenFlag === 'true' || seenFlag === 1) {
1717
+ return true;
1718
+ }
1719
+ const rawPercent = this.config?.last_percent;
1720
+ if (rawPercent === undefined || rawPercent === null || rawPercent === 0) {
1721
+ return false;
1722
+ }
1723
+ let percent = Number(rawPercent);
1724
+ if (!Number.isFinite(percent)) {
1725
+ return false;
1726
+ }
1727
+ if (percent > 1) {
1728
+ percent = percent / 100;
1729
+ }
1730
+ return percent >= 0.8;
1731
+ }
1690
1732
  isIOSDevice() {
1691
1733
  if (typeof navigator === 'undefined')
1692
1734
  return false;
@@ -1702,19 +1744,19 @@ class VimeoPlayerComponent {
1702
1744
  return;
1703
1745
  const duration = this.plyr.duration || 0;
1704
1746
  const start = this.resolveStartTime(this.config?.last_time, this.config?.last_percent, duration);
1705
- if (start <= 0) {
1747
+ if (!(start > 0)) {
1706
1748
  this.pendingStartTime = undefined;
1707
1749
  return;
1708
1750
  }
1709
- this.pendingStartTime = start;
1710
- try {
1711
- this.plyr.currentTime = start;
1712
- }
1713
- catch { }
1714
1751
  if (duration > 0) {
1752
+ this.seekTo(start);
1715
1753
  this.startTimeApplied = true;
1716
1754
  this.pendingStartTime = undefined;
1717
1755
  }
1756
+ else {
1757
+ this.pendingStartTime = start;
1758
+ this.startTimeApplied = false;
1759
+ }
1718
1760
  }
1719
1761
  ngOnDestroy() {
1720
1762
  this.plyr?.destroy();
@@ -1753,6 +1795,134 @@ ${allPairs.map(([n, v]) => ` ${n}: ${v};`).join('\n')}
1753
1795
  }`;
1754
1796
  styleEl.textContent = cssRule;
1755
1797
  }
1798
+ seekTo(time) {
1799
+ if (!this.plyr)
1800
+ return;
1801
+ const target = Math.max(0, Number(time) || 0);
1802
+ try {
1803
+ this.plyr.currentTime = target;
1804
+ }
1805
+ catch { }
1806
+ }
1807
+ tryApplyPendingStartTime() {
1808
+ if (this.startTimeApplied)
1809
+ return;
1810
+ if (!this.plyr)
1811
+ return;
1812
+ const pending = this.pendingStartTime;
1813
+ if (typeof pending !== 'number' || !(pending > 0)) {
1814
+ return;
1815
+ }
1816
+ const duration = this.plyr.duration || 0;
1817
+ if (!(duration > 0)) {
1818
+ return;
1819
+ }
1820
+ const current = this.plyr.currentTime || 0;
1821
+ const tolerance = 0.35;
1822
+ const nearingTarget = Math.abs(current - pending) <= tolerance;
1823
+ if (nearingTarget && (this.plyr.duration || 0) > 0) {
1824
+ this.startTimeApplied = true;
1825
+ this.pendingStartTime = undefined;
1826
+ return;
1827
+ }
1828
+ this.pendingStartTime = undefined;
1829
+ this.startTimeApplied = true;
1830
+ this.seekTo(pending);
1831
+ try {
1832
+ const maybePromise = this.plyr.play?.();
1833
+ if (maybePromise && typeof maybePromise.then === 'function') {
1834
+ maybePromise.catch(() => { });
1835
+ }
1836
+ }
1837
+ catch { }
1838
+ }
1839
+ ensureStartTimeBeforePlayback() {
1840
+ if (this.startTimeApplied)
1841
+ return false;
1842
+ if (!this.plyr)
1843
+ return false;
1844
+ const pending = this.pendingStartTime;
1845
+ if (typeof pending !== 'number' || !(pending > 0)) {
1846
+ return false;
1847
+ }
1848
+ const duration = this.plyr.duration || 0;
1849
+ if (!(duration > 0)) {
1850
+ return false;
1851
+ }
1852
+ const current = this.plyr.currentTime || 0;
1853
+ const tolerance = 0.35;
1854
+ if (Math.abs(current - pending) <= tolerance) {
1855
+ this.startTimeApplied = true;
1856
+ this.pendingStartTime = undefined;
1857
+ return false;
1858
+ }
1859
+ const resumeAfterSeek = () => {
1860
+ this.plyr?.off?.('seeked', resumeAfterSeek);
1861
+ this.startTimeApplied = true;
1862
+ this.pendingStartTime = undefined;
1863
+ try {
1864
+ const maybePromise = this.plyr?.play?.();
1865
+ if (maybePromise && typeof maybePromise.then === 'function') {
1866
+ maybePromise.catch(() => { });
1867
+ }
1868
+ }
1869
+ catch { }
1870
+ };
1871
+ this.plyr?.on?.('seeked', resumeAfterSeek);
1872
+ try {
1873
+ this.plyr?.pause?.();
1874
+ }
1875
+ catch { }
1876
+ this.seekTo(pending);
1877
+ return true;
1878
+ }
1879
+ shouldEmitEndedOnPause() {
1880
+ if (!this.isIOSContext()) {
1881
+ return false;
1882
+ }
1883
+ if (this.endedLoggedOnPause) {
1884
+ return false;
1885
+ }
1886
+ const duration = this.plyr?.duration;
1887
+ if (!Number.isFinite(duration) || !duration || duration <= 0) {
1888
+ return false;
1889
+ }
1890
+ const current = this.plyr?.currentTime || 0;
1891
+ return duration - current < 1;
1892
+ }
1893
+ handleEnded(triggeredByPause = false) {
1894
+ if (triggeredByPause && this.endedLoggedOnPause) {
1895
+ return;
1896
+ }
1897
+ if (!triggeredByPause) {
1898
+ this.endedOverlayVisible = true;
1899
+ }
1900
+ console.log('event: ended');
1901
+ parent.postMessage('event: ended', '*');
1902
+ this.postCastEvent({
1903
+ event: 'ended',
1904
+ currentTime: this.plyr?.currentTime || 0,
1905
+ });
1906
+ this.progressService.ended$.next();
1907
+ this.endedLoggedOnPause = true;
1908
+ }
1909
+ isIOSContext() {
1910
+ if (this.isIOSDevice()) {
1911
+ return true;
1912
+ }
1913
+ if (typeof window === 'undefined') {
1914
+ return false;
1915
+ }
1916
+ try {
1917
+ const params = new URLSearchParams(window.location.search);
1918
+ const os = params.get('os');
1919
+ if (os && os.toLowerCase() === 'ios') {
1920
+ return true;
1921
+ }
1922
+ }
1923
+ catch { }
1924
+ return false;
1925
+ }
1756
1926
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VimeoPlayerComponent, deps: [{ token: WebplayerProgressService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component });
1757
1927
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: VimeoPlayerComponent, isStandalone: true, selector: "app-vimeo-player", inputs: { config: "config" }, outputs: { ready: "ready" }, host: { properties: { "class.overlay-visible": "endedOverlayVisible" } }, viewQueries: [{ propertyName: "videoRef", first: true, predicate: ["video"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
1758
1928
  <div class="vimeo-wrapper">