Author: boutell
Date: 2009-05-12 21:41:05 +0200 (Tue, 12 May 2009)
New Revision: 18190

Added:
   plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoEmbedForm.class.php
   plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoYoutubeForm.class.php
Modified:
   plugins/pkMediaPlugin/trunk/README
   plugins/pkMediaPlugin/trunk/UPGRADE
   plugins/pkMediaPlugin/trunk/config/doctrine/schema.yml
   plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoForm.class.php
   plugins/pkMediaPlugin/trunk/lib/model/doctrine/PluginpkMediaItem.class.php
   plugins/pkMediaPlugin/trunk/lib/pkMediaTools.php
   plugins/pkMediaPlugin/trunk/modules/pkMedia/actions/actions.class.php
   plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/editVideoSuccess.php
   plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/newVideoSuccess.php
Log:
Support for other video hosts via embed codes. See the README and UPGRADE files.
You will need a new field in your schema if you are upgrading (see UPGRADE).



Modified: plugins/pkMediaPlugin/trunk/README
===================================================================
--- plugins/pkMediaPlugin/trunk/README  2009-05-12 18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/README  2009-05-12 19:41:05 UTC (rev 18190)
@@ -198,11 +198,29 @@
 You can also edit and delete items in context using the edit
 and delete buttons. 
 
-Since videos are hosted by YouTube and not directly hosted by the
+Since videos are hosted by YouTube (or other services when
+embed_codes is enabled) and not directly hosted by the
 plugin, adding video works a little bit differently. When you add
 a video you'll be invited to search YouTube to locate that video.
 If you prefer you can also paste in the YouTube URL of the video directly.
 
+== The Embed Code Option ==
+
+If `app_pkMedia_embed_codes` is enabled via `app.yml` you can also
+paste in embed codes for other sites using a third option that appears
+when adding videos.
+
+The embed feature does filter
+irrelevant tags and text, but does not attempt to remove all
+attributes, since so many are necessary when embedding. That means
+that users could paste in unwanted JavaScript handlers or style
+attributes. So you may or may not wish to enable it. By default 
+it is turned off.
+
+The embed feature requires you to supply a thumbnail image manually
+at the same time you supply the embed code. This is not necessary
+when using a YouTube URL. When you can, use YouTube.
+
 == The Select Action: Selecting Media ==
 
 Many web applications will want to embed images and video that

Modified: plugins/pkMediaPlugin/trunk/UPGRADE
===================================================================
--- plugins/pkMediaPlugin/trunk/UPGRADE 2009-05-12 18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/UPGRADE 2009-05-12 19:41:05 UTC (rev 18190)
@@ -1,3 +1,9 @@
+20090510: you'll need a new field in your database:
+
+ALTER TABLE pk_media_item ADD COLUMN embed varchar(1000);
+
+* * *
+
 In version 0.5 the media repository moved from web/media-items to 
 web/uploads/media_items for consistency with other writable folders
 in web space. Version 0.5 comes with a different set of rewrite rules

Modified: plugins/pkMediaPlugin/trunk/config/doctrine/schema.yml
===================================================================
--- plugins/pkMediaPlugin/trunk/config/doctrine/schema.yml      2009-05-12 
18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/config/doctrine/schema.yml      2009-05-12 
19:41:05 UTC (rev 18190)
@@ -39,6 +39,21 @@
       type: integer(4)
     height:
       type: integer(4)
+
+    # If this field is non-null, it contains HTML embed/object code to
+    # be used without alteration (except for replacing _WIDTH_ and _HEIGHT_)
+    # when embedding the video. This is used to allow embedding of 
+    # video hosted on services whose APIs are not directly supported
+    # by pkMediaPlugin (i.e. anything except YouTube, as of this writing).
+    # Note that this can actually be used to embed any scalable 
+    # applet (Flash, Java, etc) supported by embed/object/applet/param tags
+    # although our intention is simply to support black-box Flash players.
+    # 
+    # The user is required to manually supply a thumbnail when 
+    # embedding a video in this way.
+    embed:
+      type: string(1000)
+
     title:
       type: string(200)
       notnull: true

Added: plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoEmbedForm.class.php
===================================================================
--- plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoEmbedForm.class.php        
                        (rev 0)
+++ plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoEmbedForm.class.php        
2009-05-12 19:41:05 UTC (rev 18190)
@@ -0,0 +1,68 @@
+<?php
+
+class pkMediaVideoEmbedForm extends pkMediaVideoForm
+{
+  public function configure()
+  {
+    parent::configure();
+    unset($this['service_url']);
+    // TODO: custom validator looking for appropriate tags only
+    $this->setValidator('embed',
+      new sfValidatorCallback(
+        array('required' => true, 'callback' => 
'pkMediaVideoEmbedForm::validateEmbed'),
+        array('required' => "Not a valid embed code", 'invalid' => "Not a 
valid embed code")));
+    $this->setWidget('thumbnail',
+      new pkWidgetFormInputFilePersistent());
+    $this->setValidator('thumbnail',
+      new pkValidatorFilePersistent(array('mime_types' =>
+        array('image/jpeg', 'image/png', 'image/gif'),
+        "required" => (!$this->getObject()->getId()))));
+  }
+  static public function validateEmbed($validator, $value, $arguments)
+  {
+    // Don't let this become a way to embed arbitrary HTML
+    $value = trim(strip_tags($value, "<embed><object><param><applet>"));
+    // Kill any text outside of tags
+    if (preg_match_all("/<.*?>/", $value, $matches))
+    {
+      $value = implode("", $matches[0]);
+    }
+    else
+    {
+      $value = '';
+    }
+    if (!strlen($value))
+    {
+      throw new sfValidatorError($validator, 
$validator->getMessage('invalid'), $arguments);
+    }
+    return $value;
+  }
+  public function updateObject($values = null)
+  {
+    $object = parent::updateObject($values);
+    // If possible, get the width and height from the embed tag rather
+    // than from the thumbnail the user uploaded, which is likely to be
+    // a mismatch quite often. If the embed tag has percentages we don't
+    // want to match, just let the thumbnail dimensions win
+    if (preg_match("/width\s*=\s*([\"'])(\d+)\\1/i", $object->embed, $matches))
+    {
+      $object->width = $matches[2];
+    }
+    if (preg_match("/height\s*=\s*([\"'])(\d+)\\1/i", $object->embed, 
$matches))
+    {
+      $object->height = $matches[2];
+    }
+    // Put placeholders in the embed/applet/object tags
+    $object->embed = preg_replace(
+      array(
+        "/width\s*=\s*([\"'])\d+%?\\1/i",
+        "/height\s*=\s*([\"'])\d+%?\\1/i",
+        "/alt\s*\s*([\"']).*?\\1/i"),
+      array(
+        "width=\"_WIDTH_\"",
+        "height=\"_HEIGHT_\"",
+        "alt=\"_TITLE_\""),
+      $object->embed);
+    return $object;
+  }
+}

Modified: plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoForm.class.php
===================================================================
--- plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoForm.class.php     
2009-05-12 18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoForm.class.php     
2009-05-12 19:41:05 UTC (rev 18190)
@@ -5,10 +5,23 @@
   public function configure()
   {
     unset($this['id'], $this['type'], $this['slug'], $this['width'], 
$this['height'], $this['format']);
-    $this->setValidator('service_url',
-      new sfValidatorUrl(
-        array('required' => true, 'trim' => true),
-        array('required' => "Not a valid YouTube URL")));
+    $object = $this->getObject();
+//    if ($object->embed)
+//    {
+//      unset($this['service_url']);
+//      $this->setValidator('embed',
+//        new sfValidatorText(
+//          array('required' => true, 'trim' => true),
+//          array('required' => "Not a valid embed code")));
+//    }
+//    else
+//    {
+//      unset($this['embed']);
+      $this->setValidator('service_url',
+        new sfValidatorUrl(
+          array('required' => true, 'trim' => true),
+          array('required' => "Not a valid YouTube URL")));
+//    }
   }
   public function updateObject($values = null)
   {

Added: plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoYoutubeForm.class.php
===================================================================
--- plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoYoutubeForm.class.php      
                        (rev 0)
+++ plugins/pkMediaPlugin/trunk/lib/form/pkMediaVideoYoutubeForm.class.php      
2009-05-12 19:41:05 UTC (rev 18190)
@@ -0,0 +1,14 @@
+<?php
+
+class pkMediaVideoYoutubeForm extends pkMediaVideoForm
+{
+  public function configure()
+  {
+    parent::configure();
+    unset($this['embed']);
+    $this->setValidator('service_url',
+      new sfValidatorUrl(
+        array('required' => true, 'trim' => true),
+        array('required' => "Not a valid YouTube URL")));
+  }
+}

Modified: 
plugins/pkMediaPlugin/trunk/lib/model/doctrine/PluginpkMediaItem.class.php
===================================================================
--- plugins/pkMediaPlugin/trunk/lib/model/doctrine/PluginpkMediaItem.class.php  
2009-05-12 18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/lib/model/doctrine/PluginpkMediaItem.class.php  
2009-05-12 19:41:05 UTC (rev 18190)
@@ -116,8 +116,8 @@
   {
     if ($height === false)
     {
-      // Scale the height
-      $height = floor(($width * $this->width / $this->height) + 0.5); 
+      // Scale the height. I had this backwards
+      $height = floor(($width * $this->height / $this->width) + 0.5); 
     }
     // Accessible alt title
     $title = htmlspecialchars($this->getTitle());
@@ -125,6 +125,13 @@
     // Think about whether that's possible.
     if ($this->getType() === 'video')
     {
+      if ($this->embed)
+      {
+        // Solution for non-YouTube videos based on a manually
+        // provided thumbnail and embed code
+        return str_replace(array('_TITLE_', '_WIDTH_', '_HEIGHT_'),
+          array($title, $width, $height), $this->embed);
+      }
       // TODO: less YouTube-specific
       $serviceUrl = $this->getServiceUrl();
       $embeddedUrl = $this->youtubeUrlToEmbeddedUrl($serviceUrl);

Modified: plugins/pkMediaPlugin/trunk/lib/pkMediaTools.php
===================================================================
--- plugins/pkMediaPlugin/trunk/lib/pkMediaTools.php    2009-05-12 18:40:55 UTC 
(rev 18189)
+++ plugins/pkMediaPlugin/trunk/lib/pkMediaTools.php    2009-05-12 19:41:05 UTC 
(rev 18190)
@@ -150,6 +150,7 @@
     'selected_resizeType' => 'c',
     'show_width' => 720,
     'show_height' => 720,
+    'embed_codes' => false,
     'apikeys' => array()
   );
   static public function getOption($name)

Modified: plugins/pkMediaPlugin/trunk/modules/pkMedia/actions/actions.class.php
===================================================================
--- plugins/pkMediaPlugin/trunk/modules/pkMedia/actions/actions.class.php       
2009-05-12 18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/modules/pkMedia/actions/actions.class.php       
2009-05-12 19:41:05 UTC (rev 18190)
@@ -355,11 +355,21 @@
       $this->forward404Unless($item->userHasPrivilege('edit'));
     }
     $this->item = $item;
-    $this->form = new pkMediaVideoForm($item);
-    if ($request->hasParameter('pk_media_item[]'))
+    $subclass = 'pkMediaVideoYoutubeForm';
+    $embed = false;
+    $parameters = $request->getParameter('pk_media_item');
+    if (pkMediaTools::getOption('embed_codes') && 
+      (($item && strlen($item->embed)) || (isset($parameters['embed']))))
     {
-      $parameters = $request->getParameter('pk_media_item[]');
-      $this->form->bind($parameters);
+      $subclass = 'pkMediaVideoEmbedForm';
+      $embed = true;
+    }
+    $this->form = new $subclass($item);
+    if ($parameters)
+    {
+      $files = $request->getFiles('pk_media_item');
+      $this->form->bind($parameters, $files);
+
       do
       {
         // first_pass forces the user to interact with the form
@@ -373,68 +383,93 @@
         {
           break;
         }
-        $url = $this->form->getValue("service_url");
-        // TODO: migrate this into the model and a 
-        // YouTube-specific support class
-        if (!preg_match("/youtube.com.*\?.*v=([\w\-\+]+)/", 
-          $url, $matches))
+        // TODO: this is pretty awful factoring, I should have separate actions
+        // and migrate more of this code into the model layer
+        if ($embed)
         {
-          $this->serviceError = true;
-          break;
+          $embed = $this->form->getValue("embed");
+          $thumbnail = $this->form->getValue('thumbnail');
+          // The base implementation for saving files gets confused when 
+          // $file is not set, a situation that our code tolerates as useful 
+          // because if you're updating a record containing an image you 
+          // often don't need to submit a new one.
+          unset($this->form['thumbnail']);
+          $object = $this->form->getObject();
+          if ($thumbnail)
+          {
+            $object->preSaveImage($thumbnail->getTempName());
+          }
+          $this->form->save();
+          if ($thumbnail)
+          {
+            $object->saveImage($thumbnail->getTempName());                     
+          }
         }
-        // YouTube thumbnails are always JPEG
-        $format = 'jpg';
-        $videoid = $matches[1];
-        $feed = "http://gdata.youtube.com/feeds/api/videos/$videoid";;
-        $entry = simplexml_load_file($feed);
-        // get nodes in media: namespace for media information
-        $media = $entry->children('http://search.yahoo.com/mrss/');
-            
-        // get a more canonical video player URL
-        $attrs = $media->group->player->attributes();
-        $canonicalUrl = $attrs['url']; 
-        // get biggest video thumbnail
-        foreach ($media->group->thumbnail as $thumbnail)
+        else
         {
-          $attrs = $thumbnail->attributes();
-          if ((!isset($widest)) || (($attrs['width']  + 0) > 
-            ($widest['width'] + 0)))
+          $url = $this->form->getValue("service_url");
+          // TODO: migrate this into the model and a 
+          // YouTube-specific support class
+          if (!preg_match("/youtube.com.*\?.*v=([\w\-\+]+)/", 
+            $url, $matches))
           {
-            $widest = $attrs;
+            $this->serviceError = true;
+            break;
           }
-        }
-        // The YouTube API doesn't report the original width and height of
-        // the video stream, so we use the largest thumbnail, which in practice
-        // is the same thing on YouTube.
-        if (isset($widest))
-        {
-          $thumbnail = $widest['url']; 
-          // Turn them into actual numbers instead of weird XML wrapper things
-          $width = $widest['width'] + 0;
-          $height = $widest['height'] + 0;
-        }
-        if (!isset($thumbnail))
-        {
-          $this->serviceError = true;
-          break;
-        }
-        // Grab a local copy of the thumbnail, and get the pain
-        // over with all at once in a predictable way if 
-        // the service provider fails to give it to us.
+          // YouTube thumbnails are always JPEG
+          $format = 'jpg';
+          $videoid = $matches[1];
+          $feed = "http://gdata.youtube.com/feeds/api/videos/$videoid";;
+          $entry = simplexml_load_file($feed);
+          // get nodes in media: namespace for media information
+          $media = $entry->children('http://search.yahoo.com/mrss/');
+            
+          // get a more canonical video player URL
+          $attrs = $media->group->player->attributes();
+          $canonicalUrl = $attrs['url']; 
+          // get biggest video thumbnail
+          foreach ($media->group->thumbnail as $thumbnail)
+          {
+            $attrs = $thumbnail->attributes();
+            if ((!isset($widest)) || (($attrs['width']  + 0) > 
+              ($widest['width'] + 0)))
+            {
+              $widest = $attrs;
+            }
+          }
+          // The YouTube API doesn't report the original width and height of
+          // the video stream, so we use the largest thumbnail, which in 
practice
+          // is the same thing on YouTube.
+          if (isset($widest))
+          {
+            $thumbnail = $widest['url']; 
+            // Turn them into actual numbers instead of weird XML wrapper 
things
+            $width = $widest['width'] + 0;
+            $height = $widest['height'] + 0;
+          }
+          if (!isset($thumbnail))
+          {
+            $this->serviceError = true;
+            break;
+          }
+          // Grab a local copy of the thumbnail, and get the pain
+          // over with all at once in a predictable way if 
+          // the service provider fails to give it to us.
        
-        $thumbnailCopy = pkFiles::getTemporaryFilename();
-        if (!copy($thumbnail, $thumbnailCopy))
-        {
-          $this->serviceError = true;
-          break;
+          $thumbnailCopy = pkFiles::getTemporaryFilename();
+          if (!copy($thumbnail, $thumbnailCopy))
+          {
+            $this->serviceError = true;
+            break;
+          }
+          $object = $this->form->getObject();
+          $new = !$object->getId();
+          $object->preSaveImage($thumbnailCopy);
+          $object->setServiceUrl($url);
+          $this->form->save();
+          $object->saveImage($thumbnailCopy);
+          unlink($thumbnailCopy);
         }
-        $object = $this->form->getObject();
-        $new = !$object->getId();
-        $object->preSaveImage($thumbnailCopy);
-        $object->setServiceUrl($url);
-        $this->form->save();
-        $object->saveImage($thumbnailCopy);
-        unlink($thumbnailCopy);
         return $this->redirect("pkMedia/resumeWithPage");
       } while (false);
     }

Modified: 
plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/editVideoSuccess.php
===================================================================
--- plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/editVideoSuccess.php  
2009-05-12 18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/editVideoSuccess.php  
2009-05-12 19:41:05 UTC (rev 18190)
@@ -36,9 +36,23 @@
           <?php endif ?>
           <?php echo $form['title']->render() ?>
         </div>
-        <div class="form-row service-url">
-          <?php echo $form['service_url']->renderRow() ?>
-        </div>
+        <?php if (isset($form['service_url'])): ?>
+          <div class="form-row service-url">
+            <?php echo $form['service_url']->renderRow() ?>
+          </div>
+        <?php endif ?>
+        <?php if (isset($form['embed'])): ?>
+          <div class="form-row embed">
+            <?php echo $form['embed']->renderRow() ?>
+          </div>
+          <div class="form-row thumbnail">
+            <?php echo $form['thumbnail']->renderLabel() ?>
+            <?php if (!$sf_params->get('first_pass')): ?>
+              <?php echo $form['thumbnail']->renderError() ?>
+            <?php endif ?>
+            <?php echo $form['thumbnail']->render() ?>
+          </div>
+        <?php endif ?>
         <div class="form-row description">
           <?php echo $form['description']->renderLabel() ?>
           <?php echo $form['description']->renderError() ?>

Modified: 
plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/newVideoSuccess.php
===================================================================
--- plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/newVideoSuccess.php   
2009-05-12 18:40:55 UTC (rev 18189)
+++ plugins/pkMediaPlugin/trunk/modules/pkMedia/templates/newVideoSuccess.php   
2009-05-12 19:41:05 UTC (rev 18190)
@@ -14,8 +14,12 @@
           <div id="pk-media-video-buttons">
             <?php echo link_to_function("Search YouTube<span></span>", 
               "$('#pk-media-video-search-form').show(); 
$('#pk-media-video-buttons').hide(); 
$('#pk-media-video-search-heading').show();", array("class" => "pk-btn")) ?> 
-            <?php echo link_to_function("Add by URL<span></span>", 
+            <?php echo link_to_function("Add by YouTube URL<span></span>", 
               "$('#pk-media-video-add-by-url-form').show(); 
$('#pk-media-video-buttons').hide(); 
$('#pk-media-video-add-by-url-heading').show();", array("class" => "pk-btn")) 
?> 
+            <?php if (pkMediaTools::getOption('embed_codes')): ?>
+              <?php echo link_to_function("Add by Embed Code<span></span>", 
+                "$('#pk-media-video-add-by-embed-form').show(); 
$('#pk-media-video-buttons').hide(); 
$('#pk-media-video-add-by-embed-heading').show();", array("class" => "pk-btn")) 
?> 
+            <?php endif ?>
                                                <span class="or">or</span>
             <?php echo link_to("Cancel<span></span>", 
               "pkMedia/resumeWithPage",
@@ -23,7 +27,9 @@
           </div>
           <h4 id="pk-media-video-search-heading">Search YouTube</h3>          
           <h4 id="pk-media-video-add-by-url-heading">Add by URL</h3>          
-       
+          <?php if (pkMediaTools::getOption('embed_codes')): ?>
+            <h4 id="pk-media-video-add-by-embed-heading">Add by Embed 
Code</h3>          
+               <?php endif ?>
                              <?php echo jq_form_remote_tag(array(
                                  'url' => 'pkMedia/videoSearch',
                                  'update' => 'pk-media-video-search-form'),
@@ -52,6 +58,28 @@
                                                        </div>
                                                        
                              </form>
+            <?php if (pkMediaTools::getOption('embed_codes')): ?>
+                             <form id="pk-media-video-add-by-embed-form" 
method="POST" action="<?php echo url_for("pkMedia/editVideo") ?>">
+
+                                                       <div class="form-row 
example">
+                                       <p>Example: <?php echo 
htmlspecialchars('<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 
width="437" height="291" ...</object>') ?></p>
+                                       <input type="hidden" name="first_pass" 
value="1" /> 
+                                                       </div>
+                                                       
+                                                       <div class="form-row" 
style="position:relative">
+                                       <label for="pk-media-video-embed">Embed 
code</label>
+                                       <input type="text" 
id="pk-media-video-embed" name="pk_media_item[embed]" value="" />
+                               
+                                                               <div 
id="pk-media-video-add-by-embed-form-submit">
+                                               <input type="submit" value="Go" 
class="submit" />
+                                                                       <span 
class="or">or</span>
+                                               <?php echo 
link_to_function("Cancel<span></span>", 
"$('#pk-media-video-add-by-embed-form').hide(); 
$('#pk-media-video-add-by-embed-heading').hide(); 
$('#pk-media-video-buttons').show();", array("class" => "pk-cancel")) ?>
+                                                               </div>
+                               
+                                                       </div>
+                                                       
+                             </form>
+                       <?php endif ?>
         </div>
       </div>
 


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to