Go to main content

Textpattern CMS support forum

You are not logged in. Register | Login | Help

#13 2010-12-03 15:32:29

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

ok… you are awesome, it works perfectly now!! I edited the code in my previous post to reflect this change.

Offline

#14 2010-12-03 16:07:50

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Glad it’s working. In your previous post you also need to change:

$theurl = $matches[1];

to

$theurl = $matches[2];

and

$theid = $matches[1];

to

$theid = $matches[2];

FYI, when you give preg_match() the optional third argument ($matches in this case) it stores an array containing the complete match and all sub-matches, which are the parts of the pattern enclosed by parentheses. $matches[1] is the first sub-pattern, i.e. the part matching ^([\s\S]*?).


Code is topiary

Offline

#15 2010-12-03 16:46:07

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Thanks for catching that too! I don’t know how I did that… I had it right in the actual code that I’ve used for testing (which explains why it is working!), but somehow pasted it wrong here in the forum. Good eye!

Offline

#16 2010-12-03 19:14:59

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Having looked at this code several times, I can’t help but make a few more comments:

  • The resize() operation is best done after you’ve decided which image to use, so that you only do it once. Not a big deal as resize() appears to have a cache, but as a general point you don’t want to run a big function more than necessary.
  • Best not to include non-core functions (resize()) without giving them a distinct prefix, as with plugins.
  • The first matching pattern assumes any img tag to be a flickr embed. Pretty big assumption.
  • If you know you are in article context you can use permlinkurl($GLOBALS['thisarticle']) to generate the link URL. It would automatically use the permanent link mode set in site prefs, and would allow you to delete several lines of code. For that matter, you could use permlink() function to generate the anchor tag as well, if you don’t mind rel="bookmark" as a tag attribute. Again, you can wait to do this after you’ve decided which image to use.
  • You can get rid of the // Edit: see below comments I added :)

Code is topiary

Offline

#17 2010-12-03 21:39:15

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

jsoo thanks for the tips and suggestions. I’m shaky with PHP, but I think I’ve managed to clean it up a bit while keeping it working.

<txp:php>
  if (preg_match('@^([\s\S]*?)<img src=([^<]+)/>@',$thisarticle['body'], $matches)) 
  {
	$first_bodyimg = strlen($matches[1]);
	$bodyimg = explode(" ",$matches[2]);
}
if (preg_match('#^([\s\S]*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s', $thisarticle['body'], $matches))
  {
	$first_youtube = strlen($matches[1]);
	$youtubeid = $matches[2];
}
if (isset($bodimg) and isset($youtube))
	echo $first_bodimg < $first_youtube ? $bodyimg : $youtubeid;
elseif (isset($bodyimg)) {
	$imgurl = trim($bodyimg[0],"\"");
	$thumbsized = resize("$imgurl",array("w"=>200));
	$arturl = permlinkurl($GLOBALS['thisarticle']);
	echo "<a href=\"".$arturl."\" /><img src=\".".$thumbsized."\" /></a>";
}
elseif (isset($youtubeid)) {
	$thumbsized = resize('http://i.ytimg.com/vi/'.$youtubeid.'/0.jpg',array('w'=>200));
	$arturl = permlinkurl($GLOBALS['thisarticle']);
	echo "<a href=\"".$arturl."\" /><img src=\".".$thumbsized."\" /></a>";
}
</txp:php>

I can’t figure out how to use the permlink() function, but permlinkurl($GLOBALS['thisarticle']) is working fine.

Re: resize(): should I add a prefix like img_resize()? I’m really naive when it comes to plugin/core protocol. I guess I would need to add the prefix to the native resize code (it is in a separate file on the server).

And finally, a quick question about the s that comes after the # sign in the preg_match line for finding YouTube videos. I removed the s at some point while playing around with your code. With or without the s, everything seems to work fine. Does it play an important role? I went ahead and put it back in the code above just to be safe.

Again, thanks so much for all of your help and suggestions!!

Offline

#18 2010-12-04 01:16:55

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Just about. However, your latest revision won’t work correctly if the article contains both types of content.

Here’s what I had in mind:

<txp:php> 

// Regex patterns to search for embedded flickr and youtube content
	$img_pattern = '#^(.*?)<img src=(\'|")(.+?)\2#s';
	$youtube_pattern = '#^(.*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s';

// Check for embedded content; if found calculate position from start of article
	$first_bodyimg = preg_match($img_pattern, $thisarticle['body'], $img_match) ? 
		strlen($img_match[1]) : null;
	$first_youtube = preg_match($youtube_pattern, $thisarticle['body'], $youtube_match) ?
		strlen($youtube_match[1]) : null;

// Resize and output thumbnail for first embedded content
	if ( $first_youtube and ( is_null($first_bodyimg) or $first_youtube < $first_bodyimg ) )
		echo permlink(array(), resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200)));
	elseif ( $first_bodyimg and ( is_null($first_youtube) or $first_bodyimg < $first_youtube ) )
		echo permlink(array(), resize($img_match[3], array("w"=>200)));

</txp:php>

I’ve tweaked the flickr regex pattern so it uses the same delimiters (the # characters) as the youtube pattern, and I’ve added back the s after both patterns — this is a regex option that allows the . in the pattern to also match line returns (so I can do away with [\s\S]). I added an extra subpattern (the (\'|")) to the flickr pattern so that $youtube_match[3] will capture just the image URL, so I can eliminate some extra steps. FYI, learning at least basic regex is quite handy even for non-coders. An increasing number of apps support regex in find and replace dialogs, and you can do some real power editing with it.

There are more compact ways to format this code, but this version is clearer to read and maintain.

The resize() function is OK as named for now, because Txp does not have a function with the same name. Best practice is to use a distinct prefix for non-Txp functions to prevent that sort of conflict, so to be on the safe side you could rename the function photonomad_resize() (both in the function definition and in the function calls).


Code is topiary

Offline

#19 2010-12-04 18:52:34

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Wow, this is quite a revision! I had completely missed the problem in my version. Thanks for pointing that out! It reared its head when a youtube video came before an image in an article.

Ok, so there is only one issue in your new version that I can’t fix. The resize script only produces a url, not the full html img tag. I’ve messed around with it and can’t figure out how/where in the script to work the image tag in without adding a bunch more lines and eliminating the permlink() function.

Last edited by photonomad (2010-12-04 19:53:23)

Offline

#20 2010-12-04 19:52:44

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

I take that back, I got it working with the img tag. My first attempts involved some careless typos!

I changed this:

echo permlink(array(), resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200)));

to this:

echo permlink(array(), "<img src=\"".resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200))."\" />");

and this:

echo permlink(array(), resize($img_match[3], array("w"=>200)));

to this:

echo permlink(array(), "<img src=\"".resize($img_match[3], array("w"=>200))."\" />");

Thanks again!!

Offline

#21 2010-12-04 20:25:20

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Good job. I was just previewing this post when you posted your latest, so here’s another way the code could be arranged:

// Check article body for embedded flickr and/or youtube content
	$img_pattern = '#^(.*)<img src=(\'|")(.+flickr\.com.+)\2#sU';
	$youtube_pattern = '#^(.*)<object.+youtube\.com/v/([\w-]+).+</object>#sU';

// Check for embedded content; if found calculate position from start of article
	$first_bodyimg = preg_match($img_pattern, $thisarticle['body'], $img_match) ? 
		strlen($img_match[1]) : null;
	$first_youtube = preg_match($youtube_pattern, $thisarticle['body'], $youtube_match) ?
		strlen($youtube_match[1]) : null;

// Find first instance and resize it
	$img_src = null;
	if ( $first_youtube and ( is_null($first_bodyimg) or $first_youtube < $first_bodyimg ) )
		$img_src = resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200));
	elseif ( $first_bodyimg and ( is_null($first_youtube) or $first_bodyimg < $first_youtube ) )
		$img_src = resize($img_match[3], array("w"=>200));

// If we have an image src, output the image as the contents of a link to the current article
	if ( $img_src )
		echo permlink(array('class'=>'article-thumb'), '<img src="'.$img_src.'" alt="" />');

Among other things this avoids repeating the permlink() code, including the concatenated strings for building the img tag. Not a big deal, but if you wanted to add, say, a title attribute to the img tag, there’s only one place you need to edit.

Note that I’ve added a class attribute to permlink(). When calling a Txp tag directly as a PHP function, the first argument is always the tag attribute array.

I also made a few tweaks to the regex patterns. I added the U option to both patterns. This makes the * and + quantifiers non-greedy by default, so I can do away with the ? modifiers. I added flickr\.com to the flickr pattern to only match flickr images. I removed the http./ from the youtube pattern because it doesn’t really add anything useful. I changed the [A-Za-z0-9\-_] character class to [\w-], which is identical. I escaped the literal dot characters (youtube\.com), because an unescaped dot in regex matches any character.


Code is topiary

Offline

#22 2011-04-07 20:22:00

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Hello! I have another php/regex question. It appears that YouTube recently changed the format of the code for embedding videos. Instead of an <object>, they are now using an <iframe> and the video id comes after embed/ in the src.

Example:

<iframe title="YouTube video player" width="480" height="390" src="http://www.youtube.com/embed/9JA0QVP3JwQ" frameborder="0" allowfullscreen></iframe>

I need help understanding how to modify the script so that it will look for the first object or iframe with youtube code.

Also, jsoo, I decided that I do not want to limit the script for just Flickr images. I tried to modify your changes (so that it would find any img tags) in the revised code (in your post above) and I wasn’t able to get it to work correctly.

I have been using the following:

<txp:php> 
// Regex patterns to search for embedded image and youtube content
	$img_pattern = '#^(.*?)<img src=(\'|")(.+?)\2#s';
	$youtube_pattern = '#^(.*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s';

// Check for embedded content; if found calculate position from start of article $first_bodyimg = preg_match($img_pattern, $thisarticle[‘body’], $img_match) ? strlen($img_match1) : null; $first_youtube = preg_match($youtube_pattern, $thisarticle[‘body’], $youtube_match) ? strlen($youtube_match1) : null;

// Resize and output thumbnail for first embedded content if ( $first_youtube and ( is_null($first_bodyimg) or $first_youtube < $first_bodyimg ) ) echo permlink(array(), “<img src=\”.”.resize(‘http://i.ytimg.com/vi/’.$youtube_match2.’/0.jpg’,array(‘w’=>150)).”\” />”); elseif ( $first_bodyimg and ( is_null($first_youtube) or $first_bodyimg < $first_youtube ) ) echo permlink(array(), “<img src=\”.”.resize($img_match3, array(“w”=>150)).”\” />”);
</txp:php>

Offline

#23 2011-04-08 13:46:49

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

photonomad wrote:

$img_pattern = '#^(.*?)<img src=(\'|")(.+?)\2#s';

Should still be OK for matching the first img tag. This might improve it, in case of tags in which src is not the first attribute:

$img_pattern = '#^(.*?)<img\s[^>]*src=(\'|")(.+?)\2#s';

photonomad wrote:

$youtube_pattern = '#^(.*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s';

Untested, but this might work if you need to test for either object or iframe:

$youtube_pattern = '#^(.*?)<(object|iframe)[^>]+>.+?http://www.youtube.com/(?:v|embed)/([A-Za-z0-9\-_]+).+?</\2>#s';

With this latter pattern there is an extra matching subpattern (the (object|iframe) subpattern), so you would need to change this in the $youtube_match index for the ID (i.e., use $youtube_match[3]).


Code is topiary

Offline

#24 2011-04-09 19:32:11

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Hi jsoo, Thanks for your help!

I’ve tested it and the new image pattern works great and finds the src no matter what order it appears in the <img> tag!

The youtube regex pattern works fine too, but I’m getting stuck with the $youtube_match index. You are correct, $youtube_match[2] does not work. The resize script runs, but doesn’t return an actual image url.

When I switch $youtube_match[2] to $youtube_match[3], it works, but does not return the first occurrence. If there is only one youtube (object and/or iframe) in the article body, then no image is returned. When I put two youtube (objects and/or iframes) in the same article, the second video’s image is returned. If I put an image in between two youtubes, the second youtube is returned and the still image is ignored. However, if there is a youtube first and then an image and no other youtubes, then the still image is returned. I am stumped as to how to fix it. Any ideas?

Thanks so much!

Offline

Board footer

Powered by FluxBB