Embedded Youtube Videos with Placeholder Images

One of the requests I've had for a website I'm currently working on is to provide a placeholder image for an embedded Youtube Video.  Essentially, the client wants to display the image until someone clicks on it, then replace it with the video.  So here's how I did it with the new uTube package for Umbraco, but the same technique can be used for any web page...

With this method, I'm not trying to play the video in a separate window, or resize anything, I'm just wanting to have the video take the place of the image on the website.  This makes things a little easier, as I can render both the video and the image in separate div's and use CSS to lay one on top of the other using z-index and position elements.  In addition, I can use some fairly straight forward jquery javascript to hide one element and show the other.

Rendering a Flash Video player with an Image overlay

Here's a sample of the HTML including embedded javascript:

    <div id="mainFeature">
        <div id="mediaVideo" style="visibility: hidden">
            <div class="youTubePlayer" style="height: 433px; width: 680px;">
                <div id="ytPlayerAPI-rldN0jSBbZQ">
                    <p>
                        You need Flash version 8 and JS enabled to view the video</p>
                </div>
                <script type="text/javascript">
                    //SWF Embedd
                    var flashVars = { video_id: "rldN0jSBbZQ", playerapiid: "ytPlayerAPI-rldN0jSBbZQ", allowFullScreen: "true" }
                    var params = { allowScriptAccess: "always", wmode: "transparent", allowFullScreen: "true" };
                    var atts = { id: "ytPlayerAPI-rldN0jSBbZQ" };
                    swfobject.embedSWF("http://www.youtube.com/v/rldN0jSBbZQ?fs=1&rel=0&enablejsapi=1&version=3&playerapiid=ytPlayerAPI-rldN0jSBbZQ", "ytPlayerAPI-rldN0jSBbZQ", "680", "433", "8", null, flashVars, params, atts);
                </script>
            </div>
        </div>
        <div id="mediaImage">
            <a href="/recipes/crispy-chinese-chicken-with-sichuan-salt-pepper" title="Crispy Chinese Chicken with Sichuan Salt & Pepper">
                <img src="/media/2245/crispy_chinese_chicken_01.jpg" title="Crispy Chinese Chicken with Sichuan Salt & Pepper"
                    alt="Crispy Chinese Chicken with Sichuan Salt & Pepper" /></a></div>
        <script type="text/javascript">

            $(document).ready(function () {
                $('div#mediaImage a').click(function () {
                    $('div#mediaVideo').css('visibility', 'visible');
                    $('div#mediaImage').fadeOut(1000);
                    return false;
                });
            });
      
        </script>
    </div>

And the corresponding CSS to initially lay out the elements:

#mediaVideo, #mediaImage {
  position: absolute;
  left: 0;
  top: 0;
}

#mediaImage {
  z-index: 10;
}

Notice that in this example I'm using the SWFObject library to render the flash player. For some reason I haven't fully explored yet, if you render the flash object using object tags, the flash player is rendered on top of the mediaImage instead of obeying the CSS rules and rendering the image div on top as it should.

The result? When the user clicks on the image, it fades out and is replaced by the flash object.

Displaying embedded Youtube Videos on an iPhone/iPad

The thing about iPhone and iPad is it doesn't yet support Flash.  However, if you use the object tags approach, the device is smart enough to recognise the Youtube player and use the built-in YouTube app in it's place.  This is a pretty cool feature, but doesn't appear to work if you use the SWFObject library approach above.  Only problem is, although iPhones etc support javascript, and will honour the code above, all you see is the following message:

Rendering Youtube on iPhone with SWFObject libraryRendering a Youtube embedded video with the SWFObject on iPhone...

And using the <object> tag approach:

Rendering Youtube on iPhone with object TagsRendering a Youtube embedded video with object tags on iPhone...

Clicking on the video launches the Youtube App.  The iPad plays the video in place in the website using the Youtube app, which is pretty cool, only launching a separate window if you view it in fullscreen mode.

The code for rendering the Youtube with object tags is as follows:

            <div class="youTubePlayer" style="height: 433px; width: 680px;">
                <object width="680" height="433">
                    <param name="movie" value="http://www.youtube.com/v/rldN0jSBbZQ?fs=1&rel=0" />
                    <param name="allowFullScreen" value="true" />
                    <param name="allowscriptaccess" value="always" />
                    <embed src="http://www.youtube.com/v/rldN0jSBbZQ?fs=1&rel=0" type="application/x-shockwave-flash"
                        allowscriptaccess="always" allowfullscreen="true" width="680" height="433" /></object></div>

The best of both worlds: Supporting iPhone and rendering placeholder Images...

It's a compromise, but since we can't get both apple devices and standard browsers to render the same thing, we need to use the HTTP_USER_AGENT string to conditionally render the different approaches.

Umbraco and the uTube plugin...

For those of us utilising the excellent new uTube plugin with Umbraco, the following XSLT code should do the trick - note that you'll have to render the Chrome player if you want Full screen mode, as the chromeless player doesn't support it.  See my earlier post about this: Enabling Alternate Media with the uTube Umbraco Package

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
  <!ENTITY nbsp " ">
]>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library"
  xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon"
  xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes"
  xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath"
  xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions"
  xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings"
  xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:yt="http://gdata.youtube.com/schemas/2007"
  xmlns:media="http://search.yahoo.com/mrss/"
  xmlns:uTube.XSLT="urn:uTube.XSLT"
  exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath
  Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets atom yt media uTube.XSLT"> <xsl:output method="xml" omit-xml-declaration="yes"/> <xsl:param name="currentPage"/> <xsl:template match="/"> <!-- YouTube URL or VideoID --> <xsl:variable name="uTubeVideo" select="/macro/uTubeVideo" /> <xsl:variable name="allowFullScreen" select="/macro/allowFullScreen" /> <xsl:variable name="allowRelatedVideos" select="/macro/allowRelatedVideos" /> <xsl:variable name="jsPlayerApiId" select="/macro/jsPlayerApiId" /> <!-- Don't do anything unless we have a value in uTubeVideo --> <xsl:if test="/macro/uTubeVideo"> <xsl:variable name="uTubeVideoID" select="uTube.XSLT:GetVideoId($uTubeVideo)" /> <xsl:variable name="uTubeXML" select="uTube.XSLT:GetVideoData($uTubeVideoID, 60)"/> <xsl:variable name="uTubeRatio" select="uTube.XSLT:GetAspectRatio($uTubeVideoID)"/> <!-- Video Width --> <xsl:variable name="uTubeWidth"> <xsl:choose> <!-- If the Width is not set, then check if Height is available --> <xsl:when test="not(/macro/uTubeWidth) and /macro/uTubeHeight"> <!-- Use the Height to get the Width --> <xsl:value-of select="uTube.XSLT:GetVideoWidth(/macro/uTubeHeight, $uTubeRatio)" /> </xsl:when> <!-- If the Width is set, use it! --> <xsl:when test="/macro/uTubeWidth"> <xsl:value-of select="/macro/uTubeWidth" /> </xsl:when> <!-- Otherwise fall back on a default value --> <xsl:otherwise> <xsl:value-of select="number(480)" /> </xsl:otherwise> </xsl:choose> </xsl:variable> <!-- Video Height --> <xsl:variable name="uTubeHeight"> <xsl:choose> <!-- If the Height is not set --> <xsl:when test="not(/macro/uTubeHeight)"> <!-- Then use the Width to get the Height --> <xsl:value-of select="uTube.XSLT:GetVideoHeight($uTubeWidth, $uTubeRatio)" /> </xsl:when> <xsl:otherwise> <!-- Otherwise use the user-defined value --> <xsl:value-of select="/macro/uTubeHeight" /> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="allowFullScreenText"> <xsl:choose> <xsl:when test="$allowFullScreen = 1">true</xsl:when> <xsl:otherwise>false</xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="uTubeRel"> <xsl:choose> <xsl:when test="$allowRelatedVideos = 1">&rel=1</xsl:when> <xsl:otherwise>&rel=0</xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="enableJSApi"> <xsl:if test="$jsPlayerApiId != ''">&enablejsapi=1&playerapiid=<xsl:value-of select="$jsPlayerApiId" /></xsl:if> </xsl:variable> <div class="youTubePlayer" style="height:{$uTubeHeight}px; width:{$uTubeWidth}px;"> <xsl:choose> <xsl:when test="uTube.XSLT:AllowEmbed($uTubeVideoID) = true()"> <xsl:choose> <xsl:when test="contains(umbraco.library:RequestServerVariables('HTTP_USER_AGENT'), 'iPad') or contains(umbraco.library:RequestServerVariables('HTTP_USER_AGENT'), 'iPhone')"> <object width="{$uTubeWidth}" height="{$uTubeHeight}"> <param name="movie"
                   value="http://www.youtube.com/v/{$uTubeVideoID}?fs={$allowFullScreen}{$uTubeRel}{$enableJSApi}"></param> <param name="allowFullScreen" value="{$allowFullScreenText}"></param> <param name="allowscriptaccess" value="always"></param> <embed src="http://www.youtube.com/v/{$uTubeVideoID}?fs={$allowFullScreen}{$uTubeRel}{$enableJSApi}" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="{$allowFullScreenText}" width="{$uTubeWidth}" height="{$uTubeHeight}"></embed> </object> </xsl:when> <xsl:otherwise> <!-- Video is allowed to be embedded --> <div id="{concat('ytPlayerAPI-',$uTubeVideoID)}"> <p>You need Flash version 8 and JS enabled to view the video</p> </div> <!-- SWFObject call to Embed Chromless player --> <script type="text/javascript"> //SWF Embedd var flashVars = {video_id : "<xsl:value-of select="$uTubeVideoID"/>",
                                            playerapiid: "<xsl:value-of select="concat('ytPlayerAPI-',$uTubeVideoID)" />",
                                            allowFullScreen: "<xsl:value-of select="$allowFullScreenText"/>" } var params = {allowScriptAccess: "always", wmode: "transparent",
                                            allowFullScreen: "<xsl:value-of select="$allowFullScreenText"/>" }; var atts = { id: "<xsl:value-of select="concat('ytPlayerAPI-',$uTubeVideoID)" />" }; swfobject.embedSWF("http://www.youtube.com/v/<xsl:value-of
                                                    select="$uTubeVideoID" />?fs=<xsl:value-of
                                                    select="$allowFullScreen" /><xsl:value-of
                                                    select="$uTubeRel" />&enablejsapi=1&version=3&playerapiid=<xsl:value-of
                                                    select="concat('ytPlayerAPI-',$uTubeVideoID)" />","<xsl:value-of
                                                    select="concat('ytPlayerAPI-',$uTubeVideoID)" />", "<xsl:value-of
                                                    select="$uTubeWidth" />", "<xsl:value-of
                                                    select="$uTubeHeight"/>", "8", null, flashVars, params, atts); </script> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <!-- Video Not Allowed to be embedded --> <p>This video does not allow it to be embedded.</p> </xsl:otherwise> </xsl:choose> </div> </xsl:if> </xsl:template> </xsl:stylesheet>

Any questions, comments or suggestions, feel free to leave a comment...

Enjoy!

1 comment for “Embedded Youtube Videos with Placeholder Images”

  1. Posted Friday, December 06, 2013 at 2:29:21 PM

    The reason for this is that the code assumes that all Media items in the selected folder are Images, and doesn't do anything to filter out other items.

Post a comment