Source: ui/presentation_time.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.ui.PresentationTimeTracker');
  7. goog.require('shaka.ads.Utils');
  8. goog.require('shaka.ui.Controls');
  9. goog.require('shaka.ui.Element');
  10. goog.require('shaka.ui.Locales');
  11. goog.require('shaka.ui.Utils');
  12. goog.require('shaka.util.Dom');
  13. /**
  14. * @extends {shaka.ui.Element}
  15. * @final
  16. * @export
  17. */
  18. shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
  19. /**
  20. * @param {!HTMLElement} parent
  21. * @param {!shaka.ui.Controls} controls
  22. */
  23. constructor(parent, controls) {
  24. super(parent, controls);
  25. /** @type {!HTMLButtonElement} */
  26. this.currentTime_ = shaka.util.Dom.createButton();
  27. this.currentTime_.classList.add('shaka-current-time');
  28. this.setValue_('0:00');
  29. this.parent.appendChild(this.currentTime_);
  30. this.eventManager.listen(this.currentTime_, 'click', () => {
  31. if (!this.controls.isOpaque()) {
  32. return;
  33. }
  34. // Jump to LIVE if the user clicks on the current time.
  35. if (this.player.isLive()) {
  36. this.video.currentTime = this.player.seekRange().end;
  37. }
  38. });
  39. this.eventManager.listen(this.player, 'loading', () => {
  40. shaka.ui.Utils.setDisplay(this.currentTime_, true);
  41. });
  42. this.eventManager.listen(this.controls, 'timeandseekrangeupdated', () => {
  43. this.updateTime_();
  44. });
  45. this.eventManager.listen(this.player, 'trackschanged', () => {
  46. this.onTracksChanged_();
  47. });
  48. this.eventManager.listen(
  49. this.adManager, shaka.ads.Utils.AD_STARTED, () => {
  50. shaka.ui.Utils.setDisplay(this.currentTime_, !this.ad.isLinear());
  51. });
  52. this.eventManager.listen(
  53. this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
  54. shaka.ui.Utils.setDisplay(this.currentTime_, true);
  55. });
  56. }
  57. /**
  58. * @param {string} value
  59. * @private
  60. */
  61. setValue_(value) {
  62. // To avoid constant updates to the DOM, which makes debugging more
  63. // difficult, only set the value if it has changed. If we don't do this
  64. // check, the DOM updates constantly, this element flashes in the debugger
  65. // in Chrome, and you can't make changes in the CSS panel.
  66. if (value != this.currentTime_.textContent) {
  67. this.currentTime_.textContent = value;
  68. }
  69. }
  70. /** @private */
  71. updateTime_() {
  72. const isSeeking = this.controls.isSeeking();
  73. let displayTime = this.controls.getDisplayTime();
  74. const seekRange = this.player.seekRange();
  75. const seekRangeSize = seekRange.end - seekRange.start;
  76. const Utils = shaka.ui.Utils;
  77. if (!isFinite(seekRangeSize)) {
  78. this.setValue_(this.localization.resolve(shaka.ui.Locales.Ids.LIVE));
  79. this.currentTime_.disabled = true;
  80. } else if (this.player.isLive()) {
  81. // The amount of time we are behind the live edge.
  82. const behindLive = Math.floor(seekRange.end - displayTime);
  83. displayTime = Math.max(0, behindLive);
  84. const showHour = seekRangeSize >= 3600;
  85. // Consider "LIVE" when less than 1 second behind the live-edge. Always
  86. // show the full time string when seeking, including the leading '-';
  87. // otherwise, the time string "flickers" near the live-edge.
  88. // The button should only be clickable when it's live stream content, and
  89. // the current play time is behind live edge.
  90. if ((displayTime >= 1) || isSeeking) {
  91. this.setValue_('- ' + Utils.buildTimeString(displayTime, showHour));
  92. this.currentTime_.disabled = false;
  93. } else {
  94. this.setValue_(this.localization.resolve(shaka.ui.Locales.Ids.LIVE));
  95. this.currentTime_.disabled = true;
  96. }
  97. } else {
  98. const showHour = seekRangeSize >= 3600;
  99. const currentTime = Math.max(0, displayTime - seekRange.start);
  100. let value = Utils.buildTimeString(currentTime, showHour);
  101. if (seekRangeSize) {
  102. value += ' / ' + Utils.buildTimeString(seekRangeSize, showHour);
  103. }
  104. this.setValue_(value);
  105. this.currentTime_.disabled = true;
  106. }
  107. }
  108. /**
  109. * Set the aria label to be 'Live' when the content is live stream.
  110. * @private
  111. */
  112. onTracksChanged_() {
  113. if (this.player.isLive()) {
  114. const ariaLabel = shaka.ui.Locales.Ids.SKIP_TO_LIVE;
  115. this.currentTime_.ariaLabel = this.localization.resolve(ariaLabel);
  116. }
  117. }
  118. };
  119. /**
  120. * @implements {shaka.extern.IUIElement.Factory}
  121. * @final
  122. */
  123. shaka.ui.PresentationTimeTracker.Factory = class {
  124. /** @override */
  125. create(rootElement, controls) {
  126. return new shaka.ui.PresentationTimeTracker(rootElement, controls);
  127. }
  128. };
  129. shaka.ui.Controls.registerElement(
  130. 'time_and_duration', new shaka.ui.PresentationTimeTracker.Factory());