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. // Jump to LIVE if the user clicks on the current time.
  32. if (this.player.isLive()) {
  33. this.video.currentTime = this.player.seekRange().end;
  34. }
  35. });
  36. this.eventManager.listen(this.player, 'loading', () => {
  37. shaka.ui.Utils.setDisplay(this.currentTime_, true);
  38. });
  39. this.eventManager.listen(this.controls, 'timeandseekrangeupdated', () => {
  40. this.updateTime_();
  41. });
  42. this.eventManager.listen(this.player, 'trackschanged', () => {
  43. this.onTracksChanged_();
  44. });
  45. this.eventManager.listen(
  46. this.adManager, shaka.ads.Utils.AD_STARTED, () => {
  47. shaka.ui.Utils.setDisplay(this.currentTime_, !this.ad.isLinear());
  48. });
  49. this.eventManager.listen(
  50. this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
  51. shaka.ui.Utils.setDisplay(this.currentTime_, true);
  52. });
  53. }
  54. /** @private */
  55. setValue_(value) {
  56. // To avoid constant updates to the DOM, which makes debugging more
  57. // difficult, only set the value if it has changed. If we don't do this
  58. // check, the DOM updates constantly, this element flashes in the debugger
  59. // in Chrome, and you can't make changes in the CSS panel.
  60. if (value != this.currentTime_.textContent) {
  61. this.currentTime_.textContent = value;
  62. }
  63. }
  64. /** @private */
  65. updateTime_() {
  66. const isSeeking = this.controls.isSeeking();
  67. let displayTime = this.controls.getDisplayTime();
  68. const seekRange = this.player.seekRange();
  69. const seekRangeSize = seekRange.end - seekRange.start;
  70. const Utils = shaka.ui.Utils;
  71. if (!isFinite(seekRangeSize)) {
  72. this.setValue_(this.localization.resolve(shaka.ui.Locales.Ids.LIVE));
  73. this.currentTime_.disabled = true;
  74. } else if (this.player.isLive()) {
  75. // The amount of time we are behind the live edge.
  76. const behindLive = Math.floor(seekRange.end - displayTime);
  77. displayTime = Math.max(0, behindLive);
  78. const showHour = seekRangeSize >= 3600;
  79. // Consider "LIVE" when less than 1 second behind the live-edge. Always
  80. // show the full time string when seeking, including the leading '-';
  81. // otherwise, the time string "flickers" near the live-edge.
  82. // The button should only be clickable when it's live stream content, and
  83. // the current play time is behind live edge.
  84. if ((displayTime >= 1) || isSeeking) {
  85. this.setValue_('- ' + Utils.buildTimeString(displayTime, showHour));
  86. this.currentTime_.disabled = false;
  87. } else {
  88. this.setValue_(this.localization.resolve(shaka.ui.Locales.Ids.LIVE));
  89. this.currentTime_.disabled = true;
  90. }
  91. } else {
  92. const showHour = seekRangeSize >= 3600;
  93. const currentTime = Math.max(0, displayTime - seekRange.start);
  94. let value = Utils.buildTimeString(currentTime, showHour);
  95. if (seekRangeSize) {
  96. value += ' / ' + Utils.buildTimeString(seekRangeSize, showHour);
  97. }
  98. this.setValue_(value);
  99. this.currentTime_.disabled = true;
  100. }
  101. }
  102. /**
  103. * Set the aria label to be 'Live' when the content is live stream.
  104. * @private
  105. */
  106. onTracksChanged_() {
  107. if (this.player.isLive()) {
  108. const ariaLabel = shaka.ui.Locales.Ids.SKIP_TO_LIVE;
  109. this.currentTime_.ariaLabel = this.localization.resolve(ariaLabel);
  110. }
  111. }
  112. };
  113. /**
  114. * @implements {shaka.extern.IUIElement.Factory}
  115. * @final
  116. */
  117. shaka.ui.PresentationTimeTracker.Factory = class {
  118. /** @override */
  119. create(rootElement, controls) {
  120. return new shaka.ui.PresentationTimeTracker(rootElement, controls);
  121. }
  122. };
  123. shaka.ui.Controls.registerElement(
  124. 'time_and_duration', new shaka.ui.PresentationTimeTracker.Factory());