具有自定义开始和结束时间的 YouTube Iframe 的自定义进度条

Custom Progress bar for YouTube Iframe with custom start and end time

我正在尝试创建一个具有不同开始和结束时间(默认开始和持续时间除外)的自定义 YouTube 进度条,原因是我只想显示视频的一部分,而且用户无法录制视频整个原始视频。 参考网址为:https://tutorialzine.com/2015/08/how-to-control-youtubes-video-player-with-javascript

我正在使用此代码以 1 秒的间隔更新进度条,这是一个范围输入。

<input type="range" id="progress-bar" value="0" />

function updateProgressBar(){
    // Update the value of our progress bar accordingly.
    $('#progress-bar').val((player.getCurrentTime() / Session.get('customEndTime') * 100);
}

但是,这并没有达到目的,因为它需要从 player.getCurrentTime() 开始的当前时间当我实际上希望它从 0 或最左边开始时,因为我想让它看起来像在播放从头开始。

假设我的开始持续时间为 10,结束持续时间为 60。我如何显示进度条,以便它给出一个百分比,并且该百分比会随着我的播放器的播放进度而增加。

我尽我所能对代码进行注释,但像这样的东西应该可以工作。诀窍实际上只是在 input 上设置 minmax type='range'..

我还对每个函数进行了参数化 - 我发现参数化函数的扩展性更好。

~~~ 重要的是要注意 Stack Overflow 似乎不允许在代码段中使用 iframe ~~~,所以你可以:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Custom YouTube Controls</title>
</head>

<body>
  <div id="video-placeholder"></div>
  <div>
    <button id="play">Play</button>
    <button id="pause">Pause</button>
    <input id="progress-bar" type="range" style="width: 300px;">
    <span id="current-time"></span>
    <span id="duration"></span>
  </div>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
  <script src="https://www.youtube.com/iframe_api"></script>
  <script>
    /** 
     * CONFIGURATION
     */

    var YOUTUBE_PLAYER,
      YOUTUBE_PLAYER_EL = "video-placeholder", // Don't have to specify "#" here
      START_TIME = "1:00",
      END_TIME = "1:20",
      PLAY_EL = "#play",
      PAUSE_EL = "#pause",
      PROGRESS_BAR_EL = "#progress-bar",
      CURRENT_TIME_EL = "#current-time",
      DURATION_EL = "#duration";

    /**
     * FUNCTIONS
     */

    function onYouTubeIframeAPIReady() {
      /**
       * Builds main YouTube API object
       */

      YOUTUBE_PLAYER = new YT.Player(YOUTUBE_PLAYER_EL, {
        width: 600,
        height: 400,
        videoId: 'Xa0Q0J5tOP0',
        playerVars: {
          // Supported player params can be found at https://developers.google.com/youtube/player_parameters#Parameters
          controls: 0, // disable video controls on mouse over
          disablekb: 1, // disable keyboard controls
          start: minutesToSeconds(START_TIME),
          end: minutesToSeconds(END_TIME),
        },
        events: {
          onReady: () => initialize(START_TIME, END_TIME, YOUTUBE_PLAYER, PLAY_EL, PAUSE_EL, PROGRESS_BAR_EL, CURRENT_TIME_EL, DURATION_EL)
        }
      });
    }

    function initialize(videoStartTime, videoEndTime, playerObj, playElId, pauseElId, progressBarElId, currentTimeElId, durationElId) {
      /**
       * Initializes all functions for player.
       * The reason we check for PlayerState is because if the video ends, and a user clicks play
       * it will start from the very beginning instead of our desired start time.
       *
       * More can be found https://developers.google.com/youtube/iframe_api_reference#Playback_status
       */

      $(playElId).on('click', () => { // Set play button click handler
        playerObj.getPlayerState() === 0 // a state of 0 means 'ended'
          ? playerObj.seekTo(minutesToSeconds(videoStartTime)) 
          : null;
        playerObj.playVideo();
      });

      $(pauseElId).on('click', () => playerObj.pauseVideo()); // Set pause button click handler

      $(progressBarElId) // Set min/max values for progress bar & set mouseup and touchend handlers
        .attr('min', minutesToSeconds(videoStartTime))
        .attr('max', minutesToSeconds(videoEndTime))
        .on('mouseup touchend', e => playerObj.seekTo(e.target.value));

      playerObj.seekTo(minutesToSeconds(videoStartTime)); // Sets the progress bar to correct start time
      doUpdate(currentTimeElId, durationElId, progressBarElId, playerObj, videoEndTime); // Updates progress bar and timestamp

      let time_update_interval = setInterval(() => { // Creates interval for updating progress bar and timestamp
        doUpdate(currentTimeElId, durationElId, progressBarElId, playerObj, videoEndTime);
      }, 1000);
    }


    function doUpdate(currentTimeElId, durationElId, progressBarElId, playerObj, videoEndTime) {
      /**
       * Updates current_time / duration
       * Updates progress_bar
       */

      updateTimerDisplay(currentTimeElId, durationElId, playerObj, videoEndTime);
      updateProgressBar(progressBarElId, playerObj);
    }


    function updateTimerDisplay(currentTimeElId, durationElId, playerObj, videoEndTime) {
      /**
       * Updates current_time / duration
       */

      $(currentTimeElId).text(formatTime(playerObj.getCurrentTime()));
      $(durationElId).text(formatTime(minutesToSeconds(videoEndTime)));
    }


    function formatTime(time) {
      /**
       * Formats time in xx:xx format
       */

      time = Math.round(time);
      let minutes = Math.floor(time / 60),
        seconds = time - minutes * 60;
      seconds = seconds < 10 ? '0' + seconds : seconds;
      return minutes + ":" + seconds;
    }


    function updateProgressBar(progressBarElId, playerObj) {
      /**
       * Updates progress bar
       */

      $(progressBarElId).val(playerObj.getCurrentTime());
    }
    

    function minutesToSeconds(mins) {
      /**
       * ~~ mins param must be a str in "1:00" format ~~
       * Converts time in xx:xx format to seconds
       */

      let p = mins.split(":");
      return Number((Number(p[0]) * 60 + Number(p[1])).toFixed(3));
    }
  </script>
</body>

</html>

更新:

您询问了关于从 0 开始并显示您希望播放的 "total section" 的结束时间...

This CodePen Mirror 显示了如何完成此操作以及以下代码:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Custom YouTube Controls</title>
</head>

<body>
  <div id="video-placeholder"></div>
  <div>
    <button id="play">Play</button>
    <button id="pause">Pause</button>
    <input id="progress-bar" type="range" style="width: 300px;">
    <span id="current-time"></span>
    <span id="duration"></span>
  </div>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
  <script src="https://www.youtube.com/iframe_api"></script>
  <script>
    /** 
     * CONFIGURATION
     */

    var YOUTUBE_PLAYER,
      YOUTUBE_PLAYER_EL = "video-placeholder", // Don't have to specify "#" here
      YOUTUBE_VIDEO_ID = "Xa0Q0J5tOP0",
      START_TIME = "1:00",
      END_TIME = "1:20",
      PLAY_EL = "#play",
      PAUSE_EL = "#pause",
      PROGRESS_BAR_EL = "#progress-bar",
      CURRENT_TIME_EL = "#current-time",
      DURATION_EL = "#duration";

    /**
     * FUNCTIONS
     */

    function onYouTubeIframeAPIReady() {
      /**
       * Builds main YouTube API object
       */

      YOUTUBE_PLAYER = new YT.Player(YOUTUBE_PLAYER_EL, {
        width: 600,
        height: 400,
        videoId: YOUTUBE_VIDEO_ID,
        playerVars: {
          // Supported player params can be found at https://developers.google.com/youtube/player_parameters#Parameters
          controls: 0, // disable video controls on mouse over
          disablekb: 1, // disable keyboard controls
          start: minutesToSeconds(START_TIME),
          end: minutesToSeconds(END_TIME),
        },
        events: {
          onReady: () => initialize(START_TIME, END_TIME, YOUTUBE_PLAYER, PLAY_EL, PAUSE_EL, PROGRESS_BAR_EL, CURRENT_TIME_EL, DURATION_EL)
        }
      });
    }

    function initialize(videoStartTime, videoEndTime, playerObj, playElId, pauseElId, progressBarElId, currentTimeElId, durationElId) {
      /**
       * Initializes all functions for player.
       * The reason we check for PlayerState is because if the video ends, and a user clicks play
       * it will start from the very beginning instead of our desired start time.
       *
       * More can be found https://developers.google.com/youtube/iframe_api_reference#Playback_status
       */

      const START_SECONDS = minutesToSeconds(videoStartTime),
        END_SECONDS = minutesToSeconds(videoEndTime),
        TOTAL_SECONDS = END_SECONDS - START_SECONDS;

      // Make sure the end time is greater than the start time, the total play time is greater 
      // than 0 and we didnt specify an end time greater than the videos length
      if (END_SECONDS > START_SECONDS && TOTAL_SECONDS > 0 && playerObj.getDuration() > END_SECONDS) {

        $(playElId).on('click', () => { // Set play button click handler
          playerObj.getPlayerState() === 0 // a state of 0 means 'ended'
            ? playerObj.seekTo(minutesToSeconds(videoStartTime)) 
            : null;
          playerObj.playVideo();
        });

        $(pauseElId).on('click', () => playerObj.pauseVideo()); // Set pause button click handler

        $(progressBarElId) // Set min/max values for progress bar & set mouseup and touchend handlers
          //.attr('min', minutesToSeconds(videoStartTime))
          //.attr('max', minutesToSeconds(videoEndTime))
          .attr('min', 0)
          .attr('max', TOTAL_SECONDS)       
          .on('mouseup touchend', e => playerObj.seekTo(Number(e.target.value) + Number(START_SECONDS)));

        playerObj.seekTo(minutesToSeconds(videoStartTime)); // Sets the progress bar to correct start time
        doUpdate(currentTimeElId, durationElId, progressBarElId, playerObj, START_SECONDS, TOTAL_SECONDS); // Updates progress bar and timestamp

        let time_update_interval = setInterval(() => { // Creates interval for updating progress bar and timestamp
          doUpdate(currentTimeElId, durationElId, progressBarElId, playerObj, START_SECONDS, TOTAL_SECONDS);
        }, 1000);
      
      } else {
        playerObj.destroy();
        alert("Unable to play video, please verify supplied parameters!")
      }
    }


    function doUpdate(currentTimeElId, durationElId, progressBarElId, playerObj, startSeconds, totalSeconds) {
      /**
       * Updates current_time / duration
       * Updates progress_bar
       */

      updateTimerDisplay(currentTimeElId, durationElId, playerObj, startSeconds, totalSeconds);
      updateProgressBar(progressBarElId, playerObj, startSeconds);
    }


    function updateTimerDisplay(currentTimeElId, durationElId, playerObj, startSeconds, totalSeconds) {
      /**
       * Updates current_time / duration
       */

      $(currentTimeElId).text(formatTime(Number(playerObj.getCurrentTime()) - Number(startSeconds)));
      $(durationElId).text(formatTime(totalSeconds));
    }


    function formatTime(time) {
      /**
       * Formats time in xx:xx format
       */

      time = Math.round(time);
      let minutes = Math.floor(time / 60),
        seconds = time - minutes * 60;
      seconds = seconds < 10 ? '0' + seconds : seconds;
      return minutes + ":" + seconds;
    }


    function updateProgressBar(progressBarElId, playerObj, startSeconds) {
      /**
       * Updates progress bar
       */

      //$(progressBarElId).val(playerObj.getCurrentTime());
      $(progressBarElId).val(playerObj.getCurrentTime() - startSeconds);
    }
    

    function minutesToSeconds(mins) {
      /**
       * ~~ mins param must be a str in "1:00" format ~~
       * Converts time in xx:xx format to seconds
       */

      let p = mins.split(":");
      return Number((Number(p[0]) * 60 + Number(p[1])).toFixed(3));
    }
  </script>
</body>

</html>