From 761d627871b93b4fde4578f32c8761977e309d22 Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Mon, 12 Sep 2016 15:36:24 +0000 Subject: [PATCH 1/2] Brightcove implementation --- src/AMP.php | 1 + src/Pass/IframeBrightCoveTagTransformPass.php | 160 ++++++++++++++++++ src/Utility/ActionTakenType.php | 1 + 3 files changed, 162 insertions(+) create mode 100644 src/Pass/IframeBrightCoveTagTransformPass.php diff --git a/src/AMP.php b/src/AMP.php index 9836e62a..596abebc 100644 --- a/src/AMP.php +++ b/src/AMP.php @@ -58,6 +58,7 @@ class AMP 'Lullabot\AMP\Pass\IframeVineTagTransformPass', 'Lullabot\AMP\Pass\IframeDailymotionTagTransformPass', 'Lullabot\AMP\Pass\IframeYouTubeTagTransformPass', + 'Lullabot\AMP\Pass\IframeBrighCoveTagTransformPass', 'Lullabot\AMP\Pass\IframeTagTransformPass', 'Lullabot\AMP\Pass\InstagramTransformPass', 'Lullabot\AMP\Pass\PinterestTagTransformPass', diff --git a/src/Pass/IframeBrightCoveTagTransformPass.php b/src/Pass/IframeBrightCoveTagTransformPass.php new file mode 100644 index 00000000..0e5e85df --- /dev/null +++ b/src/Pass/IframeBrightCoveTagTransformPass.php @@ -0,0 +1,160 @@ + tags which don't have noscript as an ancestor to tags + * + * This is what a BrighCove embed looks like: + * + * + * @see https://github.com/ampproject/amphtml/blob/master/extensions/amp-BrighCove/amp-BrighCove.md + * @see https://developers.google.com/BrighCove/iframe_api_reference + * + */ +class IframeBrighCoveTagTransformPass extends BasePass +{ + /** + * A standard BrighCove video aspect ratio + * @var float + */ + const DEFAULT_ASPECT_RATIO = 1.7778; + const DEFAULT_VIDEO_WIDTH = 560; + const DEFAULT_VIDEO_HEIGHT = 315; + + function pass() + { + $all_iframes = $this->q->find('iframe:not(noscript iframe)'); + /** @var DOMQuery $el */ + foreach ($all_iframes as $el) { + /** @var \DOMElement $dom_el */ + $dom_el = $el->get(0); + if (!$this->isBrighCoveIframe($el)) { + continue; + } + + $lineno = $this->getLineNo($dom_el); + $context_string = $this->getContextString($dom_el); + $brightcove_code = $this->getBrightcoveCode($el); + + // If we couldnt find a BrighCove videoid then we abort + if (empty($brightcove_code)) { + continue; + } + + if ($el->hasAttr('class')) { + $class_attr = $el->attr('class'); + } + + /** @var \DOMElement $new_dom_el */ + $el->after(""); + $new_el = $el->next(); + $new_dom_el = $new_el->get(0); + if (!empty($class_attr)) { + $new_el->attr('class', $class_attr); + } + $this->setStandardAttributesFrom($el, $new_el, self::DEFAULT_VIDEO_WIDTH, self::DEFAULT_VIDEO_HEIGHT, self::DEFAULT_ASPECT_RATIO); + $this->setBrightcoveAttributesFrom($el, $new_el); + + // Remove the iframe and its children + $el->removeChildren()->remove(); + $this->addActionTaken(new ActionTakenLine('iframe', ActionTakenType::BRIGHTCOVE_IFRAME_CONVERTED, $lineno, $context_string)); + $this->context->addLineAssociation($new_dom_el, $lineno); + } + + return $this->transformations; + } + + /** + * @param DOMQuery $el + * @return bool + */ + protected function isBrighCoveIframe(DOMQuery $el) + { + $href = $el->attr('src'); + if (empty($href)) { + return false; + } + + if (preg_match('&(*UTF8)(brighcove\.com|youtu\.be)&i', $href)) { + return true; + } + + return false; + } + + /** + * + * Get the brightcove videoid + * + * @param DOMQuery $el + * @return string + */ + protected function getBrightcoveCode(DOMQuery $el) + { + $matches = []; + $brightcove_code = ''; + $href = $el->attr('src'); + + // @todo there seem to be a lot of ways to embed a brightcove video. We probably need to capture all patterns here + // The next one is the embed code that brightcove gives you + if (preg_match('&(*UTF8)/embed/([^/?]+)&i', $href, $matches)) { + if (!empty($matches[1])) { + $brightcove_code = $matches[1]; + } + } + elseif (preg_match('&(*UTF8)brightcove/([^/?]+)&i', $href, $matches)) { + if (!empty($matches[1])) { + $brightcove_code = $matches[1]; + } + } + elseif (preg_match('!(*UTF8)watch\?v=([^&]+)!i', $href, $matches)) { + if (!empty($matches[1])) { + $brightcove_code = $matches[1]; + } + } + + return $brightcove_code; + } + + /** + * @param DOMQuery $el + * @param DOMQuery $new_dom_el + */ + protected function setBrightcoveAttributesFrom($el, $new_dom_el) + { + $arr = $this->getQueryArray($el); + // From https://github.com/ampproject/amphtml/blob/master/extensions/amp-brightcove/amp-brightcove.md + // "All data-param-* attributes will be added as query parameter to the brightcove iframe src. This may be used to + // pass custom values through to brightcove plugins, such as autoplay." + // + // We're doing this in reverse: we see the query parameters and we make them data-param-* + foreach ($arr as $query_name => $query_value) { + $new_dom_el->attr("data-param-$query_name", $query_value); + } + } +} diff --git a/src/Utility/ActionTakenType.php b/src/Utility/ActionTakenType.php index 37f437cb..658e96dc 100644 --- a/src/Utility/ActionTakenType.php +++ b/src/Utility/ActionTakenType.php @@ -37,6 +37,7 @@ class ActionTakenType const IFRAME_CONVERTED = 'tag was converted to the amp-iframe tag.'; const IFRAME_CONVERTED_AND_HTTPS = 'tag was converted to the amp-iframe tag. The url protocol was changed to explicitly use https. amp-iframe does not support http'; const YOUTUBE_IFRAME_CONVERTED = 'tag was converted to the amp-youtube tag.'; + const BRIGHTCOVE_IFRAME_CONVERTED = 'tag was converted to the amp-youtube tag.'; const SOUNDCLOUD_IFRAME_CONVERTED = 'tag was converted to the amp-soundcloud tag.'; const COMPONENT_SCRIPT_TAG_ADDED = 'custom component script tag added to head'; const AUDIO_CONVERTED = 'tag was converted to the amp-audio tag.'; From fffcf0110d7e45607c3e02258fbaae8957db3162 Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Mon, 12 Sep 2016 15:38:22 +0000 Subject: [PATCH 2/2] Some minor changes --- src/Pass/IframeBrightCoveTagTransformPass.php | 2 +- src/Utility/ActionTakenType.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Pass/IframeBrightCoveTagTransformPass.php b/src/Pass/IframeBrightCoveTagTransformPass.php index 0e5e85df..684343c4 100644 --- a/src/Pass/IframeBrightCoveTagTransformPass.php +++ b/src/Pass/IframeBrightCoveTagTransformPass.php @@ -100,7 +100,7 @@ protected function isBrighCoveIframe(DOMQuery $el) return false; } - if (preg_match('&(*UTF8)(brighcove\.com|youtu\.be)&i', $href)) { + if (preg_match('&(*UTF8)(brighcove\.com)&i', $href)) { return true; } diff --git a/src/Utility/ActionTakenType.php b/src/Utility/ActionTakenType.php index 658e96dc..c4120fb5 100644 --- a/src/Utility/ActionTakenType.php +++ b/src/Utility/ActionTakenType.php @@ -37,7 +37,7 @@ class ActionTakenType const IFRAME_CONVERTED = 'tag was converted to the amp-iframe tag.'; const IFRAME_CONVERTED_AND_HTTPS = 'tag was converted to the amp-iframe tag. The url protocol was changed to explicitly use https. amp-iframe does not support http'; const YOUTUBE_IFRAME_CONVERTED = 'tag was converted to the amp-youtube tag.'; - const BRIGHTCOVE_IFRAME_CONVERTED = 'tag was converted to the amp-youtube tag.'; + const BRIGHTCOVE_IFRAME_CONVERTED = 'tag was converted to the amp-brightcove tag.'; const SOUNDCLOUD_IFRAME_CONVERTED = 'tag was converted to the amp-soundcloud tag.'; const COMPONENT_SCRIPT_TAG_ADDED = 'custom component script tag added to head'; const AUDIO_CONVERTED = 'tag was converted to the amp-audio tag.';