The Ultimate YouTube regex for VideoParser

Регулярка для обработки ссылок с YouTube видеопарсером (вставляется вместо этого).
Поддерживаются следующие типы ссылок:
(~)youtube.com/watch?v=jvtWyKYckI0
(~)youtube.com/e/jvtWyKYckI0
(~)youtube.com/embed/jvtWyKYckI0
(~)youtube.com/v/jvtWyKYckI0
(~)youtube.com/watch?some=params&v=jvtWyKYckI0
(~)youtube.com/watch?v=jvtWyKYckI0&some=params
(~)youtu.be/jvtWyKYckI0
(~)youtu.be/jvtWyKYckI0&some=params

(~) = :
    https://www.
    http://www.
    https://
    http://
    www.
    m.
    //
    ''


Сабж (с описанием):
$sYoutubeURL  = '/<video>';	        # video tag (begin)
$sYoutubeURL .= '(?:http(?:s|):|)';	# optional URL Scheme
$sYoutubeURL .= '(?:\/\/|)';		# optional //
$sYoutubeURL .= '(?:www\.|m.|)';	# optional www or m subdomain
$sYoutubeURL .= 'youtu(?:\.|)be';	# youtube or youtu.be
$sYoutubeURL .= '(?:-nocookie|)';	# youtube-nocookie
$sYoutubeURL .= '(?:\.com|)';		# optional '.com' (may be '.be')
$sYoutubeURL .= '\/(?:';		# Optional group path alternatives:
$sYoutubeURL .= 'e(?:mbed|)\/';		# /e/ or /embed/
$sYoutubeURL .= '|v\/';			# /v/
$sYoutubeURL .= '|watch\?(?:.+&|)';	# watch - with optional params
$sYoutubeURL .= 'v=|)';			# video pre-id
$sYoutubeURL .= '([a-zA-Z0-9_\-]+?)';	# video id
$sYoutubeURL .= '(&.+)?';		# optional params (after video id)
$sYoutubeURL .= '<\/video>/Ui';		# video tag (end)

$sText = preg_replace(
    $sYoutubeURL,
    '<iframe width="560" height="315" src="http://www.youtube.com/embed/$1" frameborder="0" allowfullscreen></iframe>',
    $sText
);


«Короткая» версия:
$sText = preg_replace(
    '/<video>(?:http(?:s|):|)(?:\/\/|)(?:www\.|m.|)youtu(?:\.|)be(?:-nocookie|)(?:\.com|)\/(?:e(?:mbed|)\/|v\/|watch\?(?:.+&|)v=|)([a-zA-Z0-9_\-]+?)(&.+)?<\/video>/Ui',
    '<iframe width="560" height="315" src="http://www.youtube.com/embed/$1" frameborder="0" allowfullscreen></iframe>',
    $sText
);

P.S.: Заранее извиняюсь за выпендреж с названием топика

UPD: Немного обновил (опциональная точка между youtu и be) + поправка от PSNet
UPD 15.01.2016: Добавлен опциональный субдомен m. (m.youtube.com — при заходе с мобильных устройств)

34 комментария

avatar
Спасибо!
avatar
Почему не pull request?
avatar
От VK бы получить новый парсер. А то не удобно вставлять ссылку из кода, а по-другому я не знаю как реализовать.

Вот с таким вот костылём приходиться работать:

/**
		 * vk.com
		 */
		$sText = preg_replace('/<video>(https:\/\/(?:www\.|)vk\.com\/video_ext\.php.*)<\/video>/i', '<iframe src="$1" width="500" height="281" frameborder="0"></iframe>', $sText);
		/**
avatar
В ВК для iframe требуется знать hash который формирует вконтакт, этот hash присутствует в поделиться->код вставки. Т.е. простой ссылкой на видео вставить не получиться, т.к. неизветен hash. И Ваша конструкция кажись неработоспособная, вставляйте iframe, других вариантов кажись нет.
avatar
у меня всё работает как раз. Приходиться вставлять вот такую ссылку:
https://vk.com/video_ext.php?oid=-74449836&id=171127780&hash=90d0a2cb9e46cf4f


В поддержке ВК меня кинули на эту страницу vk.com/dev/video.get
avatar
Быстренько набросал парсер для видео вконтакта, испытал — кажись работает нормально.
Для каждого видео из вконтакта идет загрузка странички с видео из вконтакта, т.е. идут запросы к вконтакту, это необходимо для получения значения hash видео. К счастью это происходит только при добавлении или редактировании топика или коммента, соответственно в этот момент возможен «небольшая» задержка, по другому пока не получается.

Допускаются ссылки вида
<video>http://vk.com/video123456789_123456789</video>

Код (добавить в Text.class.php в функцию VideoParser):
#Регулярка для вконтакта
$regExp = '/<video>http(?:s|):\/\/(?:www\.|)vk\.com\/video([\d]+)_([\d]+)<\/video>/Ui';
#Если есть видео из вконтакта
if(preg_match($regExp, $sText)) {
	#Считаем количество видео вконтакта
	preg_match_all($regExp, $sText, $sTextMatches);
	for($i=0;$i<count($sTextMatches[1]);$i++){
		#Получаем страницу с видео
		$html = file_get_contents('http://vk.com/video'.$sTextMatches[1][$i].'_'.$sTextMatches[2][$i]);
		#Ищем hash для видео
		preg_match('/\\\"hash2\\\":\\\"([a-f0-9]+)\\\"/Ui', $html, $matches);
		#Заменяем ссылки
		$sText = preg_replace('/<video>http(?:s|):\/\/(?:www\.|)vk\.com\/video'.$sTextMatches[1][$i].'_'.$sTextMatches[2][$i].'<\/video>/Ui', '<iframe src="http://vk.com/video_ext.php?oid='.$sTextMatches[1][$i].'&id='.$sTextMatches[2][$i].'&hash='.$matches[1].'" width="560" height="315" frameborder="0"></iframe>', $sText);
	}
}

Не забудьде добавить vk.com в jevix.php
avatar
спасибо. работает.
avatar
Немного доработал
$regExp = '/<video>(?:http(?:s|):|)(?:\/\/|)(?:www\.|)vk\.com\/video([\d]+)_([\d]+)(?:\?[\s\S]+|)<\/video>/Ui';
if(preg_match($regExp, $sText)) {
	preg_match_all($regExp, $sText, $sTextMatches);
	for($i=0;$i<count($sTextMatches[1]);$i++){
		$html = file_get_contents('http://vk.com/video'.$sTextMatches[1][$i].'_'.$sTextMatches[2][$i]);
		preg_match('/\\\"hash2\\\":\\\"([a-f0-9]+)\\\"/Ui', $html, $matches);
		$sText = preg_replace('/<video>(?:http(?:s|):|)(?:\/\/|)(?:www\.|)vk\.com\/video'.$sTextMatches[1][$i].'_'.$sTextMatches[2][$i].'(?:\?[\s\S]+|)<\/video>/Ui', '<div class="vd-w"><div class="vd-c"><iframe src="http://vk.com/video_ext.php?oid='.$sTextMatches[1][$i].'&id='.$sTextMatches[2][$i].'&hash='.$matches[1].'" width="560" height="315" frameborder="0"></iframe></div></div>', $sText);
	}
}
avatar
Скопировал с оптимизацией под свой шаблон:
В строке
$sText = preg_replace('/<video>(?:http(?:s|):|)(?:\/\/|)(?:www\.|)vk\.com\/video'.$sTextMatches[1][$i].'_'.$sTextMatches[2][$i].'(?:\?[\s\S]+|)<\/video>/Ui', '<div class="vd-w"><div class="vd-c"><iframe src="http://vk.com/video_ext.php?oid='.$sTextMatches[1][$i].'&id='.$sTextMatches[2][$i].'&hash='.$matches[1].'" width="560" height="315" frameborder="0"></iframe></div></div>', $sText);


Нужно удалить '' и ''
avatar
Нужно удалить
<div class="vd-w"><div class="vd-c">
и
</div></div>

Парсер обрезал в прошлом сообщении
avatar
А что это объяснить для человека обычного может? В чем разница стандартного и этого варианта кода?
Может графически показать можете?
avatar
в стандарте ты можешь только вставлят ссылку типа
avatar
youtube.com/watch?v=jvtWyKYckI0 и все. Тут различные варианты.
avatar
с
avatar
с кодом iframe этот номер проходит тоже? Просто зачастую хочешь внедрить уникальный плеер с какого-нибудь сайта, а не выходит. Дописывание домена в файл jevix не помогало… Этот метод поможет с этим?
avatar
поможет. В места стандартного плеера ютуба можно прописать свой.
avatar
Огромное спасибо! добра тебе добрый человек.
avatar
при добавление видео с контакта пишет Видео не найдено в чем может быть проблема?
avatar
А как бы сделать, так, что бы пользователь мог просто в код вставлять ссылку на ютуб.
некоторые так и делают не пользуясь тегами…
Подскажите с обработкой плз
avatar
А если пользователь хочет вставить именно ссылку на видео? По моему для этого и существует тег video, чтобы обозначить url как для вставки в топик фреймом…
avatar
Не все пользователи такое понимают. Тупорылят иногда
avatar
вам либо плагин, либо убрать по бокам регулярки <video> и использовать правки ниже
avatar
если убрать (или сделать опцией) теги <video> по бокам, то будет «косяк» — iframe также сделается ссылкой (ведь в ссылке будет http) со всякими там rel="nofollow"
avatar
не должно быть, ведь парсер знает о фрейме.
avatar
решил протестить регулярку, не на всех версиях PCRE будет работать, поэтому желательно строку
$sYoutubeURL .= '([a-zA-Z0-9_\-]+)'; # video id

заменить на
$sYoutubeURL .= '([a-zA-Z0-9_\-]+?)'; # video id

для инвертирования модификатора жадности и чтобы забрать весь ид видео если вся ссылка аккуратная и без каки
avatar
хочу заметить что у большинства будет работать и без этой правки т.к. ссылку оборачивают в <video>
avatar
Спасибо, обновил.
avatar
Как вставлять с ютуба с определенного момента?
avatar
Такой возможности нет?
avatar
Наверно нет?
avatar
Примерно так:
$sYoutubeURL = "/<video>(?:https?:\/\/)?(?:(?:www\.))?(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})(?:\?(?:t|start)=((?:[0-9]{1,10}[hms]?){1,4}))?<\/video>/i";

preg_match($sYoutubeURL, $sText, $NrOutputs);

if (count($NrOutputs) == 2) {
    $sText = preg_replace(
        $sYoutubeURL,
        '<iframe width="560" height="315" src="http://www.youtube.com/embed/$1" frameborder="0" allowfullscreen></iframe>',
        $sText
    );
} elseif (count($NrOutputs) == 3 ) {
    $sText = preg_replace(
        $sYoutubeURL,
        '<iframe width="560" height="315" src="http://www.youtube.com/embed/$1?start=$2" frameborder="0" allowfullscreen></iframe>',
        $sText
    );
}
avatar
очень хорошо! Обязательно попробую! ))
avatar
Спасибо
avatar
Огромное спасибо
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.