建立自定义的YouTube播放列表播放器

YouTube成立于2005年,现已发展成为占主导地位的视频共享网站。 播放列表是YouTube使用最广泛的功能之一。 您可以建立自己和其他用户上传的视频的播放列表,并在YouTube上共享您的播放列表。 您还可以通过将播放列表嵌入网站,博客或社交媒体页面来共享它们。 但是,嵌入式播放列表播放器缺少YouTube.com上本机播放器的全部功能。

图1显示了本机youtube.com播放列表播放器。

图1.本机播放列表播放器
屏幕截图显示了本地YouTube播放列表播放器

图2显示了默认的嵌入式播放器。

图2.嵌入式播放列表播放器
屏幕截图显示了默认的嵌入式YouTube播放列表播放器

在嵌入式播放器中:

  • 默认情况下,包含的视频列表处于隐藏状态,并且仅显示为叠加层,而不是播放器旁边(如YouTube.com上所示)。
  • 随机播放列表的功能已删除。
  • 由其作者添加到播放列表中的注释将被删除。

当我决定在自己的博客中嵌入一个播放列表,其中包含2014年FIFA世界杯资格赛中取得的一些最佳进球时,我遇到了这些限制。 在YouTube API,jQuery,JsRender模板引擎和Bootstrap前端框架的帮助下,我扩展并改进了默认嵌入式播放器,以创建与本地播放器等效的版本。 在本文中,我将带您完成相同的过程。 您将在YouTube上建立播放列表,添加带有精彩时刻(例如目标)的注释,然后使用相同的工具来构建嵌入式播放器,以恢复缺少的功能并改善用户体验。

完整的项目代码存储在DevOps Services上。 我已将该应用程序部署到IBM Bluemix™,因此您可以看到它的运行情况。 您可以使用任何主机站点(包括Bluemix )来部署代码。

运行播放器 获取代码

注意 :要派生本文项目的代码,请单击右上角的“ 编辑代码”按钮(如果尚未登录,请输入DevOps Services凭据),然后单击菜单上的“ 分叉”按钮以创建一个新的项目。

第一步是获取用于访问YouTube API的密钥。

获取YouTube API密钥

要访问任何Google服务(包括YouTube)的API,您必须首先在Google Developers Console上注册一个项目并创建一个API密钥。 每天最多可免费访问各种API,具体数量因服务而异,并且每个拥有Google帐户的人都可以使用。

使用您的Google凭据登录Google Developers Console ,然后点击创建项目 。 默认情况下,项目名称和项目ID文本框包含随机值。 输入项目名称和ID,然后点击创建

图3.创建一个新的Google API项目
Google Developer Console的“新建项目”对话框的屏幕截图

在项目仪表板中,单击“ API和身份验证”以打开可用API的列表。 向下滚动到YouTube Data API v3 ,然后单击标为“ 关”的相关按钮,以启用对项目的访问权限。 选择“ API和身份验证”>“凭据”,然后在“公共API访问”下选择“ 创建新密钥 ”。 选择浏览器密钥

在“ 创建浏览器密钥并配置允许的引用程序”对话框中,可以将对API密钥的访问限制为来自某些域的请求,例如您自己的站点或Bluemix 。 除非您限制访问,否则您的API密钥将对应用程序HTML源中的所有人可见。 在开发过程中这不是问题,因此将对话框留空并单击创建 。 但是,在部署项目后,请返回此步骤并限制对您应用程序域中请求的访问权限,以使第三方无法在其他应用程序中使用密钥。

如果从DevOps Services克隆了项目,则可以立即在index.html文件中指示的位置插入密钥,以使代码成功运行。

配置Google JavaScript客户端库以访问YouTube API

Google提供了各种语言的客户端库,包括JavaScript。 通过将此HTML标记包含在文档的<body>标记(而不是<head>标记)中,将JavaScript客户端导入到HTML文档中:

<script src="https://apis.google.com/js/client.js?onload=function"></script>

建议的最佳做法是将此<script>标记放在<body>标记的末尾。

加载客户端库后, gapi (Google API)对象在页面上的窗口范围内可用。 您刚刚添加的<script>标记中的onload参数是指在库加载后立即调用的回调函数。 该函数的定义必须在加载客户端的<script>标记之前。 该函数调用gapi.client.load( api name , version , callback function )方法以加载客户端将使用的API。 在这种情况下,您可以使用gapi.client.load('youtube', 'v3', onYouTubeApiLoad)加载YouTube API。 onYouTubeApiLoad是一种单行函数,它调用setAPIKey方法。 在setAPIKey ,将密钥设置为Google浏览器密钥的值。

客户端提供了用于访问Google服务的各种API调用的方法。 要获取播放列表中的项目列表,您将使用异步函数解析YouTube API中playlistItems.list方法的响应,并将相关属性存储在名为YouTubePlayListJavaScript对象的实例中。 您将在本文中开发YouTubePlaylist对象。 对象的构造函数在下面显示JavaScript函数中定义。

清单1. YouTubePlaylist.js
function YouTubePlaylist(id, entries) {
   this.id = id;
   this.entries = entries;
   this.currently_playing = 0;
   this.randomizer = false;
}
  • id是播放列表的ID。
  • entries是播放列表中视频的JSON数组。
  • currently_playingentries数组中当前播放的视频的索引。
  • randomizer指示播放是否随机化。

创建带有响应参数的JSON对象

现在,使用响应中所需的参数创建一个JSON对象。 您只需要可用参数完整列表的一小部分。

part参数是要由调用返回的属性的逗号分隔值(CSV)列表。 使用contentDetailssnippet属性。 snippet属性包含有关每个视频的基本信息。 contentDetails包含视频ID和播放列表作者添加的所有注释。 当您确定视频中的亮点时, contentDetails将很重要。 playListId参数是您将使用的播放列表的ID。 出于本文的目的,我设置了一个播放列表,突出显示的ID为PLLzJfby7cTLTbusOgXca-yIpVOImC1mWe 。 在播放列表中,请注意,目标时间已添加为注释。 JSON requestOptions对象现在看起来像这样:

var requestOptions = {
   playlistId: playlist_id,
   part: 'contentDetails,snippet'
};

调用gapi.client.youtube.playlistItems.list()与此JSON对象作为参数方法返回一个对象与两种方法: executesubscribe 。 使用异步函数调用execute方法,并将响应作为参数。

request.execute(function(response) {});

响应中的items数组包含播放列表中的视频列表。 您将使用jQuery each()方法来遍历所有项目。 您将视频ID,视频的中型缩略图,标题和注释存储在JSON对象中,然后将其添加到数组中。

清单2.添加JSON对象的entries阵列
var entries = [];
$.each( response.items, function( key, val ) {

   var entry = {};
   entry.video_id = val.snippet.resourceId.videoId;
   entry.image_src = val.snippet.thumbnails.medium.url;
   entry.title = val.snippet.title;
   entry.note = val.contentDetails.note;
   entries.push(entry);

});

创建YouTubePlayList对象

通过调用具有播放列表ID和entries数组的构造函数(请参见清单1)来创建新的YouTubePlaylist对象,并将该对象作为以播放列表ID命名的新变量存储在window作用域中。

window[playlist_id] = new YouTubePlaylist(playlistId, entries);

现在,您可以使用window[playlist_id]访问YouTubePlaylist对象。 稍后,您将使用window[playlist_id]调用YouTubePlaylist对象的其他功能。

使用模板通过JsRender格式化播放器

播放器的轮廓类似于图4,右侧的缩略图,标题和注释列表由播放列表中的条目组成。

图4.新播放器的轮廓
该图显示了新播放列表播放器的结构

默认情况下,HTML字符集不包含与本机YouTube播放器上的下一个,上一个和随机图标相似的图标。 您的应用将使用Bootstrap前端框架提供的图标。 要导入Bootstrap样式表,请将以下代码段添加到<head>标记中。

<link rel="stylesheet" 
      type="text/css" 
      href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">

您将使用JsRender模板引擎来渲染YouTubePlaylist对象。 您可以在<script>标记中定义一个JsRender模板,并将其type属性设置为text/x-jsrender 。 通过使用要渲染的对象调用x-jsrender模板的render()方法来生成HTML。 您可以使用双大括号符号{{:}}在模板中呈现变量。 例如, {{:id}}呈现传递给模板的对象的id属性。

清单3中所示的模板将YouTube播放器嵌入到网页中。

清单3.嵌入YouTube播放器的模板
<object width="640" 
        height="360" 
data="http://www.youtube.com/v/video id?version=3&amp;enablejsapi=1&amp;playerapiid=id"
        id="player id" 
        type="application/x-shockwave-flash">
   <param value="always" name="allowScriptAccess">
   <param value="true" name="allowFullScreen">
</object>

在清单3中, video id是要播放的视频的ID,而播放器ID是播放器对象本身的ID。 初始化时,您将提示entries数组中的第一个视频,因此请在嵌入式播放器模板中输入{{:entries[0].video_id}}作为视频ID。 对于播放器ID,请使用播放列表ID,即{{:id}}

初始化YouTube播放器对象后,播放器将自动以播放器ID作为参数调用onYouTubePlayerReady()函数,以自定义其状态更改时的行为。 播放器的状态为未开始,结束,正在播放,暂停,正在缓冲和提示视频; 这些被枚举为-1、0、1、2、3和4。在API的当前版本中,无法自定义回调函数。 现在,您将在窗口范围内定义一个函数,以将下一个视频加载到播放列表中(稍后将在YouTubePlaylist对象中定义此函数),并将其作为事件侦听器添加到播放器。

清单4.用于在播放列表中加载下一个视频的函数
function onYouTubePlayerReady(playerApiId) {
   var player = document.getElementById(playerApiId);
   window["onStateChange" + playerApiId] = function(state) {   
      switch(state) {
         case 0:                         
var video_player = document.getElementById(player_id);
video_player.loadVideoById(window[player_id].getNextVideo(), 0, "large");
break; } }; player.addEventListener("onStateChange", "onStateChange" + playerApiId); }

要遍历视频数组,您将使用JsRender {{for}}标签。 您将使用清单5中的模板在图4的右侧创建每个播放列表条目。

清单5.用于在列表中创建每个播放列表条目的模板
{{for entries}}
<div class="playListEntry {{if #index == 0}}nowPlaying{{/if}}" id="{{:video_id}}">
   <div class="playListEntryThumbnail">
      <img src="{{:image_src}}"/>
   </div>
   <div class="playListEntryDescription">
      <div class="playListEntryTitle">{{:title}}</div>
      <div class="playListEntryNote">{{:note}}</div>
   </div>
</div>
{{/for}}

在清单5中, entriesYouTubePlaylist对象中的entries属性。 数组中对象的索引存储在#index变量中。 因为列表中的第一个条目是创建时播放器中加载的视频,所以您将通过使用{{if}}标记在for循环中将nowPlaying CSS类应用于第一个playListEntry类。

通过将Bootstrap glyphicon类应用于span ,使用glyphicon-backwardglyphicon-forwardglyphicon-random类,可以创建播放器底部的控件。

<div class="playListControls">
   <span class="playListControl disabled glyphicon glyphicon-backward"/>
   <span class="playListControl glyphicon glyphicon-forward"/>
   <span class="playListControl glyphicon glyphicon-random"/>
</div>

请注意,最初,“上一个”图标被禁用,因为当播放器首次加载时,它默认为播放列表中的第一个条目,因此没有以前的视频可以播放。

您需要将呈现HTML添加到具有此代码段的ID playlist的页面上的空白div (请记住window[player_id]引用了您在“ 创建YouTubePlaylist ”部分中创建的对象。

$('#' + player_id).html($('#playListPlayerTemplate').render(window[player_id]));

要使此代码可重复使用,请将其移至带有签名addPlaylistToElement(playlist_id, element_id)的函数中,然后可以使用addPlaylistToElement('PLLzJfby7cTLTbusOgXca-yIpVOImC1mWe', 'playlist')进行调用。

添加控件

返回到YouTubePlaylist对象并开始添加功能。 稍后,您将使用该对象的增强版本来完成网页中的播放器。

向对象添加六个函数: previous()next()getCurrentlyPlaying()setCurrentlyPlaying()randomize()isRandomized()previousnext功能移至播放列表中的相关视频,如果操作成功,则返回true否则,则返回false(即,如果用户在播放列表中的第一个条目上单击“上一个”或在操作上单击“下一个”,则返回false)。最后一个条目)。 getCurrentlyPlaying()返回播放列表中当前正在播放的视频的ID。 randomize()设置或isRandomizer()设置对象中的random属性,而isRandomizer()返回random属性的值。

清单6显示了Next()函数。

清单6. Next()函数
next: function() {
   var retVal = false;
   if(this.randomizer) {
      retVal = true;
      this.currently_playing = Math.floor((Math.random() * this.entries.length));
   }
   else if(this.currently_playing <= this.entries.length) {
      retVal = true;
      this.currently_playing++;
   } 
   return retVal;

Next()函数,首先检查如果random属性被设置,并且如果是,则设置currently_playing索引中的随机值entries阵列。 如果未设置random属性,并且currently_playing索引小于数组中的视频数量(也就是说,您尚未传递播放列表中的最后一个视频),则将索引的值增加1以移至下一个视频并返回true表示操作成功。 如果失败,则返回false

清单7显示了previous()函数。 如果currently_playing索引大于零(也就是说,用户正在观看播放列表中除第一个视频以外的任何视频),则将索引减1并返回true表示操作成功;否则,返回true 。 否则,返回false

清单7. previous()函数
previous: function() {
   var retVal = false;
   if(this.currently_playing > 0) {
      retVal = true;
      this.currently_playing--;
   } 
   return retVal;
}

getCurrentlyPlaying()函数中,返回getCurrentlyPlaying()数组中当前播放索引的视频ID。

getCurrentlyPlaying: function() {
   return this.entries[this.currently_playing].video_id;
}

清单8显示了setCurrentlyPlaying()函数。 给定一个video_id从当前播放列表中,设置currently_playing到在元件的索引entries array与该值。

清单8. setCurrentlyPlaying()函数
setCurrentlyPlaying: function(video_id) {
   for(var index = 0; index < this.entries.length; index++) {
      if (this.entries[index].video_id === video_id) {
         this.currently_playing = index;
         break;
      }
   }
}

randomize()函数中,将randomizer属性的值反转(从true到false,反之亦然),并返回新值。

randomize: function() {
   this.randomizer = !(this.randomizer);
   return this.randomizer;
}

isRandomized()函数返回播放列表的randomizer属性的值,即播放列表是否在随机播放中:

isRandomized: function() {
   return this.randomizer;
}

使用添加的功能

现在添加功能以使用JavaScript对象的添加功能。

首先,添加一个辅助函数来安排播放列表的控件。 如果播放器是随机播放:

  • “随机”图标突出显示。
  • 由于您不在任何地方录制以前播放的视频,因此始终禁用“上一个”图标。
  • 由于播放列表永远不会随机播放“最后一个”视频,因此始终启用“下一个”图标。 (考虑一下:当您的MP3播放器随机播放时,它会停止播放吗?)

如果播放列表不是随机播放的:

  • 仅当播放列表中的第一个条目正在播放时,“上一个”图标才被禁用。
  • 仅当播放列表中的最后一个条目正在播放时,“下一个”图标才被禁用。
  • 禁用“随机”图标,直到再次单击它。

清单9显示了helper函数。

清单9.用于安排播放列表控件的Helper函数
function arrangePlayerControls(player_id) {
   var playListPlayer = $('#' + player_id + 'playListPlayer');
   if(window[player_id].isRandomized()) {
      $('#' + player_id + 'Backward').addClass('disabled');
      $('#' + player_id + 'Forward').removeClass('disabled');
      $('#' + player_id + 'Random').addClass('randomizeActive');
   }
   else {
      $('#' + player_id + 'Random').removeClass('randomizeActive');
      var playListEntries = $('#' + player_id + 'playListEntries');
      if(playListEntries.children(":first").hasClass('nowPlaying')) {
         $('#' + player_id + 'Backward').addClass('disabled');
      }
      else {
         $('#' + player_id + 'Backward').removeClass('disabled');
      }
      if(playListEntries.children(":last").hasClass('nowPlaying')) {
         $('#' + player_id + 'Forward').addClass('disabled');
      }
      else {
         $('#' + player_id + 'Forward').removeClass('disabled');
      }
   }
}

接下来,添加一个功能,以给定的播放列表ID和开始播放的时间索引将视频加载到播放器中。 请记住从当前播放视频的div删除nowPlaying类,并将其添加到新视频的div中。 然后,调用清单9中的helper函数来安排播放列表图标。 清单10显示了视频加载功能。

清单10.将视频加载到播放器中的函数
function loadVideoForPlayer(currently_playing_video_id, player_id, time) {
   time = time || 0;
   var video_id = window[player_id].getCurrentlyPlaying();
   $('#' + currently_playing_video_id).removeClass('nowPlaying')
   $('#' + video_id).addClass('nowPlaying');
   $('#' + player_id + 'playListEntries').scrollTop($('#' + video_id).index() * 80);
   document.getElementById(player_id).loadVideoById(video_id, time, "large");
   arrangePlayerControls(player_id);
}

最后,添加一个功能以在给定播放列表中加载下一个视频,但前提是该播放列表中有另一个视频(也就是说,您不在随机播放中,并且当前视频不是最后一个视频)。

清单11.如果存在下一个视频,则加载视频的函数
function loadNextVideo(player_id) {
   var currently_playing_video_id = window[player_id].getCurrentlyPlaying();
   if(window[player_id].next()) {
      loadVideoForPlayer(currently_playing_video_id, player_id);
   }
}

这个功能类似于您在声明匿名函数onYouTubePlayerReady()清单4 ),所以重构case 0onYouTubePlayerReady()调用loadNextVideo()来代替。

您可能已经注意到,我在播放列表中为每个视频添加了目标时间。 借助这些新功能,您可以将目标时间用作链接热点,直接跳到视频中的目标,而无需全程观看。 在$.each()在环addPlaylistToElement()存储所述注释每一个的值playlistItem对象在局部变量,然后使用JavaScript match()函数以从纸币返回的次阵列,使用正则表达式/[0-9]*:[0-5][0-9]/g进行查找。 然后,您可以遍历此数组,并用链接替换变量中每次的值,以使用播放器ID,要播放的视频和开始的时间索引来调用cueThisVideo()函数。 请记住,YouTube API loadVideoById()调用花费的时间以秒为单位,因此请使用字符串中的冒号作为分隔符,将时间分成一个数组。 将第一个索引(分钟)中的值乘以60,将其转换为秒,然后将其添加到第二个索引中的秒,以获取秒的总数。 例如,1:30变成数组[1,30](1 * 60)+ 30 = 90秒。 最后,用新的链接替换注释中的时间。 每次处理便笺中的内容时,都将完整的字符串作为该条目的便笺存储在entries数组中,如清单12所示。

清单12.用链接替换笔记中的时间
var note = val.contentDetails.note;
var times = note.match(/[0-9]*:[0-5][0-9]/g);
times.forEach(function(value, index, array) {
   var time = value.split(":");
   var seconds = parseInt(time[0]) * 60;
   seconds += parseInt(time[1]);
   note = note.replace(value, 
     "<span class='timeLink' onclick='cueThisVideo(\"" 
     + player_id + "\", \"" 
     + video_id + "\", " 
     + seconds + ");'>" 
     + value + "</span>");
});
entry.note = note;

剩下的就是重新访问模板并添加对这些新功能的调用。 您希望用户能够通过单击标题或缩略图来使视频排队,将播放列表中的上一个或下一个视频排队,并使用控制面板中的相关按钮将播放列表随机化。 清单13显示了模板中完成的更改,以使用添加的功能。

清单13.重构的模板代码
<div onclick="cueThisVideo('{{:~player_id}}', '{{:video_id}}');" 
     class="playListEntryThumbnail">
          <img src="{{:image_src}}"/>
</div>
<div onclick="cueThisVideo('{{:~player_id}}', '{{:video_id}}');" 
     class="playListEntryTitle">
     {{:title}}
</div>

<span id="{{:id}}Backward" 
     class="playListControl disabled glyphicon glyphicon-backward" 
     onclick="if(!$(this).hasClass('disabled'))	{   loadPreviousVideo('{{:id}}')   }">
</span>
<span id="{{:id}}Forward" 
     class="playListControl glyphicon glyphicon-forward" 
     onclick="if(!$(this).hasClass('disabled')) {   loadNextVideo('{{:id}}')   }">
</span>
<span id="{{:id}}Random" 
     class="playListControl glyphicon glyphicon-random" 
     onclick="window['{{:id}}'].randomize();arrangePlayerControls('{{:id}}');">
</span>

现在,您的自定义播放器已准备就绪,可以摇滚!

结论

本文演示了如何使用YouTube API和一些简单JavaScript和样式来呈现嵌入式YouTube播放列表,并具有与YouTube.com上的本地播放列表相同的功能。 有关用于进一步增强播放器的一些建议,请参阅我的DevOps Services页面中的README文件。 随意分叉项目代码以实施任何或所有这些建议。


翻译自: https://www.ibm.com/developerworks/web/library/wa-bluemix-youtube/index.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值