<?php
/**
 * Adam Franco's WPEnclosureAdder.
 * http://www.adamfranco.com/
 *
 * XPath-based RSS feed reformatter. This script will take an input feed and
 * add enclosures for links found in the description. This is especially useful
 * for adding enclosure tags for YouTube or GoogleVideo videos so that they may
 * work with the Miro (formerly Democracy) Player.
 *
 * Changelog:
 *         2007-09-06
 *            - Now makes duplicate items when items contain multiple videos.
 *         2007-09-07
 *            - Now can pass arbitrary RSS urls
 *            - Fixed YouTube urls
 * 
 * @since 7/19/07
 * @package com.adamfranco.WPEnclosureAdder
 * 
 * @copyright Copyright &copy; 2007, Adam Franco
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
 *
 * @version $Id$
 */ 

ini_set('display_errors'true);
$mediaRegExps = array();
$mediaReplacements = array();
$mediaMimeTypes = array();


/*********************************************************
 * Configuration
 *********************************************************/
// The feed source to fetch
// Allow the user to pass the URL of an RSS Feed
if (isset($_REQUEST['source']) && $_REQUEST['source'])
    
$sourceRssUrl urldecode($_REQUEST['source']);
    
// default/
else
    
$sourceRssUrl 'http://throwawayyourtelescreen.wordpress.com/feed/';

// Regular expressions to match for video urls. Uses preg_match syntax.

// Google Video
$mediaRegExps[] = '/(http:\/\/video\.google\.com\/googleplayer\.swf\?docId=[0-9-]+)/i';
$mediaReplacements[] = '\\1';
$mediaMimeTypes[] = 'application/x-shockwave-flash';

// YouTube
$mediaRegExps[] = '/http:\/\/[a-z0-9]+\.youtube\.com\/v[i]?\/([A-Z0-9-]+)/i';
$mediaReplacements[] = 'http://www.youtube.com/v/\\1.swf';
$mediaMimeTypes[] = 'application/x-shockwave-flash';


/*********************************************************
 * Script execution
 *********************************************************/
$error null;

// Get the source document
$doc = new DOMDocument;
if (! @
$doc->load($sourceRssUrl)) {
    
$error "The feed, '<a href='".$sourceRssUrl."'>".$sourceRssUrl."</a>', does not exist or contains errors.";
}

if (
$error) {
    
$self $_SERVER['PHP_SELF'];
    
header('Content-Type: text/html'); 
    print <<<END
<html>
<head></head>
<body>
    <h2>WPEnclosureAdder</h2>
    <p><strong><em>$error</em></strong></p>
    
    <p style='font-size: smaller;'>WPEnclosureAdder by Adam Franco
    <br/>Licensed under the <a href='http://www.gnu.org/copyleft/gpl.html'>GNU General Public License (GPL)</a></p>
</body>
</html>
    
END;
    exit;    
}

// Loop through all items in the feed and look for media urls
$xpath = new DOMXPath ($doc);

$channel $doc->getElementsByTagName('channel')->item(0);
$items $xpath->evaluate('/rss/channel/item');

foreach (
$items as $item) {
    
// Make the output pretty
    
$channel->insertBefore($doc->createTextNode("\n\t"), $item);
    
    
// get the urls
    
$mediaUrls extractMediaUrlsFromCDATA(
        
$item->getElementsByTagNameNS("http://purl.org/rss/1.0/modules/content/"'*')->item(0),
        
$mediaRegExps$mediaReplacements$mediaMimeTypes);
    
    
// Check for existing enclosures so that we might skip over them if needed
    
$existingEnclosures $item->getElementsByTagName('enclosure');
    
$num $existingEnclosures->length;
    foreach (
$mediaUrls as $urlInfo) {
        
// Look for the actual youtube video source on the YouTube page. 
        // If this could be gotten from the encloser instead of loading another remote 
        // page, things would run much faster.
//         if (preg_match('/youtube/', $url)) {
//             $page = file_get_contents($url);
//             preg_match('/video_id=([a-z0-9-]+)[a-z0-9=&-]*&t=([a-z0-9-]+)/i', $page, $matches);
//             $url = 'http://youtube.com/get_video?video_id='.$matches[1].'&t='.$matches[2];
//         }
        
        // For the first media url, add an enclosure tag.
        
if (!$num) {
            
$item->appendChild($doc->createTextNode("\n\t\t"));
            
$enclosure $item->appendChild($doc->createElement('enclosure'));
            
$item->appendChild($doc->createTextNode("\n\t"));
        } 
        
// For addition media urls, clone the item, add a number to the title and guid.
        
else {
            
$newItem $channel->insertBefore($item->cloneNode(true), $item->nextSibling);
            
$channel->insertBefore($doc->createTextNode("\n\t"), $newItem);
            
            
$title $newItem->getElementsByTagName('title')->item(0);
            
$title->appendChild($doc->createTextNode(' - #'.($num 1)));
            
            
$guid $newItem->getElementsByTagName('guid')->item(0);
            
$guid->appendChild($doc->createTextNode(($num+1).'/'));
            
            
$enclosure $newItem->getElementsByTagName('enclosure')->item(0);
        }
        
$enclosure->setAttribute('url'$urlInfo['url']);
        
$enclosure->setAttribute('length''0');
        
$enclosure->setAttribute('type'$urlInfo['mimeType']);
        
        
$num++;
    }
}

// Output the New document
header('Content-Type: text/xml');
print 
$doc->saveXML();


/**
 * Extract mediaUrls from the CDATA child of an element
 * 
 * @param object DomNode $contentNode
 * @param array $expressions
 * @return array
 * @access public
 * @since 7/19/07
 */
function extractMediaUrlsFromCDATA ($contentNode$expressions$replacements$mimeTypes) {
    
$mediaUrls = array();
    foreach (
$contentNode->childNodes as $contentData) {
        if (
$contentData->nodeType == XML_CDATA_SECTION_NODE) {
            foreach (
$expressions as $key => $regexp) {
                
preg_match_all($regexp$contentData->data$matches);
                foreach(
$matches[0] as $match) {
                    
$mediaUrls[] = array(
                        
'url' => preg_replace($regexp$replacements[$key], $match),
                        
'mimeType' => $mimeTypes[$key]);
                }
            }
        }
    }
    
    return 
array_unique($mediaUrls);
}

?>