Вступление


Наверняка многие фронтэнд разработчики да и в целом многие пользователи хоть раз интересовались работой и функционированием Youtube Player. В этой статье я расскажу, как он работает, и как сделать свой плеер для воспроизведения Youtube видео со своим интерфейсом. Так же приведу примеры для понимания, как это работает.

Для обычного пользователя снаружи ссылка на видео может выглядеть таким образом: www.youtube.com/watch?v={video_id} . Или, например, таким: youtu.be/{video_id} — где video_id — идентификатор видео в базе Youtube (он уникальный для каждого видео и самую важную информацию, по которой тянется видео, формируются ссылки и т.д). Для примера возьму, чтобы никого не обидеть (и не пиарить не дай бог) video_id=CyVuYAHiZb8 — видео ролик с Ray Charles — Hit the Road.

Как многие знают, для вставки собственно видео на свой сайт существует простая возможность «скопировать HTML код» при нажатии на видео правой кнопкой в Youtube и получить в буфере iframe:

<iframe width="640" height="360" src="https://www.youtube.com/embed/CyVuYAHiZb8" frameborder="0" allowfullscreen></iframe>

Таким iframe как раз и можно управлять на своем сайте. Далее расскажу, как это сделать на примере формирования своих элементов управления и обработчиков событий на Javascript + Jquery.

Страница с плеером — верстка


Сначала создаем простую html-страничку, в которой будут несколько div-block'ов, на которые мы привяжем наш плеер.

HTML-код страницы
<!DOCTYPE html>
<html>	
<head>
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>   <!-- jQuery -->
<script src="https://www.youtube.com/iframe_api"></script> <!-- Здесь цепляем кода iframe_api-->
<link rel='stylesheet' id='fortunato-style-css'  href='http://your.styles.css' type='text/css' media='' /> <!-- стили (в отдельном куске css кода)-->
</head>
<body>	   
<div class="panel">
<button id="back" onclick="player.previousVideo();">Back</button>
<button id="play" onclick="player.playVideo();">Play</button>
<button id="pause" onclick="player.pauseVideo();">Pause</button>
<button id="next" onclick="player.nextVideo();">Next</button>
<div id="time">00:00</div>		
<div id="line" onclick="progress (event);">
<div class="viewed"></div>
<div id="fader" onclick="alert('fader');"></div>
</div>
<button id="volume" onclick="editVolume ();">Громкость</button>
<div id="quality">Auto</div>
<button id="full" onclick="playFullscreen ();">FullScreen</button>
</div>		
<div>
<button id="playlist" onclick="loadPlaylistVideoIds();">Load New Playlist</button>
<button id="qual" onclick="editQuality ();">Сменить качество на 480</button>
</div>
</body>	
</html>



Стили кнопок и плеера
body {
	margin: 0;			
}
.panel {
	width: 850px; 
	height: 40px; 
	background: grey;
	margin-top: -5px;
	border: 1px solid #aaa;
}
#play, #back, #next, #pause{
	float: left;
	width: 50px;
	height: 40px;
}
#time{
	float: left;
	width: 50px;
	height: 40px;
	color: #fff;
	padding-top: 10px;
	margin-left: 10px;
}
#line{
	margin-top: 15px;	
	height: 4px;
	width: 350px;
	background: #fff;
	float: left;
	margin-right: 15px;
}
#volume {
	float: left;
	width: 80px;
	height: 40px;
}
#quality{
	float: left;
	width: 50px;
	height: 40px;
	color: #fff;
	padding-top: 10px;
	margin-left: 10px;
}
#full {
	float: left;
	width: 75px;
	height: 40px;
}
#fader {
	background: black;
	border-radius: 5px;
	width: 10px;
	height: 10px;
	position: relative;
	z-index: 4;
	bottom: 3px;
}
#playlist {
	margin-top: 20px;
}
.viewed {
	position: absolute;
	background: red;
	height: 4px;
}


И самое главное — javascript.

Для создания и инициализации плеера через iframe api необходим div с идентификатором, к которому будет привязываться iframe с видео. В нашем случае это
<div id="player"></div>


Управление плеером — JavaScript


Все равно, куда вы его положите, но главное ниже подключаемых библиотек (для простоты можно прямо в html-документе).

Весь Javascript-код - функции
//Инициализация плеера
function onYouTubeIframeAPIReady() {
	  player = new YT.Player('player', {
		height: '500',
		playerVars: { 'autoplay': 0, 'controls': 0, 'showinfo': 0, 'rel': 0},
		width: '850',
		videoId: 'CyVuYAHiZb8',
		events: {
		  'onReady': onPlayerReady
		}
  });
}

// Обработчик готовность
function onPlayerReady(event) {
	var player = event.target;
	iframe = document.getElementById('player');
	setupListener(); 			  
	updateTimerDisplay();
	updateProgressBar();
				
	time_update_interval = setInterval(function () {
		updateTimerDisplay();
		updateProgressBar();
	}, 1000);		  
}
/*Слушать события*/
function setupListener (){
	document.getElementById('full').addEventListener('click', playFullscreen);
}
/*Включение фуллскрина*/
function playFullscreen (){
	player.playVideo();//won't work on mobile
			  
	  var requestFullScreen = iframe.requestFullScreen || iframe.mozRequestFullScreen || iframe.webkitRequestFullScreen;
	  if (requestFullScreen) {
		requestFullScreen.bind(iframe)();
	  }
}
/*Загрузить плейлист*/			
function loadPlaylistVideoIds(); {
	player.loadPlaylist({
		'playlist': ['9HPiBJBCOq8', 'Mp4D0oHEnjc', '8y1D8KGtHfQ', 'jEEF_50sBrI'],
		'listType': 'playlist',
		'index': 0,
		'startSeconds': 0,
		'suggestedQuality': 'small'
			});
}			
/*Громкость*/
function editVolume () {				
	if (player.getVolume() == 0) {
		player.setVolume('100');
	} else {
		player.setVolume('0');
	}
}
			
/*Качество*/
function editQuality () {
	player.setPlaybackQuality('medium');			
	document.getElementById('quality').innerHTML = '480';
}
			
// Обновляем время на панельке - счетчик
function updateTimerDisplay(){
	document.getElementById('time').innerHTML = formatTime(player.getCurrentTime());
}
/*Формат времени*/
function formatTime(time){
	time = Math.round(time);
	var minutes = Math.floor(time / 60),
	seconds = time - minutes * 60;
	seconds = seconds < 10 ? '0' + seconds : seconds;
	return minutes + ":" + seconds;
}

// Обновляем прогресс
function updateProgressBar(){

	var line_width = jQuery('#line').width();
	var persent = (player.getCurrentTime() / player.getDuration());
	jQuery('.viewed').css('width', persent * line_width);
	per = persent * 100;
	jQuery('#fader').css('left', per+'%');
}

/*Линия прогресса*/
function progress (event) {
				
	var line_width = jQuery('#line').width();
	// положение элемента
	var pos = jQuery('#line').offset();
	var elem_left = pos.left;		
	// положение курсора внутри элемента
	var Xinner = event.pageX - elem_left;
	var newTime = player.getDuration() * (Xinner / line_width);
	// Skip video to new time.
	player.seekTo(newTime);
}



А теперь как это работает. Для начала создаем плеер — для этого нужна обязательная функция:

  //Инициализация плеера
function onYouTubeIframeAPIReady() {
   player = new YT.Player('player', {
                         height: '500',
			playerVars: { 'autoplay': 0, 'controls': 0, 'showinfo': 0, 'rel': 0},
			width: '850',
			videoId: 'CyVuYAHiZb8',
			events: {
			  'onReady': onPlayerReady
			}
		 });
}

Она вызывается сама по видимому сразу, а внутри нее создается объект YT.Player с параметрами. Первый 'player' — идентификатор
<div id="player"></div>
к которому при инициализации цепляется iframe. Далее height и width — размеры iframe, videoId: 'CyVuYAHiZb8' — идентификатор видео — это наш Рэй Чарльз. playerVars: { 'autoplay': 0, 'controls': 0, 'showinfo': 0, 'rel': 0} — это настройки плеера, сами говорят за себя -стоят нули, чтобы выключить элементы управления, которые мы делаем свои.

И events: {'onReady': onPlayerReady} — хук, цепляющий метод для обработки события готовности. Дальше как раз идет эта функция, в ней собраны методы для обработки событий и т.п.

Теперь что касается объекта player. Он создан и им можно управлять, вызывая методы, как в панели управления в html — кнопочки.

HTML-код панельки плеера
<div class="panel">
	<button id="back" onclick="player.previousVideo();">Back</button>
	<button id="play" onclick="player.playVideo();">Play</button>
	<button id="pause" onclick="player.pauseVideo();">Pause</button>
	<button id="next" onclick="player.nextVideo();">Next</button>
	<div id="time">00:00</div>		
	<div id="line" onclick="progress (event);">
		<div class="viewed"></div>
		<div id="fader" ></div>			
	</div>
	<button id="volume" onclick="editVolume ();">Громкость</button>
	<div id="quality">Auto</div>
	<button id="full" onclick="playFullscreen ();">FullScreen</button>
	</div>		
	<div>
	<button id="playlist" onclick="loadPlaylistVideoIds();">Load New Playlist</button>
	<button id="qual" onclick="editQuality ();">Сменить качество на 480</button>
</div>



Кнопки play и pause
<button id="play" onclick="player.playVideo();">Play</button> 
— play
<button id="pause" onclick="player.pauseVideo();">Pause</button>
— pause
Здесь все просто плей-пауза

Кнопки back и next
<button id="back" onclick="player.previousVideo();">Back</button>
<button id="next" onclick="player.nextVideo();">Next</button>

Эти кнопки нужны для переключения видео в плейлисте.

Для создания плейлиста есть кнопка
<button id="playlist" onclick="loadPlaylistVideoIds();">Load New Playlist</button>
— которая вызывает функцию по клику.

Эта функция вызывает метод player.loadPlaylist ({....})
function loadPlaylistVideoIds(); {
       player.loadPlaylist({
	        'playlist': ['9HPiBJBCOq8', 'Mp4D0oHEnjc', '8y1D8KGtHfQ', 'jEEF_50sBrI'],
	        'listType': 'playlist',
		'index': 0,
		'startSeconds': 0,
		'suggestedQuality': 'small'
	});
}

с параметрам playlist': ['9HPiBJBCOq8', 'Mp4D0oHEnjc', '8y1D8KGtHfQ', 'jEEF_50sBrI'] — список видео в плейлисте. 'listType': 'playlist' — тип, 'index': 0 — индекс видео, с которого начать, остальные параметры очевидны. Так загружаются плейлисты. Также плейлист можно инициализировать прямо в начале, тогда нужно в параметрах объекта YT.Player прописать playerVars: { 'autoplay': 0, 'controls': 0, 'showinfo': 0, 'rel': 0, playlist': ['9HPiBJBCOq8', 'Mp4D0oHEnjc', '8y1D8KGtHfQ', 'jEEF_50sBrI'] },

Также реализованы кнопки управления громкостью
<button id="volume" onclick="editVolume ();">Громкость</button>
— при нажатии включает или вырубает звук. Используются методы по аналогии:
/*Громкость*/
function editVolume () {				
	if (player.getVolume() == 0) {
		player.setVolume('100');
	} else {
		player.setVolume('0');
	}
}

А также качество

<button id="qual" onclick="editQuality ();">Сменить качество на 480</button>


/*Качество*/
function editQuality () {
	player.setPlaybackQuality('medium');			
	document.getElementById('quality').innerHTML = '480';
}

И фуллскрин
<button id="full" onclick="playFullscreen ();">FullScreen</button>

function playFullscreen (){
	player.playVideo();		  
	var requestFullScreen = iframe.requestFullScreen || iframe.mozRequestFullScreen || iframe.webkitRequestFullScreen;
	if (requestFullScreen) {
		requestFullScreen.bind(iframe)();
        }
}


Здесь кратко описаны функции для работоспособности панельки. В итоге — Кнопки Play, Pause, есть кнопка загрузки плейлиста из 3-х видео, Next и Back для плейлиста, фейдер и линия прогрузки, обновляющееся время, кнопки, демонстрирующие работу громкости, качества и фуллскрин — все это начальные сведения для разработки собственного плеера, взаимодействующего с Youtube Iframe.

Демо вариант доступен Вот тут

При написании статьи использовался мануал от Youtube в котором можно найти расширенное описание работы с Youtube iframe API здесь

Ресурсы, реализующие такой плеер


  • Про функционирование кнопки для fullscreen я нашел пример на codepen
  • Демо вариант от ютуба можно посмотреть у них демо Youtube — но тут не совсем то.
  • Ещё на просторах интернета нашел сайт Valera.tv с реализацией такого плеера со своим забавным дизайном.
  • Кстати, аналогичный плеер был сделан в ВКонтакте, но почему то они от него отказались, и просто вставляют стандартный iframe c ютубовскими кнопками.
  • Также для справки аналогичный плеер и реализацию через Youtube iframe API для плеера делает Uppod — но он частично платный и про него кучу раз писали.


Заключение


В целом в статье приводится один пример создания своего плеера, транслирующего Youtube видео на вашем сайте с использованием Javascript.
Поделиться с друзьями
-->

Комментарии (10)


  1. cjbars
    29.07.2016 20:11
    +1

    А как быть с несколькими плеерами на странице? Привязка к id? Для каждого ручками писать? Я может что-то недопонял


    1. ShapitoS999
      29.07.2016 21:01

      cjbars, можно реализовать как сделано в ВК на стене — обернуть в div ссылку с каким-нибудь параметром (все что угодно можно какой-то уникальный селектор, например, имя класса). Там ссылка имеет вид картинки с кнопкой плей посередине. При клике по ней можно например инициализировать событие, и по событию в нужный div внутрь подкладывать iframe с помощью функции onYouTubeIframeAPIReady() например, и подменять. Таким образом получается плеер один на странице, а остальное — ссылки с картинками. А вообще странно создавать несколько плееров с разными id-ми — это грузит страницу, наверняка вы видели кучу тяжелых сайтов с видео рекламой, которая врубается по скроллу. Как-то так.


  1. nazarpc
    30.07.2016 07:50

    Подскажите, пожалуйста, вы не нарушаете случайно лицензионное соглашение таким использованием сервиса и его кода?


    1. ShapitoS999
      30.07.2016 13:01

      Нет, в принципе здесь сложно что-то нарушить, потому что Youtube Iframe API находится в открытом доступе. Идентификаторы же для видео, несущие смысловую нагрузку для ретрансляции на внешний сайт несут также разрешение на публикацию. Если в плеер попадает видео без права на ретрансляцию, то формируется сообщение об ошибке, которое можно обработать с хуком 'onError': onPlayerError


      1. nazarpc
        30.07.2016 13:07

        Фронтенд любого сайта в этом смысле в открытом доступе, так что сложно назвать это аргументом.


        1. ShapitoS999
          30.07.2016 13:20

          Ну в смысле Youtube ничего не требует от размещения и использования iframe самого плеера. Ознакомьтесь по подробнее https://developers.google.com/youtube/iframe_api_reference?hl=ru
          И здравый смысл подсказывает, что без этого они бы не реализовывали вставку

          <iframe width="640" height="360" src="https://www.youtube.com/embed/CyVuYAHiZb8" frameborder="0" allowfullscreen></iframe>
          

          на внешние сайты. Какова цель вашего последнего комментария?


          1. nazarpc
            30.07.2016 15:24

            То, что вы можете использовать готовый продукт ещё не значит что вы можете его менять, и тем более выдавать за оригинальный продукт.
            Моя цель — любопытство.


            1. ShapitoS999
              30.07.2016 17:15

              nazarpc, да API готовый, но интерфейс можно создать свой собственный. Если вы хотите сделать свое, то Вам придется как-то хранить видео, использовать HTML5 или иной плеер, писать свой собственный код для нового проекта. Цель статьи — помочь людям разобраться с функциональностью и продемонстрировать пример работы уже существующего Youtube Iframe API. В рамках лицензии на публикацию ничего не нарушается. Может Вам что-то не нравится в статье или в демо?


  1. CodeViking
    30.07.2016 15:24

    Тоже думал о создании плеера со своим дизайном в будущем проекте. Во время вышла статья, благодарю. Интересно, есть ли смысл в библиотеке, позволяющем создавать такие плееры?


    1. ShapitoS999
      30.07.2016 15:28

      Возможно есть. Упомянутый в статье плеер Uppod реализовал что-то подобное на уровне библы, но там было множество неприятных багов.