diff --git a/src/AMP.php b/src/AMP.php
index b1eb5f6c..3bf2417e 100644
--- a/src/AMP.php
+++ b/src/AMP.php
@@ -47,6 +47,7 @@ class AMP
// The StandardScanPass should be first after all transform passes
// The StandardFixPass should be after StandardScanPass
+ // The ObjectVideoTagTransformPass should be after all Object transform passes
public $passes = [
'Lullabot\AMP\Pass\PreliminaryPass', // Removes user blacklisted tags
'Lullabot\AMP\Pass\ImgTagTransformPass',
@@ -63,6 +64,9 @@ class AMP
'Lullabot\AMP\Pass\PinterestTagTransformPass',
'Lullabot\AMP\Pass\FacebookNonIframeTransformPass',
'Lullabot\AMP\Pass\TwitterTransformPass',
+ 'Lullabot\AMP\Pass\ObjectYouTubeTagTransformPass',
+ 'Lullabot\AMP\Pass\ObjectVimeoTagTransformPass',
+ 'Lullabot\AMP\Pass\ObjectVideoTagTransformPass',
'Lullabot\AMP\Pass\StandardScanPass',
'Lullabot\AMP\Pass\StandardFixPass',
'Lullabot\AMP\Pass\AmpImgFixPass',
diff --git a/src/Pass/ObjectVideoTagTransformPass.php b/src/Pass/ObjectVideoTagTransformPass.php
new file mode 100644
index 00000000..fde2f6eb
--- /dev/null
+++ b/src/Pass/ObjectVideoTagTransformPass.php
@@ -0,0 +1,112 @@
+ tags
+ *
+ * This is what a video embed looks like:
+ *
+ */
+class ObjectVideoTagTransformPass extends BasePass
+{
+ function pass()
+ {
+ $all_objects = $this->q->find('object:not(noscript object)');
+ /** @var DOMQuery $el */
+ foreach ($all_objects as $el) {
+ /** @var \DOMElement $dom_el */
+ $dom_el = $el->get(0);
+ $lineno = $this->getLineNo($dom_el);
+ $context_string = $this->getContextString($dom_el);
+
+ $actionTakenType = '';
+
+ if ($this->isVideoObject($el)) {
+ $video_url = $this->getVideoUrl($el);
+
+ if (empty($video_url)) {
+ continue;
+ }
+
+ $video_url = htmlspecialchars($video_url, ENT_QUOTES);
+ $el->after("{$video_url}");
+ $new_dom_el = $el->next()->get(0);
+
+ $actionTakenType = ActionTakenType::OBJECT_CONVERTED_TO_A;
+ } else {
+ continue;
+ }
+
+ // Remove the object and its children
+ $el->removeChildren()->remove();
+ $this->addActionTaken(new ActionTakenLine('object', $actionTakenType, $lineno, $context_string));
+ $this->context->addLineAssociation($new_dom_el, $lineno);
+
+ }
+
+ return $this->transformations;
+ }
+
+ protected function isVideoObject(DOMQuery $el)
+ {
+ $params = $el->find('param');
+ foreach ($params as $param) {
+ if ($param->attr('name') == 'movie') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ * Get the Video Url
+ *
+ * @param DOMQuery $el
+ * @return string
+ */
+ protected function getVideoUrl(DOMQuery $el)
+ {
+ $matches = [];
+ $video_url = '';
+ $params = $el->find('param');
+
+ foreach ($params as $param) {
+ if ($param->attr('name') == 'movie') {
+ return $param->attr('value');
+ }
+ }
+
+ return $video_url;
+ }
+}
diff --git a/src/Pass/ObjectVimeoTagTransformPass.php b/src/Pass/ObjectVimeoTagTransformPass.php
new file mode 100644
index 00000000..260ac463
--- /dev/null
+++ b/src/Pass/ObjectVimeoTagTransformPass.php
@@ -0,0 +1,127 @@
+ tags which don't have noscript as an ancestor to tags
+ *
+ * This is what a vimeo embed looks like:
+ *
+ *
+ * @see https://github.com/ampproject/amphtml/blob/master/extensions/amp-vimeo/amp-vimeo.md
+ *
+ */
+class ObjectVimeoTagTransformPass extends BasePass
+{
+ function pass()
+ {
+ $all_objects = $this->q->find('object:not(noscript object)');
+ /** @var DOMQuery $el */
+ foreach ($all_objects as $el) {
+ /** @var \DOMElement $dom_el */
+ $dom_el = $el->get(0);
+ $lineno = $this->getLineNo($dom_el);
+ $context_string = $this->getContextString($dom_el);
+
+ $actionTakenType = '';
+
+ if ($this->isVimeoObject($el)) {
+ $vimeo_code = $this->getVimeoCode($el);
+
+ // If we couldnt find a vimeo videoid then we abort
+ if (empty($vimeo_code)) {
+ continue;
+ }
+
+ $el->after('');
+ $new_dom_el = $el->next()->get(0);
+
+ $actionTakenType = ActionTakenType::VIMEO_OBJECT_CONVERTED;
+
+ } else {
+ continue;
+ }
+
+ // Remove the object and its children
+ $el->removeChildren()->remove();
+ $this->addActionTaken(new ActionTakenLine('object', $actionTakenType, $lineno, $context_string));
+ $this->context->addLineAssociation($new_dom_el, $lineno);
+
+ }
+
+ return $this->transformations;
+ }
+
+ protected function isVimeoObject(DOMQuery $el)
+ {
+ $params = $el->find('param');
+ foreach ($params as $param) {
+ if ($param->attr('name') == 'movie') {
+ $param_value = $param->attr('value');
+ if (preg_match('&(*UTF8)(vimeo\.com)&i', $param_value)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ * Get the Vimeo Code
+ *
+ * @param DOMQuery $el
+ * @return string
+ */
+ protected function getVimeoCode(DOMQuery $el)
+ {
+ $matches = [];
+ $vimeo_code = '';
+ $params = $el->find('param');
+
+ foreach ($params as $param) {
+ if ($param->attr('name') == 'movie') {
+ $param_value = $param->attr('value');
+
+ $pattern = '#http://(?:\w+.)?vimeo.com/(?:video/|moogaloop\.swf\?clip_id=)(\w+)#i';
+ if (preg_match($pattern, $param_value, $matches)) {
+ if (!empty($matches[1])) {
+ $vimeo_code = $matches[1];
+ return $vimeo_code;
+ }
+ }
+ }
+ }
+
+ return $vimeo_code;
+ }
+}
diff --git a/src/Pass/ObjectYouTubeTagTransformPass.php b/src/Pass/ObjectYouTubeTagTransformPass.php
new file mode 100644
index 00000000..b1de2e3f
--- /dev/null
+++ b/src/Pass/ObjectYouTubeTagTransformPass.php
@@ -0,0 +1,163 @@
+ tags which don't have noscript as an ancestor to tags
+ *
+ * This is what a youtube embed looks like:
+ *
+ *
+ * @see https://github.com/ampproject/amphtml/blob/master/extensions/amp-youtube/amp-youtube.md
+ *
+ */
+class ObjectYouTubeTagTransformPass extends BasePass
+{
+ /**
+ * A standard youtube video aspect ratio
+ * @var float
+ */
+ const DEFAULT_ASPECT_RATIO = 1.7778;
+ const DEFAULT_VIDEO_WIDTH = 560;
+ const DEFAULT_VIDEO_HEIGHT = 315;
+
+ function pass()
+ {
+ $all_objects = $this->q->find('object:not(noscript object)');
+ /** @var DOMQuery $el */
+ foreach ($all_objects as $el) {
+ /** @var \DOMElement $dom_el */
+ $dom_el = $el->get(0);
+ $lineno = $this->getLineNo($dom_el);
+ $context_string = $this->getContextString($dom_el);
+
+ $actionTakenType = '';
+
+ if ($this->isYouTubeObject($el)) {
+ $youtube_code = $this->getYouTubeCode($el);
+
+ // If we couldnt find a youtube videoid then we abort
+ if (empty($youtube_code)) {
+ continue;
+ }
+
+ $el->after("");
+
+ $new_el = $el->next();
+ $new_dom_el = $new_el->get(0);
+
+ $actionTakenType = ActionTakenType::YOUTUBE_OBJECT_CONVERTED;
+
+ $this->setStandardAttributesFrom($el, $new_el, self::DEFAULT_VIDEO_WIDTH, self::DEFAULT_VIDEO_HEIGHT, self::DEFAULT_ASPECT_RATIO);
+
+ } else {
+ continue;
+ }
+
+ // Remove the object and its children
+ $el->removeChildren()->remove();
+ $this->addActionTaken(new ActionTakenLine('object', $actionTakenType, $lineno, $context_string));
+ $this->context->addLineAssociation($new_dom_el, $lineno);
+
+ }
+
+ return $this->transformations;
+ }
+
+ protected function isYouTubeObject(DOMQuery $el)
+ {
+ $params = $el->find('param');
+ foreach ($params as $param) {
+ if ($param->attr('name') == 'movie') {
+ $param_value = $param->attr('value');
+ if (preg_match('&(*UTF8)(youtube\.com|youtu\.be)&i', $param_value)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ *
+ * Get the youtube videoid
+ *
+ * @param DOMQuery $el
+ * @return string
+ */
+ protected function getYouTubeCode(DOMQuery $el)
+ {
+ $matches = [];
+ $youtube_code = '';
+ $params = $el->find('param');
+
+ foreach ($params as $param) {
+ if ($param->attr('name') == 'movie') {
+ $param_value = $param->attr('value');
+
+ $pattern =
+ '~(?#!js YouTubeId Rev:20160125_1800)
+ # Match non-linked youtube URL in the wild. (Rev:20130823)
+ https?:// # Required scheme. Either http or https.
+ (?:[0-9A-Z-]+\.)? # Optional subdomain.
+ (?: # Group host alternatives.
+ youtu\.be/ # Either youtu.be,
+ | youtube # or youtube.com or
+ (?:-nocookie)? # youtube-nocookie.com
+ \.com # followed by
+ \S*? # Allow anything up to VIDEO_ID,
+ [^\w\s-] # but char before ID is non-ID char.
+ ) # End host alternatives.
+ ([\w-]{11}) # $1: VIDEO_ID is exactly 11 chars.
+ (?=[^\w-]|$) # Assert next char is non-ID or EOS.
+ (?! # Assert URL is not pre-linked.
+ [?=&+%\w.-]* # Allow URL (query) remainder.
+ (?: # Group pre-linked alternatives.
+ [\'"][^<>]*> # Either inside a start tag,
+ | # or inside element text contents.
+ ) # End recognized pre-linked alts.
+ ) # End negative lookahead assertion.
+ [?=&+%\w.-]* # Consume any URL (query) remainder.
+ ~ix';
+ if (preg_match($pattern, $param_value, $matches)) {
+ if (!empty($matches[1])) {
+ $youtube_code = $matches[1];
+ return $youtube_code;
+ }
+ }
+ }
+ }
+
+ return $youtube_code;
+ }
+}
diff --git a/src/Utility/ActionTakenType.php b/src/Utility/ActionTakenType.php
index 52462b5c..60b88025 100644
--- a/src/Utility/ActionTakenType.php
+++ b/src/Utility/ActionTakenType.php
@@ -52,4 +52,7 @@ class ActionTakenType
const ISSUE_RESOLVED = 'no further action required as this issue was resolved due to an earlier fix';
const AMP_IMG_FIX = 'tried to fix problems with amp-img by trying to fetch height, width from image directly and/or setting layout to responsive';
const AMP_IMG_FIX_RESPONSIVE = 'tried to fix problems with amp-img by setting layout to responsive';
+ const YOUTUBE_OBJECT_CONVERTED = 'youtube object code was converted to the amp-youtube tag.';
+ const VIMEO_OBJECT_CONVERTED = 'vimeo object code was converted to the amp-vimeo tag.';
+ const OBJECT_CONVERTED_TO_A = 'video object code was converted to a#href tag.';
}
diff --git a/tests/test-data/fragment-html/object-video-fragment.html b/tests/test-data/fragment-html/object-video-fragment.html
new file mode 100644
index 00000000..18faf3a9
--- /dev/null
+++ b/tests/test-data/fragment-html/object-video-fragment.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/tests/test-data/fragment-html/object-video-fragment.html.out b/tests/test-data/fragment-html/object-video-fragment.html.out
new file mode 100644
index 00000000..a00438d3
--- /dev/null
+++ b/tests/test-data/fragment-html/object-video-fragment.html.out
@@ -0,0 +1,26 @@
+http://video.golem.de/player/videoplayer.swf?id=2883&autoPl=false
+
+ORIGINAL HTML
+---------------
+Line 1:
+
+
+Transformations made from HTML tags to AMP custom tags
+-------------------------------------------------------
+
+