player.html 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <!-- ======================= Player ======================= -->
  2. <button class="play-pause iconic" title='play/pause'>
  3. {% include 'play-fill.svg' %}
  4. {% include 'pause-fill.svg' %}
  5. </button>
  6. <progress class="player" value="0" min="0"></progress>
  7. <audio class="clip" preload="metadata"></audio>
  8. <script>
  9. try {
  10. let mediaElement = $('.clip');
  11. let playPauseButton = $('button.play-pause');
  12. let progressBar = $('progress.player');
  13. document.body.addEventListener('keyup', evt => {
  14. if (['INPUT', 'TEXTAREA'].filter(
  15. tag => tag == document.activeElement.tagName
  16. ).length == 0) {
  17. if (evt.code == 'ArrowRight') {
  18. globalState.set('playbackTime', Math.min(globalState.get('playbackTime') + 1, mediaElement.duration));
  19. }
  20. if (evt.code == 'ArrowLeft') {
  21. globalState.set('playbackTime', Math.max(globalState.get('playbackTime') - 1, 0));
  22. }
  23. }
  24. if (evt.code == 'Space' && ['INPUT', 'TEXTAREA', 'BUTTON', 'SUMMARY'].filter(
  25. tag => tag == document.activeElement.tagName
  26. ).length == 0) {
  27. globalState.set('playing', !globalState.get('playing'));
  28. }
  29. });
  30. globalState.render(['playingClip'], current => {
  31. if (current.playingClip && current.playingClip.audio) {
  32. progressBar.setAttribute('max', 60);
  33. mediaElement.addEventListener('loadedmetadata', updateDuration);
  34. mediaElement.addEventListener('durationchange', updateDuration);
  35. mediaElement.src = current.playingClip.audio;
  36. globalState.set('playbackTime', 0);
  37. }
  38. });
  39. function updateDuration(evt) {
  40. if (mediaElement.duration < 1000 && mediaElement.duration != Infinity) {
  41. progressBar.setAttribute('max', mediaElement.duration);
  42. };
  43. }
  44. globalState.render(['playingClip'], current => {
  45. progressBar.setAttribute('max', 60);
  46. if (current.playingClip && current.playingClip.audio) {
  47. mediaElement.addEventListener('loadedmetadata', updateDuration);
  48. mediaElement.addEventListener('durationchange', updateDuration);
  49. mediaElement.src = current.playingClip.audio;
  50. globalState.set('playbackTime', 0);
  51. }
  52. })
  53. globalState.render(['playing'], current => {
  54. if (current.playing && !globalState.get('playingClip')) {
  55. globalState.set('playing', false);
  56. return;
  57. }
  58. if (current.playing) {
  59. playPauseButton.classList.add('playing') ;
  60. mediaElement.play();
  61. } else {
  62. playPauseButton.classList.remove('playing') ;
  63. mediaElement.pause();
  64. }
  65. });
  66. playPauseButton.addEventListener('click', evt => {
  67. globalState.set('playing', !globalState.get('playing'));
  68. globalState.set('previewClip', globalState.get('playingClip'));
  69. });
  70. progressBar.addEventListener('click', evt => {
  71. if (globalState.get('playingClip')) {
  72. let pos = (evt.pageX - progressBar.offsetLeft) / progressBar.offsetWidth;
  73. globalState.set('playbackTime', pos * mediaElement.duration);
  74. }
  75. })
  76. let dragInProgress = false;
  77. progressBar.addEventListener('mousedown', evt => dragInProgress = true);
  78. progressBar.addEventListener('mouseup', evt => dragInProgress = false);
  79. progressBar.addEventListener('mousemove', evt => {
  80. if (dragInProgress && globalState.get('playingClip')) {
  81. let pos = (evt.pageX - progressBar.offsetLeft)
  82. / progressBar.offsetWidth;
  83. globalState.set('playbackTime', pos * mediaElement.duration);
  84. }
  85. })
  86. globalState.render(['playbackTime'], current => {
  87. if (current.playbackTime &&
  88. current.playbackTime != mediaElement.currentTime
  89. ) {
  90. current.playbackTime = mediaElement.currentTime;
  91. }
  92. progressBar.setAttribute('value', current.playbackTime);
  93. if (current.playbackTime >= progressBar.max && globalState.get('playing') == true) {
  94. globalState.set('playing', false);
  95. }
  96. });
  97. let updateTime = () => {
  98. let playbackTime = globalState.get('playbackTime');
  99. if (playbackTime != mediaElement.currentTime) {
  100. globalState.set('playbackTime', mediaElement.currentTime);
  101. }
  102. window.requestAnimationFrame(updateTime);
  103. }
  104. window.requestAnimationFrame(updateTime);
  105. } catch(exception) {
  106. alert("An unknown error occured.");
  107. console.error(exception);
  108. }
  109. </script>
  110. <style>
  111. button.play-pause svg {
  112. display: none;
  113. }
  114. button.play-pause svg:first-child {
  115. display: inline-block;
  116. }
  117. button.play-pause.playing svg {
  118. display: inline-block;
  119. }
  120. button.play-pause.playing svg:first-child {
  121. display: none;
  122. }
  123. progress.player {
  124. width: 100%;
  125. height: calc(var(--header-height) - 1em);
  126. vertical-align: center;
  127. flex-shrink: 1;
  128. }
  129. .custom-widgets progress[value] {
  130. /* Reset the default appearance */
  131. -webkit-appearance: none;
  132. -moz-appearance: none;
  133. appearance: none;
  134. /* Get rid of default border in Firefox. */
  135. border: none;
  136. border: 1px solid var(--chrome-border);
  137. border-radius: var(--border-radius);
  138. overflow: hidden;
  139. }
  140. .custom-widgets progress[value]::-webkit-progress-bar, progress[value] {
  141. background: var(--input-background);
  142. box-shadow: inset -1px 2px calc(var(--box-shadow-spread) * 1.25) 2px rgba(255,255,255, calc(var(--highlight-strength) * 1));
  143. }
  144. /* These don't work together for some reason*/
  145. .custom-widgets progress[value]::-webkit-progress-value {
  146. background: var(--progress-bar-background);
  147. border-radius: var(--border-radius) 0px 0px var(--border-radius);
  148. }
  149. .custom-widgets progress[value]::-moz-progress-bar {
  150. background: var(--progress-bar-background);
  151. border-radius: var(--border-radius) 0px 0px var(--border-radius);
  152. }
  153. video.clip {
  154. position: absolute;
  155. top: 0px;
  156. left: 0px;
  157. right:0px;
  158. bottom: 0px;
  159. z-index: 1;
  160. width: 100%;
  161. height: var(--header-height);
  162. margin: 0px;
  163. opacity: 0;
  164. }
  165. </style>
  166. <!-- ====================================================== -->